Code refactoring: removed concat_dir_and_file() function.
[midnight-commander.git] / src / editor / editwidget.c
blobdd60c30a9f6ecbe0834a948fe5d6e5017c4fb3cf
1 /*
2 Editor initialisation and callback handler.
4 Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
5 2007,2011
6 The Free Software Foundation, Inc.
8 Written by:
9 Paul Sheer, 1996, 1997
11 This file is part of the Midnight Commander.
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.
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.
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/>.
27 /** \file
28 * \brief Source: editor initialisation and callback handler
29 * \author Paul Sheer
30 * \date 1996, 1997
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include <sys/stat.h>
43 #include <stdlib.h>
45 #include "lib/global.h"
47 #include "lib/tty/tty.h" /* LINES, COLS */
48 #include "lib/tty/key.h" /* is_idle() */
49 #include "lib/tty/color.h" /* tty_setcolor() */
50 #include "lib/skin.h" /* EDITOR_NORMAL_COLOR */
51 #include "lib/strutil.h" /* str_term_trim() */
52 #include "lib/util.h" /* mc_build_filename() */
53 #include "lib/widget.h"
54 #include "lib/mcconfig.h"
56 #include "src/keybind-defaults.h"
57 #include "src/main.h" /* home_dir */
59 #include "edit-impl.h"
60 #include "edit-widget.h"
62 /*** global variables ****************************************************************************/
64 /*** file scope macro definitions ****************************************************************/
66 /*** file scope type declarations ****************************************************************/
68 /*** file scope variables ************************************************************************/
70 /*** file scope functions ************************************************************************/
72 static cb_ret_t edit_callback (Widget * w, widget_msg_t msg, int parm);
75 /* --------------------------------------------------------------------------------------------- */
77 static char *
78 edit_get_shortcut (unsigned long command)
80 const char *ext_map;
81 const char *shortcut = NULL;
83 shortcut = keybind_lookup_keymap_shortcut (editor_map, command);
84 if (shortcut != NULL)
85 return g_strdup (shortcut);
87 ext_map = keybind_lookup_keymap_shortcut (editor_map, CK_ExtendedKeyMap);
88 if (ext_map != NULL)
89 shortcut = keybind_lookup_keymap_shortcut (editor_x_map, command);
90 if (shortcut != NULL)
91 return g_strdup_printf ("%s %s", ext_map, shortcut);
93 return NULL;
96 /* --------------------------------------------------------------------------------------------- */
98 static char *
99 edit_get_title (const Dlg_head * h, size_t len)
101 const WEdit *edit = (const WEdit *) find_widget_type (h, edit_callback);
102 const char *modified = edit->modified ? "(*) " : " ";
103 const char *file_label;
104 char *filename;
106 len -= 4;
108 filename = vfs_path_to_str (edit->filename_vpath);
109 file_label = str_term_trim (filename, len - str_term_width1 (_("Edit: ")));
110 g_free (filename);
112 return g_strconcat (_("Edit: "), modified, file_label, (char *) NULL);
115 /* --------------------------------------------------------------------------------------------- */
117 static int
118 edit_event (Gpm_Event * event, void *data)
120 WEdit *edit = (WEdit *) data;
122 /* Unknown event type */
123 if (!(event->type & (GPM_DOWN | GPM_DRAG | GPM_UP)))
124 return MOU_NORMAL;
126 edit_update_curs_row (edit);
127 edit_update_curs_col (edit);
129 /* Outside editor window */
130 if (event->y < 1 || event->x < 1
131 || event->x > edit->widget.cols || event->y > edit->widget.lines)
132 return MOU_NORMAL;
134 /* Double click */
135 if ((event->type & (GPM_DOUBLE | GPM_UP)) == (GPM_UP | GPM_DOUBLE))
137 edit_mark_current_word_cmd (edit);
138 goto update;
140 #if 0
141 /* Triple click */
142 if ((event->type & (GPM_TRIPLE | GPM_UP)) == (GPM_UP | GPM_TRIPLE))
144 edit_mark_current_line_cmd (edit);
145 goto update;
147 #endif
148 /* Wheel events */
149 if ((event->buttons & GPM_B_UP) && (event->type & GPM_DOWN))
151 edit_move_up (edit, 2, 1);
152 goto update;
154 if ((event->buttons & GPM_B_DOWN) && (event->type & GPM_DOWN))
156 edit_move_down (edit, 2, 1);
157 goto update;
160 /* A lone up mustn't do anything */
161 if (edit->mark2 != -1 && event->type & (GPM_UP | GPM_DRAG))
162 return MOU_NORMAL;
164 if (event->type & (GPM_DOWN | GPM_UP))
165 edit_push_key_press (edit);
167 if (!option_cursor_beyond_eol)
168 edit->prev_col = event->x - edit->start_col - option_line_state_width - 1;
169 else
171 long line_len = edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0,
172 edit_eol (edit, edit->curs1));
174 if (event->x > line_len)
176 edit->over_col = event->x - line_len - edit->start_col - option_line_state_width - 1;
177 edit->prev_col = line_len;
179 else
181 edit->over_col = 0;
182 edit->prev_col = event->x - option_line_state_width - edit->start_col - 1;
186 --event->y;
187 if (event->y > edit->curs_row)
188 edit_move_down (edit, event->y - edit->curs_row, 0);
189 else if (event->y < edit->curs_row)
190 edit_move_up (edit, edit->curs_row - event->y, 0);
191 else
192 edit_move_to_prev_col (edit, edit_bol (edit, edit->curs1));
194 if (event->type & GPM_DOWN)
196 edit_mark_cmd (edit, 1); /* reset */
197 edit->highlight = 0;
200 if (!(event->type & GPM_DRAG))
201 edit_mark_cmd (edit, 0);
203 update:
204 edit_find_bracket (edit);
205 edit->force |= REDRAW_COMPLETELY;
206 edit_update_curs_row (edit);
207 edit_update_curs_col (edit);
208 edit_update_screen (edit);
210 return MOU_NORMAL;
213 /* --------------------------------------------------------------------------------------------- */
215 static cb_ret_t
216 edit_command_execute (WEdit * edit, unsigned long command)
218 if (command == CK_Menu)
219 edit_menu_cmd (edit);
220 else
222 edit_execute_key_command (edit, command, -1);
223 edit_update_screen (edit);
225 return MSG_HANDLED;
228 /* --------------------------------------------------------------------------------------------- */
230 static inline void
231 edit_set_buttonbar (WEdit * edit, WButtonBar * bb)
233 buttonbar_set_label (bb, 1, Q_ ("ButtonBar|Help"), editor_map, (Widget *) edit);
234 buttonbar_set_label (bb, 2, Q_ ("ButtonBar|Save"), editor_map, (Widget *) edit);
235 buttonbar_set_label (bb, 3, Q_ ("ButtonBar|Mark"), editor_map, (Widget *) edit);
236 buttonbar_set_label (bb, 4, Q_ ("ButtonBar|Replac"), editor_map, (Widget *) edit);
237 buttonbar_set_label (bb, 5, Q_ ("ButtonBar|Copy"), editor_map, (Widget *) edit);
238 buttonbar_set_label (bb, 6, Q_ ("ButtonBar|Move"), editor_map, (Widget *) edit);
239 buttonbar_set_label (bb, 7, Q_ ("ButtonBar|Search"), editor_map, (Widget *) edit);
240 buttonbar_set_label (bb, 8, Q_ ("ButtonBar|Delete"), editor_map, (Widget *) edit);
241 buttonbar_set_label (bb, 9, Q_ ("ButtonBar|PullDn"), editor_map, (Widget *) edit);
242 buttonbar_set_label (bb, 10, Q_ ("ButtonBar|Quit"), editor_map, (Widget *) edit);
245 /* --------------------------------------------------------------------------------------------- */
246 /** Callback for the edit dialog */
248 static cb_ret_t
249 edit_dialog_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
251 WEdit *edit;
252 WMenuBar *menubar;
253 WButtonBar *buttonbar;
255 edit = (WEdit *) find_widget_type (h, edit_callback);
256 menubar = find_menubar (h);
257 buttonbar = find_buttonbar (h);
259 switch (msg)
261 case DLG_INIT:
262 edit_set_buttonbar (edit, buttonbar);
263 return MSG_HANDLED;
265 case DLG_DRAW:
266 /* don't use common_dialog_repaint() -- we don't need a frame */
267 tty_setcolor (EDITOR_NORMAL_COLOR);
268 dlg_erase (h);
269 return MSG_HANDLED;
271 case DLG_RESIZE:
272 /* dlg_set_size() is surplus for this case */
273 h->lines = LINES;
274 h->cols = COLS;
275 widget_set_size (&buttonbar->widget, h->lines - 1, h->x, 1, h->cols);
276 widget_set_size (&menubar->widget, h->y, h->x, 1, h->cols);
277 menubar_arrange (menubar);
278 widget_set_size (&edit->widget, h->y + 1, h->x, h->lines - 2, h->cols);
279 return MSG_HANDLED;
281 case DLG_ACTION:
282 if (sender == (Widget *) menubar)
283 return send_message ((Widget *) edit, WIDGET_COMMAND, parm);
284 if (sender == (Widget *) buttonbar)
285 return send_message ((Widget *) edit, WIDGET_COMMAND, parm);
286 return MSG_HANDLED;
288 case DLG_VALIDATE:
289 h->state = DLG_ACTIVE; /* don't stop the dialog before final decision */
290 if (edit_ok_to_exit (edit))
291 h->state = DLG_CLOSED;
292 return MSG_HANDLED;
294 default:
295 return default_dlg_callback (h, sender, msg, parm, data);
299 /* --------------------------------------------------------------------------------------------- */
301 static cb_ret_t
302 edit_callback (Widget * w, widget_msg_t msg, int parm)
304 WEdit *e = (WEdit *) w;
306 switch (msg)
308 case WIDGET_DRAW:
309 e->force |= REDRAW_COMPLETELY;
310 /* fallthrough */
312 case WIDGET_FOCUS:
313 edit_update_screen (e);
314 return MSG_HANDLED;
316 case WIDGET_KEY:
318 int cmd, ch;
319 cb_ret_t ret = MSG_NOT_HANDLED;
321 /* The user may override the access-keys for the menu bar. */
322 if (macro_index == -1 && edit_execute_macro (e, parm))
324 edit_update_screen (e);
325 ret = MSG_HANDLED;
327 else if (edit_translate_key (e, parm, &cmd, &ch))
329 edit_execute_key_command (e, cmd, ch);
330 edit_update_screen (e);
331 ret = MSG_HANDLED;
333 else if (edit_drop_hotkey_menu (e, parm))
334 ret = MSG_HANDLED;
336 return ret;
339 case WIDGET_COMMAND:
340 /* command from menubar or buttonbar */
341 return edit_command_execute (e, parm);
343 case WIDGET_CURSOR:
344 widget_move (w, e->curs_row + EDIT_TEXT_VERTICAL_OFFSET,
345 e->curs_col + e->start_col + e->over_col +
346 EDIT_TEXT_HORIZONTAL_OFFSET + option_line_state_width);
347 return MSG_HANDLED;
349 case WIDGET_DESTROY:
350 edit_clean (e);
351 return MSG_HANDLED;
353 default:
354 return default_proc (msg, parm);
358 /* --------------------------------------------------------------------------------------------- */
359 /*** public functions ****************************************************************************/
360 /* --------------------------------------------------------------------------------------------- */
363 edit_file (const vfs_path_t * _file_vpath, int line)
365 static gboolean made_directory = FALSE;
366 Dlg_head *edit_dlg;
367 WEdit *wedit;
368 WMenuBar *menubar;
370 if (!made_directory)
372 char *dir;
374 dir = mc_build_filename (mc_config_get_cache_path (), EDIT_DIR, NULL);
375 made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
376 g_free (dir);
378 dir = mc_build_filename (mc_config_get_path (), EDIT_DIR, NULL);
379 made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
380 g_free (dir);
382 dir = mc_build_filename (mc_config_get_data_path (), EDIT_DIR, NULL);
383 made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
384 g_free (dir);
387 wedit = edit_init (NULL, 1, 0, LINES - 2, COLS, _file_vpath, line);
389 if (wedit == NULL)
390 return 0;
392 /* Create a new dialog and add it widgets to it */
393 edit_dlg =
394 create_dlg (FALSE, 0, 0, LINES, COLS, NULL, edit_dialog_callback,
395 "[Internal File Editor]", NULL, DLG_WANT_TAB);
397 edit_dlg->get_shortcut = edit_get_shortcut;
398 edit_dlg->get_title = edit_get_title;
400 menubar = menubar_new (0, 0, COLS, NULL);
401 add_widget (edit_dlg, menubar);
402 edit_init_menu (menubar);
404 init_widget (&wedit->widget, wedit->widget.y, wedit->widget.x,
405 wedit->widget.lines, wedit->widget.cols, edit_callback, edit_event);
406 widget_want_cursor (wedit->widget, TRUE);
408 add_widget (edit_dlg, wedit);
410 add_widget (edit_dlg, buttonbar_new (TRUE));
412 run_dlg (edit_dlg);
414 if (edit_dlg->state == DLG_CLOSED)
415 destroy_dlg (edit_dlg);
417 return 1;
420 /* --------------------------------------------------------------------------------------------- */
422 char *
423 edit_get_file_name (const WEdit * edit)
425 return vfs_path_to_str (edit->filename_vpath);
428 /* --------------------------------------------------------------------------------------------- */
430 void
431 edit_update_screen (WEdit * e)
433 edit_scroll_screen_over_cursor (e);
435 edit_update_curs_col (e);
436 edit_status (e);
438 /* pop all events for this window for internal handling */
439 if (!is_idle ())
440 e->force |= REDRAW_PAGE;
441 else
443 if (e->force & REDRAW_COMPLETELY)
444 e->force |= REDRAW_PAGE;
445 edit_render_keypress (e);
449 /* --------------------------------------------------------------------------------------------- */