Set fullscreen layout as previous editor look'n'feel.
[midnight-commander.git] / src / editor / editwidget.c
blob8f00d318b0944c4a043bac43cf526b6666512e5a
1 /*
2 Editor initialisation and callback handler.
4 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
5 2007, 2011, 2012
6 The Free Software Foundation, Inc.
8 Written by:
9 Paul Sheer, 1996, 1997
10 Andrew Borodin <aborodin@vmail.ru> 2012
12 This file is part of the Midnight Commander.
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.
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.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 /** \file
29 * \brief Source: editor initialisation and callback handler
30 * \author Paul Sheer
31 * \date 1996, 1997
34 #include <config.h>
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <errno.h>
43 #include <sys/stat.h>
44 #include <stdlib.h>
46 #include "lib/global.h"
48 #include "lib/tty/tty.h" /* LINES, COLS */
49 #include "lib/tty/key.h" /* is_idle() */
50 #include "lib/tty/color.h" /* tty_setcolor() */
51 #include "lib/skin.h"
52 #include "lib/strutil.h" /* str_term_trim() */
53 #include "lib/util.h" /* mc_build_filename() */
54 #include "lib/widget.h"
55 #include "lib/mcconfig.h"
56 #include "lib/event.h" /* mc_event_raise() */
58 #include "src/keybind-defaults.h"
59 #include "src/main.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 */
64 #include "edit-impl.h"
65 #include "editwidget.h"
67 /*** global variables ****************************************************************************/
69 char *edit_window_state_char = NULL;
70 char *edit_window_close_char = NULL;
72 /*** file scope macro definitions ****************************************************************/
74 #define WINDOW_MIN_LINES (2 + 2)
75 #define WINDOW_MIN_COLS (2 + LINE_STATE_WIDTH + 2)
77 /*** file scope type declarations ****************************************************************/
79 /*** file scope variables ************************************************************************/
80 static unsigned int edit_dlg_init_refcounter = 0;
82 /*** file scope functions ************************************************************************/
84 static cb_ret_t edit_callback (Widget * w, widget_msg_t msg, int parm);
85 static cb_ret_t edit_dialog_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm,
86 void *data);
88 /* --------------------------------------------------------------------------------------------- */
89 /**
90 * Init the 'edit' subsystem
93 static void
94 edit_dlg_init (void)
96 if (edit_dlg_init_refcounter == 0)
98 edit_window_state_char = mc_skin_get ("editor", "window-state-char", "*");
99 edit_window_close_char = mc_skin_get ("editor", "window-close-char", "X");
102 edit_dlg_init_refcounter++;
105 /* --------------------------------------------------------------------------------------------- */
107 * Deinit the 'edit' subsystem
110 static void
111 edit_dlg_deinit (void)
113 if (edit_dlg_init_refcounter != 0)
114 edit_dlg_init_refcounter--;
116 if (edit_dlg_init_refcounter == 0)
118 g_free (edit_window_state_char);
119 g_free (edit_window_close_char);
123 /* --------------------------------------------------------------------------------------------- */
125 * Show info about editor
128 static void
129 edit_about (void)
131 const char *header = N_("About");
132 const char *button_name = N_("&OK");
133 const char *const version = "MCEdit " VERSION;
134 char text[BUF_LARGE];
136 int win_len, version_len, button_len;
137 int cols, lines;
139 Dlg_head *about_dlg;
141 #ifdef ENABLE_NLS
142 header = _(header);
143 button_name = _(button_name);
144 #endif
146 button_len = str_term_width1 (button_name) + 5;
147 version_len = str_term_width1 (version);
149 g_snprintf (text, sizeof (text),
150 _("Copyright (C) 1996-2012 the Free Software Foundation\n\n"
151 " A user friendly text editor\n"
152 " written for the Midnight Commander"));
154 win_len = str_term_width1 (header);
155 win_len = max (win_len, version_len);
156 win_len = max (win_len, button_len);
158 /* count width and height of text */
159 str_msg_term_size (text, &lines, &cols);
160 lines += 9;
161 cols = max (win_len, cols) + 6;
163 /* dialog */
164 about_dlg = create_dlg (TRUE, 0, 0, lines, cols, dialog_colors, NULL, NULL,
165 "[Internal File Editor]", header, DLG_CENTER | DLG_TRYUP);
167 add_widget (about_dlg, label_new (3, (cols - version_len) / 2, version));
168 add_widget (about_dlg, label_new (5, 3, text));
169 add_widget (about_dlg, button_new (lines - 3, (cols - button_len) / 2,
170 B_ENTER, NORMAL_BUTTON, button_name, NULL));
172 run_dlg (about_dlg);
173 destroy_dlg (about_dlg);
176 /* --------------------------------------------------------------------------------------------- */
178 * Show a help window
181 static void
182 edit_help (void)
184 ev_help_t event_data = { NULL, "[Internal File Editor]" };
185 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
188 /* --------------------------------------------------------------------------------------------- */
190 * Callback for the iteration of objects in the 'editors' array.
191 * Resize the editor window.
193 * @param data probably WEdit object
194 * @param user_data unused
197 static void
198 edit_dialog_resize_cb (void *data, void *user_data)
200 Widget *w = (Widget *) data;
202 (void) user_data;
204 if (edit_widget_is_editor (w) && ((WEdit *) w)->fullscreen)
206 Dlg_head *h = w->owner;
208 w->lines = h->lines - 2;
209 w->cols = h->cols;
213 /* --------------------------------------------------------------------------------------------- */
215 * Restore saved window size.
217 * @param edit editor object
220 static void
221 edit_restore_size (WEdit * edit)
223 edit->drag_state = MCEDIT_DRAG_NORMAL;
224 widget_set_size ((Widget *) edit, edit->y_prev, edit->x_prev,
225 edit->lines_prev, edit->cols_prev);
226 dlg_redraw (((Widget *) edit)->owner);
229 /* --------------------------------------------------------------------------------------------- */
231 * Move window by one row or column in any direction.
233 * @param edit editor object
234 * @param command direction (CK_Up, CK_Down, CK_Left, CK_Right)
237 static void
238 edit_window_move (WEdit * edit, unsigned long command)
240 Widget *w = (Widget *) edit;
241 Dlg_head *h = w->owner;
243 switch (command)
245 case CK_Up:
246 if (w->y > h->y + 1) /* menubar */
247 w->y--;
248 break;
249 case CK_Down:
250 if (w->y < h->y + h->lines - 2) /* buttonbar */
251 w->y++;
252 break;
253 case CK_Left:
254 if (w->x + w->cols > h->x)
255 w->x--;
256 break;
257 case CK_Right:
258 if (w->x < h->x + h->cols)
259 w->x++;
260 break;
261 default:
262 return;
265 edit->force |= REDRAW_PAGE;
266 dlg_redraw (h);
269 /* --------------------------------------------------------------------------------------------- */
271 * Resize window by one row or column in any direction.
273 * @param edit editor object
274 * @param command direction (CK_Up, CK_Down, CK_Left, CK_Right)
277 static void
278 edit_window_resize (WEdit * edit, unsigned long command)
280 Widget *w = (Widget *) edit;
281 Dlg_head *h = w->owner;
283 switch (command)
285 case CK_Up:
286 if (w->lines > WINDOW_MIN_LINES)
287 w->lines--;
288 break;
289 case CK_Down:
290 if (w->y + w->lines < h->y + h->lines - 1) /* buttonbar */
291 w->lines++;
292 break;
293 case CK_Left:
294 if (w->cols > WINDOW_MIN_COLS)
295 w->cols--;
296 break;
297 case CK_Right:
298 if (w->x + w->cols < h->x + h->cols)
299 w->cols++;
300 break;
301 default:
302 return;
305 edit->force |= REDRAW_COMPLETELY;
306 dlg_redraw (h);
309 /* --------------------------------------------------------------------------------------------- */
311 * Get hotkey by number.
313 * @param n number
314 * @return hotkey
317 static unsigned char
318 get_hotkey (int n)
320 return (n <= 9) ? '0' + n : 'a' + n - 10;
323 /* --------------------------------------------------------------------------------------------- */
325 static void
326 edit_window_list (const Dlg_head * h)
328 const size_t offset = 2; /* skip menu and buttonbar */
329 const size_t dlg_num = g_list_length (h->widgets) - offset;
330 int lines, cols;
331 Listbox *listbox;
332 GList *w;
333 int i = 0;
334 int rv;
336 lines = min ((size_t) (LINES * 2 / 3), dlg_num);
337 cols = COLS * 2 / 3;
339 listbox = create_listbox_window (lines, cols, _("Open files"), "[Open files]");
341 for (w = h->widgets; w != NULL; w = g_list_next (w))
342 if (edit_widget_is_editor ((Widget *) w->data))
344 WEdit *e = (WEdit *) w->data;
345 char *fname;
347 if (e->filename_vpath == NULL)
348 fname = g_strdup_printf ("%c [%s]", e->modified ? '*' : ' ', _("NoName"));
349 else
351 char *fname2;
353 fname2 = vfs_path_to_str (e->filename_vpath);
354 fname = g_strdup_printf ("%c%s", e->modified ? '*' : ' ', fname2);
355 g_free (fname2);
358 listbox_add_item (listbox->list, LISTBOX_APPEND_AT_END, get_hotkey (i++),
359 str_term_trim (fname, listbox->list->widget.cols - 2), NULL);
360 g_free (fname);
363 rv = g_list_position (h->widgets, h->current) - offset;
364 listbox_select_entry (listbox->list, rv);
365 rv = run_listbox (listbox);
366 if (rv >= 0)
368 w = g_list_nth (h->widgets, rv + offset);
369 dlg_set_top_widget (w->data);
373 /* --------------------------------------------------------------------------------------------- */
375 static char *
376 edit_get_shortcut (unsigned long command)
378 const char *ext_map;
379 const char *shortcut = NULL;
381 shortcut = keybind_lookup_keymap_shortcut (editor_map, command);
382 if (shortcut != NULL)
383 return g_strdup (shortcut);
385 ext_map = keybind_lookup_keymap_shortcut (editor_map, CK_ExtendedKeyMap);
386 if (ext_map != NULL)
387 shortcut = keybind_lookup_keymap_shortcut (editor_x_map, command);
388 if (shortcut != NULL)
389 return g_strdup_printf ("%s %s", ext_map, shortcut);
391 return NULL;
394 /* --------------------------------------------------------------------------------------------- */
396 static char *
397 edit_get_title (const Dlg_head * h, size_t len)
399 const WEdit *edit = find_editor (h);
400 const char *modified = edit->modified ? "(*) " : " ";
401 const char *file_label;
402 char *filename;
404 len -= 4;
406 filename = vfs_path_to_str (edit->filename_vpath);
407 if (filename == NULL)
408 filename = g_strdup (_("[NoName]"));
409 file_label = str_term_trim (filename, len - str_term_width1 (_("Edit: ")));
410 g_free (filename);
412 return g_strconcat (_("Edit: "), modified, file_label, (char *) NULL);
415 /* --------------------------------------------------------------------------------------------- */
417 * Handle mouse events of editor window
419 * @param event mouse event
420 * @param data editor window
421 * @return MOU_NORMAL if event was handled, MOU_UNHANDLED otherwise
424 static int
425 edit_event (Gpm_Event * event, void *data)
427 WEdit *edit = (WEdit *) data;
428 Widget *w = (Widget *) data;
429 Gpm_Event local;
431 if (!mouse_global_in_widget (event, w))
432 return MOU_UNHANDLED;
434 local = mouse_get_local (event, w);
436 /* Unknown event type */
437 if ((event->type & (GPM_DOWN | GPM_DRAG | GPM_UP)) == 0)
438 return MOU_NORMAL;
440 dlg_set_top_widget (w);
442 edit_update_curs_row (edit);
443 edit_update_curs_col (edit);
445 if (edit->fullscreen || (local.buttons & GPM_B_LEFT) == 0 || (local.type & GPM_UP) != 0)
446 edit->drag_state = MCEDIT_DRAG_NORMAL;
447 else if (local.y == 1 && edit->drag_state != MCEDIT_DRAG_RESIZE)
449 /* click on the top line (move) */
450 int dx = edit->fullscreen ? 0 : 2;
452 if (local.x == edit->widget.cols - dx - 1)
454 edit_dialog_callback (w->owner, NULL, DLG_ACTION, CK_Close, NULL);
455 return MOU_NORMAL;
458 if (local.x == edit->widget.cols - dx - 4)
460 edit_toggle_fullscreen (edit);
461 return MOU_NORMAL;
464 if ((local.type & (GPM_DOWN | GPM_DRAG)) != 0)
466 /* move if not fullscreen */
467 edit->drag_state_start = local.x;
468 edit->drag_state = MCEDIT_DRAG_MOVE;
469 edit->force |= REDRAW_COMPLETELY;
470 edit_update_screen (edit);
473 else if (!edit->fullscreen && local.y == w->lines && local.x == w->cols)
475 /* click on bottom-right corner (resize) */
476 if ((local.type & (GPM_DOWN | GPM_DRAG)) != 0)
478 edit->drag_state = MCEDIT_DRAG_RESIZE;
479 edit->force |= REDRAW_COMPLETELY;
480 edit_update_screen (edit);
484 if (edit->drag_state == MCEDIT_DRAG_NORMAL)
486 gboolean done = TRUE;
488 /* Double click */
489 if ((local.type & (GPM_DOUBLE | GPM_UP)) == (GPM_UP | GPM_DOUBLE))
491 edit_mark_current_word_cmd (edit);
492 goto update;
494 #if 0
495 /* Triple click */
496 if ((local.type & (GPM_TRIPLE | GPM_UP)) == (GPM_UP | GPM_TRIPLE))
498 edit_mark_current_line_cmd (edit);
499 goto update;
501 #endif
502 /* Wheel events */
503 if ((local.buttons & GPM_B_UP) != 0 && (local.type & GPM_DOWN) != 0)
505 edit_move_up (edit, 2, 1);
506 goto update;
508 if ((local.buttons & GPM_B_DOWN) != 0 && (local.type & GPM_DOWN) != 0)
510 edit_move_down (edit, 2, 1);
511 goto update;
514 /* continue handle current event */
515 goto cont;
517 /* handle DRAG mouse event, don't use standard way to continue
518 * event handling outside of widget */
521 int c;
523 c = tty_get_event (event, FALSE, TRUE);
524 if (c == EV_NONE || c != EV_MOUSE)
525 break;
527 local = mouse_get_local (event, w);
529 cont:
530 /* A lone up mustn't do anything */
531 if (edit->mark2 != -1 && (local.type & (GPM_UP | GPM_DRAG)) != 0)
532 return MOU_NORMAL;
534 if ((local.type & (GPM_DOWN | GPM_UP)) != 0)
535 edit_push_key_press (edit);
537 if (!edit->fullscreen)
538 local.x--;
539 if (!option_cursor_beyond_eol)
540 edit->prev_col = local.x - edit->start_col - option_line_state_width - 1;
541 else
543 long line_len = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
544 edit_eol (edit, edit->curs1));
546 if (local.x > line_len)
548 edit->over_col =
549 local.x - line_len - edit->start_col - option_line_state_width - 1;
550 edit->prev_col = line_len;
552 else
554 edit->over_col = 0;
555 edit->prev_col = local.x - option_line_state_width - edit->start_col - 1;
559 if (!edit->fullscreen)
560 local.y--;
561 if (local.y > (edit->curs_row + 1))
562 edit_move_down (edit, local.y - (edit->curs_row + 1), 0);
563 else if (local.y < (edit->curs_row + 1))
564 edit_move_up (edit, (edit->curs_row + 1) - local.y, 0);
565 else
566 edit_move_to_prev_col (edit, edit_bol (edit, edit->curs1));
568 if ((local.type & GPM_DOWN) != 0)
570 edit_mark_cmd (edit, 1); /* reset */
571 edit->highlight = 0;
574 done = (local.type & GPM_DRAG) == 0;
575 if (done)
576 edit_mark_cmd (edit, 0);
578 update:
579 edit_find_bracket (edit);
580 edit->force |= REDRAW_COMPLETELY;
581 edit_update_curs_row (edit);
582 edit_update_curs_col (edit);
583 edit_update_screen (edit);
585 while (!edit->fullscreen && !done);
587 else
588 while (edit->drag_state != MCEDIT_DRAG_NORMAL)
590 int c;
591 int y;
593 c = tty_get_event (event, FALSE, TRUE);
594 y = event->y - 1;
596 if (c == EV_NONE || c != EV_MOUSE)
598 /* redraw frame */
599 edit->drag_state = MCEDIT_DRAG_NORMAL;
600 edit->force |= REDRAW_COMPLETELY;
601 edit_update_screen (edit);
603 else if (y == w->y && (event->type & (GPM_DOUBLE | GPM_UP)) == (GPM_DOUBLE | GPM_UP))
605 /* double click on top line (toggle fullscreen) */
606 edit_toggle_fullscreen (edit);
607 edit->drag_state = MCEDIT_DRAG_NORMAL;
608 edit->force |= REDRAW_COMPLETELY;
609 edit_update_screen (edit);
611 else if ((event->type & (GPM_DRAG | GPM_DOWN)) == 0)
613 /* redraw frame */
614 edit->drag_state = MCEDIT_DRAG_NORMAL;
615 edit->force |= REDRAW_COMPLETELY;
616 edit_update_screen (edit);
618 else if (!edit->fullscreen)
620 Dlg_head *h = w->owner;
622 if (edit->drag_state == MCEDIT_DRAG_MOVE)
624 int x = event->x - 1;
626 y = max (y, h->y + 1); /* status line */
627 y = min (y, h->y + h->lines - 2); /* buttonbar */
628 x = max (x, h->x);
629 x = min (x, h->x + h->cols - 1);
630 /* don't use widget_set_size() here to avoid double draw */
631 w->y = y;
632 w->x = x - edit->drag_state_start;
633 edit->force |= REDRAW_COMPLETELY;
635 else if (edit->drag_state == MCEDIT_DRAG_RESIZE)
637 event->y = min (event->y, h->y + h->lines - 1); /* buttonbar */
638 event->x = min (event->x, h->x + h->cols);
639 local = mouse_get_local (event, w);
641 /* don't use widget_set_size() here to avoid double draw */
642 w->lines = max (WINDOW_MIN_LINES, local.y);
643 w->cols = max (WINDOW_MIN_COLS, local.x);
644 edit->force |= REDRAW_COMPLETELY;
647 dlg_redraw (h);
651 return MOU_NORMAL;
654 /* --------------------------------------------------------------------------------------------- */
656 * Handle mouse events of editor screen.
658 * @param event mouse event
659 * @param data editor screen
660 * @return MOU_NORMAL if event was handled, MOU_UNHANDLED otherwise
663 static int
664 edit_dialog_event (Gpm_Event *event, void *data)
666 Dlg_head *h = (Dlg_head *) data;
667 Widget *w;
668 int ret = MOU_UNHANDLED;
670 w = (Widget *) find_menubar (h);
672 if (event->y == h->y + 1 && (event->type & GPM_DOWN) != 0 && !((WMenuBar *) w)->is_active)
674 /* menubar */
676 GList *l;
677 GList *top = NULL;
678 int x;
680 /* Try find top fullscreen window */
681 for (l = h->widgets; l != NULL; l = g_list_next (l))
682 if (edit_widget_is_editor ((Widget *) l->data) && ((WEdit *) l->data)->fullscreen)
683 top = l;
685 /* Handle fullscreen/close buttons in the top line */
686 x = h->x + h->cols + 1 - 6;
688 if (top != NULL && event->x >= x)
690 WEdit *e;
692 e = (WEdit *) top->data;
693 x = event->x - x;
695 if (top != h->current)
697 /* Window is not active. Activate it */
698 dlg_set_top_widget (e);
701 /* Handle buttons */
702 if (x <= 2)
703 edit_toggle_fullscreen (e);
704 else
705 edit_dialog_callback (h, NULL, DLG_ACTION, CK_Close, NULL);
707 ret = MOU_NORMAL;
710 if (ret == MOU_UNHANDLED)
711 dlg_select_widget (w);
713 else if (event->y == h->y + h->lines)
715 /* buttonbar */
717 /* In general, this can be handled in default way (dlg_mouse_event)
718 * but let make it here to avoid walking in widget list */
719 w = (Widget *) find_buttonbar (h);
720 ret = w->mouse (event, w);
723 return ret;
726 /* --------------------------------------------------------------------------------------------- */
728 static cb_ret_t
729 edit_dialog_command_execute (Dlg_head * h, unsigned long command)
731 gboolean ret = MSG_HANDLED;
733 switch (command)
735 case CK_EditNew:
736 edit_add_window (h, h->y + 1, h->x, h->lines - 2, h->cols, NULL, 0);
737 break;
738 case CK_EditFile:
739 edit_load_cmd (h);
740 break;
741 case CK_EditSyntaxFile:
742 edit_load_syntax_file (h);
743 break;
744 case CK_EditUserMenu:
745 edit_load_menu_file (h);
746 break;
747 case CK_Close:
748 /* if there are no opened files anymore, close MC editor */
749 if (edit_widget_is_editor ((Widget *) h->current->data) &&
750 edit_close_cmd ((WEdit *) h->current->data) && find_editor (h) == NULL)
751 dlg_stop (h);
752 break;
753 case CK_Help:
754 edit_help ();
755 /* edit->force |= REDRAW_COMPLETELY; */
756 break;
757 case CK_Menu:
758 edit_menu_cmd (h);
759 break;
760 case CK_Quit:
761 case CK_Cancel:
763 Widget *w = (Widget *) h->current->data;
765 if (!edit_widget_is_editor (w) || ((WEdit *) w)->drag_state == MCEDIT_DRAG_NORMAL)
766 dlg_stop (h);
767 else
768 edit_restore_size ((WEdit *) w);
770 break;
771 case CK_About:
772 edit_about ();
773 break;
774 case CK_SyntaxOnOff:
775 edit_syntax_onoff_cmd (h);
776 break;
777 case CK_ShowTabTws:
778 edit_show_tabs_tws_cmd (h);
779 break;
780 case CK_ShowMargin:
781 edit_show_margin_cmd (h);
782 break;
783 case CK_ShowNumbers:
784 edit_show_numbers_cmd (h);
785 break;
786 case CK_Refresh:
787 edit_refresh_cmd ();
788 break;
789 case CK_Shell:
790 view_other_cmd ();
791 break;
792 case CK_LearnKeys:
793 learn_keys ();
794 break;
795 case CK_WindowMove:
796 case CK_WindowResize:
797 if (edit_widget_is_editor ((Widget *) h->current->data))
798 edit_handle_move_resize ((WEdit *) h->current->data, command);
799 break;
800 case CK_WindowList:
801 edit_window_list (h);
802 break;
803 case CK_WindowNext:
804 dlg_one_down (h);
805 dlg_set_top_widget (h->current->data);
806 break;
807 case CK_WindowPrev:
808 dlg_one_up (h);
809 dlg_set_top_widget (h->current->data);
810 break;
811 case CK_Options:
812 edit_options_dialog (h);
813 break;
814 case CK_OptionsSaveMode:
815 edit_save_mode_cmd ();
816 break;
817 case CK_SaveSetup:
818 save_setup_cmd ();
819 break;
820 default:
821 ret = MSG_NOT_HANDLED;
822 break;
825 return ret;
828 /* --------------------------------------------------------------------------------------------- */
830 static inline void
831 edit_quit (Dlg_head * h)
833 GList *l;
834 WEdit *e = NULL;
836 h->state = DLG_ACTIVE; /* don't stop the dialog before final decision */
838 for (l = h->widgets; l != NULL; l = g_list_next (l))
839 if (edit_widget_is_editor ((Widget *) l->data))
841 e = (WEdit *) l->data;
843 if (e->drag_state != MCEDIT_DRAG_NORMAL)
845 edit_restore_size (e);
846 return;
849 if (e->modified)
851 dlg_select_widget (e);
853 if (!edit_ok_to_exit (e))
854 return;
858 /* no editors in dialog at all or no any file required to be saved */
859 if (e == NULL || l == NULL)
860 h->state = DLG_CLOSED;
863 /* --------------------------------------------------------------------------------------------- */
865 static inline void
866 edit_set_buttonbar (WEdit * edit, WButtonBar * bb)
868 buttonbar_set_label (bb, 1, Q_ ("ButtonBar|Help"), editor_map, NULL);
869 buttonbar_set_label (bb, 2, Q_ ("ButtonBar|Save"), editor_map, (Widget *) edit);
870 buttonbar_set_label (bb, 3, Q_ ("ButtonBar|Mark"), editor_map, (Widget *) edit);
871 buttonbar_set_label (bb, 4, Q_ ("ButtonBar|Replac"), editor_map, (Widget *) edit);
872 buttonbar_set_label (bb, 5, Q_ ("ButtonBar|Copy"), editor_map, (Widget *) edit);
873 buttonbar_set_label (bb, 6, Q_ ("ButtonBar|Move"), editor_map, (Widget *) edit);
874 buttonbar_set_label (bb, 7, Q_ ("ButtonBar|Search"), editor_map, (Widget *) edit);
875 buttonbar_set_label (bb, 8, Q_ ("ButtonBar|Delete"), editor_map, (Widget *) edit);
876 buttonbar_set_label (bb, 9, Q_ ("ButtonBar|PullDn"), editor_map, NULL);
877 buttonbar_set_label (bb, 10, Q_ ("ButtonBar|Quit"), editor_map, NULL);
880 /* --------------------------------------------------------------------------------------------- */
881 /** Callback for the edit dialog */
883 static cb_ret_t
884 edit_dialog_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
886 WMenuBar *menubar;
887 WButtonBar *buttonbar;
889 switch (msg)
891 case DLG_INIT:
892 edit_dlg_init ();
893 return MSG_HANDLED;
895 case DLG_DRAW:
896 /* don't use common_dialog_repaint() -- we don't need a frame */
897 tty_setcolor (EDITOR_BACKGROUND);
898 dlg_erase (h);
899 return MSG_HANDLED;
901 case DLG_RESIZE:
902 menubar = find_menubar (h);
903 buttonbar = find_buttonbar (h);
904 /* dlg_set_size() is surplus for this case */
905 h->lines = LINES;
906 h->cols = COLS;
907 widget_set_size (&buttonbar->widget, h->lines - 1, h->x, 1, h->cols);
908 widget_set_size (&menubar->widget, h->y, h->x, 1, h->cols);
909 menubar_arrange (menubar);
910 g_list_foreach (h->widgets, (GFunc) edit_dialog_resize_cb, NULL);
911 return MSG_HANDLED;
913 case DLG_ACTION:
914 /* shortcut */
915 if (sender == NULL)
916 return edit_dialog_command_execute (h, parm);
917 /* message from menu */
918 menubar = find_menubar (h);
919 if (sender == (Widget *) menubar)
921 if (edit_dialog_command_execute (h, parm) == MSG_HANDLED)
922 return MSG_HANDLED;
923 /* try send command to the current window */
924 return send_message ((Widget *) h->current->data, WIDGET_COMMAND, parm);
926 /* message from buttonbar */
927 buttonbar = find_buttonbar (h);
928 if (sender == (Widget *) buttonbar)
930 if (data != NULL)
931 return send_message ((Widget *) data, WIDGET_COMMAND, parm);
932 return edit_dialog_command_execute (h, parm);
934 return MSG_NOT_HANDLED;
936 case DLG_KEY:
938 Widget *w = h->current->data;
939 cb_ret_t ret = MSG_NOT_HANDLED;
941 if (edit_widget_is_editor (w))
943 WEdit *e = (WEdit *) w;
944 unsigned long command;
946 if (!e->extmod)
947 command = keybind_lookup_keymap_command (editor_map, parm);
948 else
950 e->extmod = FALSE;
951 command = keybind_lookup_keymap_command (editor_x_map, parm);
954 if (command != CK_IgnoreKey)
955 ret = edit_dialog_command_execute (h, command);
958 return ret;
961 /* hardcoded menu hotkeys (see edit_drop_hotkey_menu) */
962 case DLG_UNHANDLED_KEY:
963 return edit_drop_hotkey_menu (h, parm) ? MSG_HANDLED : MSG_NOT_HANDLED;
965 case DLG_VALIDATE:
966 edit_quit (h);
967 return MSG_HANDLED;
969 case DLG_END:
970 edit_dlg_deinit ();
971 return MSG_HANDLED;
973 default:
974 return default_dlg_callback (h, sender, msg, parm, data);
978 /* --------------------------------------------------------------------------------------------- */
980 static cb_ret_t
981 edit_callback (Widget * w, widget_msg_t msg, int parm)
983 WEdit *e = (WEdit *) w;
985 switch (msg)
987 case WIDGET_FOCUS:
988 edit_set_buttonbar (e, find_buttonbar (e->widget.owner));
989 /* fall through */
991 case WIDGET_DRAW:
992 e->force |= REDRAW_COMPLETELY;
993 edit_update_screen (e);
994 return MSG_HANDLED;
996 case WIDGET_UNFOCUS:
997 /* redraw frame and status */
998 edit_status (e, FALSE);
999 return MSG_HANDLED;
1001 case WIDGET_KEY:
1003 int cmd, ch;
1004 cb_ret_t ret = MSG_NOT_HANDLED;
1006 /* The user may override the access-keys for the menu bar. */
1007 if (macro_index == -1 && edit_execute_macro (e, parm))
1009 edit_update_screen (e);
1010 ret = MSG_HANDLED;
1012 else if (edit_translate_key (e, parm, &cmd, &ch))
1014 edit_execute_key_command (e, cmd, ch);
1015 edit_update_screen (e);
1016 ret = MSG_HANDLED;
1019 return ret;
1022 case WIDGET_COMMAND:
1023 /* command from menubar or buttonbar */
1024 edit_execute_key_command (e, parm, -1);
1025 edit_update_screen (e);
1026 return MSG_HANDLED;
1028 case WIDGET_CURSOR:
1030 int y, x;
1032 y = (e->fullscreen ? 0 : 1) + EDIT_TEXT_VERTICAL_OFFSET + e->curs_row;
1033 x = (e->fullscreen ? 0 : 1) + EDIT_TEXT_HORIZONTAL_OFFSET + option_line_state_width +
1034 e->curs_col + e->start_col + e->over_col;
1036 widget_move (w, y, x);
1037 return MSG_HANDLED;
1040 case WIDGET_DESTROY:
1041 edit_clean (e);
1042 return MSG_HANDLED;
1044 default:
1045 return default_proc (msg, parm);
1049 /* --------------------------------------------------------------------------------------------- */
1050 /*** public functions ****************************************************************************/
1051 /* --------------------------------------------------------------------------------------------- */
1053 * Edit one file.
1055 * @param file_vpath file object
1056 * @param line line number
1057 * @return TRUE if no errors was occured, FALSE otherwise
1060 gboolean
1061 edit_file (const vfs_path_t * file_vpath, int line)
1063 mcedit_arg_t arg = { (vfs_path_t *) file_vpath, line };
1064 GList *files;
1065 gboolean ok;
1067 files = g_list_prepend (NULL, &arg);
1068 ok = edit_files (files);
1069 g_list_free (files);
1071 return ok;
1073 /* --------------------------------------------------------------------------------------------- */
1075 gboolean
1076 edit_files (const GList *files)
1078 static gboolean made_directory = FALSE;
1079 Dlg_head *edit_dlg;
1080 WMenuBar *menubar;
1081 const GList *file;
1082 gboolean ok = FALSE;
1084 if (!made_directory)
1086 char *dir;
1088 dir = mc_build_filename (mc_config_get_cache_path (), EDIT_DIR, NULL);
1089 made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
1090 g_free (dir);
1092 dir = mc_build_filename (mc_config_get_path (), EDIT_DIR, NULL);
1093 made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
1094 g_free (dir);
1096 dir = mc_build_filename (mc_config_get_data_path (), EDIT_DIR, NULL);
1097 made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
1098 g_free (dir);
1101 /* Create a new dialog and add it widgets to it */
1102 edit_dlg =
1103 create_dlg (FALSE, 0, 0, LINES, COLS, NULL, edit_dialog_callback, edit_dialog_event,
1104 "[Internal File Editor]", NULL, DLG_WANT_TAB);
1106 edit_dlg->get_shortcut = edit_get_shortcut;
1107 edit_dlg->get_title = edit_get_title;
1109 menubar = menubar_new (0, 0, COLS, NULL);
1110 add_widget (edit_dlg, menubar);
1111 edit_init_menu (menubar);
1113 add_widget (edit_dlg, buttonbar_new (TRUE));
1115 for (file = files; file != NULL; file = g_list_next (file))
1117 mcedit_arg_t *f = (mcedit_arg_t *) file->data;
1118 gboolean f_ok;
1120 f_ok = edit_add_window (edit_dlg, edit_dlg->y + 1, edit_dlg->x,
1121 edit_dlg->lines - 2, edit_dlg->cols,
1122 f->file_vpath, f->line_number);
1123 /* at least one file has been opened succefully */
1124 ok = ok || f_ok;
1127 if (ok)
1128 run_dlg (edit_dlg);
1130 if (!ok || edit_dlg->state == DLG_CLOSED)
1131 destroy_dlg (edit_dlg);
1133 return ok;
1136 /* --------------------------------------------------------------------------------------------- */
1138 char *
1139 edit_get_file_name (const WEdit * edit)
1141 return vfs_path_to_str (edit->filename_vpath);
1144 /* --------------------------------------------------------------------------------------------- */
1146 WEdit *
1147 find_editor (const Dlg_head * h)
1149 if (edit_widget_is_editor ((Widget *) h->current->data))
1150 return (WEdit *) h->current->data;
1151 return (WEdit *) find_widget_type (h, edit_callback);
1154 /* --------------------------------------------------------------------------------------------- */
1156 * Check if widget is an WEdit class.
1158 * @param w probably editor object
1159 * @return TRUE if widget is an WEdit class, FALSE otherwise
1162 gboolean
1163 edit_widget_is_editor (const Widget * w)
1165 return (w != NULL && w->callback == edit_callback);
1168 /* --------------------------------------------------------------------------------------------- */
1170 void
1171 edit_update_screen (WEdit * e)
1173 edit_scroll_screen_over_cursor (e);
1174 edit_update_curs_col (e);
1176 edit_status (e, (e->force & REDRAW_COMPLETELY) != 0 &&
1177 (void *) e == ((Widget *) e)->owner->current->data);
1179 /* pop all events for this window for internal handling */
1180 if (!is_idle ())
1181 e->force |= REDRAW_PAGE;
1182 else
1184 if ((e->force & REDRAW_COMPLETELY) != 0)
1185 e->force |= REDRAW_PAGE;
1186 edit_render_keypress (e);
1189 buttonbar_redraw (find_buttonbar (((Widget *) e)->owner));
1192 /* --------------------------------------------------------------------------------------------- */
1194 * Save current window size.
1196 * @param edit editor object
1199 void
1200 edit_save_size (WEdit * edit)
1202 edit->y_prev = edit->widget.y;
1203 edit->x_prev = edit->widget.x;
1204 edit->lines_prev = edit->widget.lines;
1205 edit->cols_prev = edit->widget.cols;
1208 /* --------------------------------------------------------------------------------------------- */
1210 * Create new editor window and insert it into editor screen.
1212 * @param h editor dialog (screen)
1213 * @param y y coordinate
1214 * @param x x coordinate
1215 * @param lines window height
1216 * @param cols window width
1217 * @param f file object
1218 * @param fline line number in file
1219 * @return TRUE if new window was successfully created and inserted into editor screen,
1220 * FALSE otherwise
1223 gboolean
1224 edit_add_window (Dlg_head * h, int y, int x, int lines, int cols, const vfs_path_t *f, int fline)
1226 WEdit *edit;
1227 Widget *w;
1229 edit = edit_init (NULL, y, x, lines, cols, f, fline);
1230 if (edit == NULL)
1231 return FALSE;
1233 w = (Widget *) edit;
1234 w->callback = edit_callback;
1235 w->mouse = edit_event;
1236 widget_want_cursor (*w, TRUE);
1238 add_widget (h, w);
1239 dlg_redraw (h);
1241 return TRUE;
1244 /* --------------------------------------------------------------------------------------------- */
1246 * Handle move/resize events.
1248 * @param edit editor object
1249 * @param command action id
1250 * @return TRUE if mouse actions was handled, FALSE otherwise
1253 gboolean
1254 edit_handle_move_resize (WEdit * edit, unsigned long command)
1256 gboolean ret = FALSE;
1258 if (edit->fullscreen)
1260 edit->drag_state = MCEDIT_DRAG_NORMAL;
1261 return ret;
1264 switch (edit->drag_state)
1266 case MCEDIT_DRAG_NORMAL:
1267 /* possible start move/resize */
1268 switch (command)
1270 case CK_WindowMove:
1271 edit->drag_state = MCEDIT_DRAG_MOVE;
1272 edit_save_size (edit);
1273 ret = TRUE;
1274 break;
1275 case CK_WindowResize:
1276 edit->drag_state = MCEDIT_DRAG_RESIZE;
1277 edit_save_size (edit);
1278 ret = TRUE;
1279 break;
1280 default:
1281 break;
1283 break;
1285 case MCEDIT_DRAG_MOVE:
1286 switch (command)
1288 case CK_WindowResize:
1289 edit->drag_state = MCEDIT_DRAG_RESIZE;
1290 ret = TRUE;
1291 break;
1292 case CK_Up:
1293 case CK_Down:
1294 case CK_Left:
1295 case CK_Right:
1296 edit_window_move (edit, command);
1297 ret = TRUE;
1298 break;
1299 case CK_Enter:
1300 case CK_WindowMove:
1301 edit->drag_state = MCEDIT_DRAG_NORMAL;
1302 /* redraw frame and status */
1303 edit_status (edit, TRUE);
1304 default:
1305 ret = TRUE;
1306 break;
1308 break;
1310 case MCEDIT_DRAG_RESIZE:
1311 switch (command)
1313 case CK_WindowMove:
1314 edit->drag_state = MCEDIT_DRAG_MOVE;
1315 ret = TRUE;
1316 break;
1317 case CK_Up:
1318 case CK_Down:
1319 case CK_Left:
1320 case CK_Right:
1321 edit_window_resize (edit, command);
1322 ret = TRUE;
1323 break;
1324 case CK_Enter:
1325 case CK_WindowResize:
1326 edit->drag_state = MCEDIT_DRAG_NORMAL;
1327 /* redraw frame and status */
1328 edit_status (edit, TRUE);
1329 default:
1330 ret = TRUE;
1331 break;
1333 break;
1336 return ret;
1339 /* --------------------------------------------------------------------------------------------- */
1341 * Toggle window fuulscreen mode.
1343 * @param edit editor object
1346 void
1347 edit_toggle_fullscreen (WEdit * edit)
1349 Dlg_head *h = ((Widget *) edit)->owner;
1351 edit->fullscreen = !edit->fullscreen;
1352 edit->force = REDRAW_COMPLETELY;
1354 if (!edit->fullscreen)
1355 edit_restore_size (edit);
1356 else
1358 edit_save_size (edit);
1359 widget_set_size ((Widget *) edit, h->y + 1, h->x, h->lines - 2, h->cols);
1360 edit->force |= REDRAW_PAGE;
1361 edit_update_screen (edit);
1365 /* --------------------------------------------------------------------------------------------- */