Reorganize WDialog flags.
[midnight-commander.git] / src / editor / editcmd_dialogs.c
blob007e69a511449e293b30c550d28759ae4600b33a
1 /*
2 Editor dialogs for high level editing commands
4 Copyright (C) 2009-2016
5 Free Software Foundation, Inc.
7 Written by:
8 Slava Zanko <slavazanko@gmail.com>, 2009
9 Andrew Borodin, <aborodin@vmail.ru>, 2012, 2013
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 #include <config.h>
29 #include "lib/global.h"
30 #include "lib/tty/tty.h"
31 #include "lib/skin.h" /* INPUT_COLOR */
32 #include "lib/tty/key.h"
33 #include "lib/search.h"
34 #include "lib/strutil.h"
35 #include "lib/widget.h"
36 #ifdef HAVE_CHARSET
37 #include "lib/charsets.h"
38 #endif
40 #include "src/history.h"
42 #include "src/editor/editwidget.h"
43 #include "src/editor/etags.h"
44 #include "src/editor/editcmd_dialogs.h"
46 #ifdef HAVE_ASPELL
47 #include "src/editor/spell.h"
48 #endif
50 /*** global variables ****************************************************************************/
52 edit_search_options_t edit_search_options = {
53 .type = MC_SEARCH_T_NORMAL,
54 .case_sens = FALSE,
55 .backwards = FALSE,
56 .only_in_selection = FALSE,
57 .whole_words = FALSE,
58 .all_codepages = FALSE
61 /*** file scope macro definitions ****************************************************************/
63 /*** file scope type declarations ****************************************************************/
65 /*** file scope variables ************************************************************************/
67 /*** file scope functions ************************************************************************/
68 /* --------------------------------------------------------------------------------------------- */
70 static cb_ret_t
71 editcmd_dialog_raw_key_query_cb (Widget * w, Widget * sender, widget_msg_t msg, int parm,
72 void *data)
74 WDialog *h = DIALOG (w);
76 switch (msg)
78 case MSG_KEY:
79 h->ret_value = parm;
80 dlg_stop (h);
81 return MSG_HANDLED;
82 default:
83 return dlg_default_callback (w, sender, msg, parm, data);
87 /* --------------------------------------------------------------------------------------------- */
88 /*** public functions ****************************************************************************/
89 /* --------------------------------------------------------------------------------------------- */
91 gboolean
92 editcmd_dialog_search_show (WEdit * edit)
94 char *search_text;
95 size_t num_of_types;
96 gchar **list_of_types;
97 int dialog_result;
99 list_of_types = mc_search_get_types_strings_array (&num_of_types);
102 quick_widget_t quick_widgets[] = {
103 /* *INDENT-OFF* */
104 QUICK_LABELED_INPUT (N_("Enter search string:"), input_label_above, INPUT_LAST_TEXT,
105 MC_HISTORY_SHARED_SEARCH, &search_text, NULL, FALSE, FALSE,
106 INPUT_COMPLETE_NONE),
107 QUICK_SEPARATOR (TRUE),
108 QUICK_START_COLUMNS,
109 QUICK_RADIO (num_of_types, (const char **) list_of_types,
110 (int *) &edit_search_options.type, NULL),
111 QUICK_NEXT_COLUMN,
112 QUICK_CHECKBOX (N_("Cas&e sensitive"), &edit_search_options.case_sens, NULL),
113 QUICK_CHECKBOX (N_("&Backwards"), &edit_search_options.backwards, NULL),
114 QUICK_CHECKBOX (N_("In se&lection"), &edit_search_options.only_in_selection, NULL),
115 QUICK_CHECKBOX (N_("&Whole words"), &edit_search_options.whole_words, NULL),
116 #ifdef HAVE_CHARSET
117 QUICK_CHECKBOX (N_("&All charsets"), &edit_search_options.all_codepages, NULL),
118 #endif
119 QUICK_STOP_COLUMNS,
120 QUICK_START_BUTTONS (TRUE, TRUE),
121 QUICK_BUTTON (N_("&OK"), B_ENTER, NULL, NULL),
122 QUICK_BUTTON (N_("&Find all"), B_USER, NULL, NULL),
123 QUICK_BUTTON (N_("&Cancel"), B_CANCEL, NULL, NULL),
124 QUICK_END
125 /* *INDENT-ON* */
128 quick_dialog_t qdlg = {
129 -1, -1, 58,
130 N_("Search"), "[Input Line Keys]",
131 quick_widgets, NULL, NULL
134 dialog_result = quick_dialog (&qdlg);
137 g_strfreev (list_of_types);
139 if ((dialog_result == B_CANCEL) || (search_text == NULL) || (search_text[0] == '\0'))
141 g_free (search_text);
142 return FALSE;
145 if (dialog_result == B_USER)
146 search_create_bookmark = TRUE;
148 #ifdef HAVE_CHARSET
150 GString *tmp;
152 tmp = str_convert_to_input (search_text);
153 if (tmp != NULL)
155 g_free (search_text);
156 search_text = g_string_free (tmp, FALSE);
159 #endif
161 g_free (edit->last_search_string);
162 edit->last_search_string = search_text;
163 mc_search_free (edit->search);
165 #ifdef HAVE_CHARSET
166 edit->search = mc_search_new (edit->last_search_string, cp_source);
167 #else
168 edit->search = mc_search_new (edit->last_search_string, NULL);
169 #endif
170 if (edit->search != NULL)
172 edit->search->search_type = edit_search_options.type;
173 #ifdef HAVE_CHARSET
174 edit->search->is_all_charsets = edit_search_options.all_codepages;
175 #endif
176 edit->search->is_case_sensitive = edit_search_options.case_sens;
177 edit->search->whole_words = edit_search_options.whole_words;
178 edit->search->search_fn = edit_search_cmd_callback;
179 edit->search->update_fn = edit_search_update_callback;
182 return (edit->search != NULL);
185 /* --------------------------------------------------------------------------------------------- */
187 void
188 editcmd_dialog_replace_show (WEdit * edit, const char *search_default, const char *replace_default,
189 /*@out@ */ char **search_text, /*@out@ */ char **replace_text)
191 size_t num_of_types;
192 gchar **list_of_types;
194 if ((search_default == NULL) || (*search_default == '\0'))
195 search_default = INPUT_LAST_TEXT;
197 list_of_types = mc_search_get_types_strings_array (&num_of_types);
200 quick_widget_t quick_widgets[] = {
201 /* *INDENT-OFF* */
202 QUICK_LABELED_INPUT (N_("Enter search string:"), input_label_above, search_default,
203 MC_HISTORY_SHARED_SEARCH, search_text, NULL, FALSE, FALSE,
204 INPUT_COMPLETE_NONE),
205 QUICK_LABELED_INPUT (N_("Enter replacement string:"), input_label_above, replace_default,
206 "replace", replace_text, NULL, FALSE, FALSE, INPUT_COMPLETE_NONE),
207 QUICK_SEPARATOR (TRUE),
208 QUICK_START_COLUMNS,
209 QUICK_RADIO (num_of_types, (const char **) list_of_types,
210 (int *) &edit_search_options.type, NULL),
211 QUICK_NEXT_COLUMN,
212 QUICK_CHECKBOX (N_("Cas&e sensitive"), &edit_search_options.case_sens, NULL),
213 QUICK_CHECKBOX (N_("&Backwards"), &edit_search_options.backwards, NULL),
214 QUICK_CHECKBOX (N_("In se&lection"), &edit_search_options.only_in_selection, NULL),
215 QUICK_CHECKBOX (N_("&Whole words"), &edit_search_options.whole_words, NULL),
216 #ifdef HAVE_CHARSET
217 QUICK_CHECKBOX (N_("&All charsets"), &edit_search_options.all_codepages, NULL),
218 #endif
219 QUICK_STOP_COLUMNS,
220 QUICK_BUTTONS_OK_CANCEL,
221 QUICK_END
222 /* *INDENT-ON* */
225 quick_dialog_t qdlg = {
226 -1, -1, 58,
227 N_("Replace"), "[Input Line Keys]",
228 quick_widgets, NULL, NULL
231 if (quick_dialog (&qdlg) != B_CANCEL)
232 edit->replace_mode = 0;
233 else
235 *replace_text = NULL;
236 *search_text = NULL;
240 g_strfreev (list_of_types);
243 /* --------------------------------------------------------------------------------------------- */
246 editcmd_dialog_replace_prompt_show (WEdit * edit, char *from_text, char *to_text, int xpos,
247 int ypos)
249 Widget *w = WIDGET (edit);
251 /* dialog size */
252 int dlg_height = 10;
253 int dlg_width;
255 char tmp[BUF_MEDIUM];
256 char *repl_from, *repl_to;
257 int retval;
259 if (xpos == -1)
260 xpos = w->x + option_line_state_width + 1;
261 if (ypos == -1)
262 ypos = w->y + w->lines / 2;
263 /* Sometimes menu can hide replaced text. I don't like it */
264 if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + dlg_height - 1))
265 ypos -= dlg_height;
267 dlg_width = WIDGET (w->owner)->cols - xpos - 1;
269 g_snprintf (tmp, sizeof (tmp), "\"%s\"", from_text);
270 repl_from = g_strdup (str_trunc (tmp, dlg_width - 7));
272 g_snprintf (tmp, sizeof (tmp), "\"%s\"", to_text);
273 repl_to = g_strdup (str_trunc (tmp, dlg_width - 7));
276 quick_widget_t quick_widgets[] = {
277 /* *INDENT-OFF* */
278 QUICK_LABEL (repl_from, NULL),
279 QUICK_LABEL (N_("Replace with:"), NULL),
280 QUICK_LABEL (repl_to, NULL),
281 QUICK_START_BUTTONS (TRUE, TRUE),
282 QUICK_BUTTON (N_("&Replace"), B_ENTER, NULL, NULL),
283 QUICK_BUTTON (N_("A&ll"), B_REPLACE_ALL, NULL, NULL),
284 QUICK_BUTTON (N_("&Skip"), B_SKIP_REPLACE, NULL, NULL),
285 QUICK_BUTTON (N_("&Cancel"), B_CANCEL, NULL, NULL),
286 QUICK_END
287 /* *INDENT-ON* */
290 quick_dialog_t qdlg = {
291 ypos, xpos, -1,
292 N_("Confirm replace"), NULL,
293 quick_widgets, NULL, NULL
296 retval = quick_dialog (&qdlg);
299 g_free (repl_from);
300 g_free (repl_to);
302 return retval;
305 /* --------------------------------------------------------------------------------------------- */
306 /* gets a raw key from the keyboard. Passing cancel = 1 draws
307 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
308 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
309 and Esc are cannot returned */
312 editcmd_dialog_raw_key_query (const char *heading, const char *query, gboolean cancel)
314 int w, wq;
315 int y = 2;
316 WDialog *raw_dlg;
318 w = str_term_width1 (heading) + 6;
319 wq = str_term_width1 (query);
320 w = MAX (w, wq + 3 * 2 + 1 + 2);
322 raw_dlg =
323 dlg_create (TRUE, 0, 0, cancel ? 7 : 5, w, WPOS_CENTER | WPOS_TRYUP, FALSE, dialog_colors,
324 editcmd_dialog_raw_key_query_cb, NULL, NULL, heading);
325 widget_want_tab (WIDGET (raw_dlg), TRUE);
327 add_widget (raw_dlg, label_new (y, 3, query));
328 add_widget (raw_dlg, input_new (y++, 3 + wq + 1, input_colors,
329 w - (6 + wq + 1), "", 0, INPUT_COMPLETE_NONE));
330 if (cancel)
332 add_widget (raw_dlg, hline_new (y++, -1, -1));
333 /* Button w/o hotkey to allow use any key as raw or macro one */
334 add_widget_autopos (raw_dlg, button_new (y, 1, B_CANCEL, NORMAL_BUTTON, _("Cancel"), NULL),
335 WPOS_KEEP_TOP | WPOS_CENTER_HORZ, NULL);
338 w = dlg_run (raw_dlg);
339 dlg_destroy (raw_dlg);
341 return (cancel && (w == ESC_CHAR || w == B_CANCEL)) ? 0 : w;
344 /* --------------------------------------------------------------------------------------------- */
345 /* let the user select its preferred completion */
347 char *
348 editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** compl, int num_compl)
350 const Widget *we = CONST_WIDGET (edit);
351 int start_x, start_y, offset, i;
352 char *curr = NULL;
353 WDialog *compl_dlg;
354 WListbox *compl_list;
355 int compl_dlg_h; /* completion dialog height */
356 int compl_dlg_w; /* completion dialog width */
358 /* calculate the dialog metrics */
359 compl_dlg_h = num_compl + 2;
360 compl_dlg_w = max_len + 4;
361 start_x = we->x + edit->curs_col + edit->start_col + EDIT_TEXT_HORIZONTAL_OFFSET +
362 (edit->fullscreen ? 0 : 1) + option_line_state_width;
363 start_y = we->y + edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + (edit->fullscreen ? 0 : 1) + 1;
365 if (start_x < 0)
366 start_x = 0;
367 if (start_x < we->x + 1)
368 start_x = we->x + 1 + option_line_state_width;
369 if (compl_dlg_w > COLS)
370 compl_dlg_w = COLS;
371 if (compl_dlg_h > LINES - 2)
372 compl_dlg_h = LINES - 2;
374 offset = start_x + compl_dlg_w - COLS;
375 if (offset > 0)
376 start_x -= offset;
377 offset = start_y + compl_dlg_h - LINES;
378 if (offset > 0)
379 start_y -= offset;
381 /* create the dialog */
382 compl_dlg =
383 dlg_create (TRUE, start_y, start_x, compl_dlg_h, compl_dlg_w, WPOS_KEEP_DEFAULT, TRUE,
384 dialog_colors, NULL, NULL, "[Completion]", NULL);
386 /* create the listbox */
387 compl_list = listbox_new (1, 1, compl_dlg_h - 2, compl_dlg_w - 2, FALSE, NULL);
389 /* add the dialog */
390 add_widget (compl_dlg, compl_list);
392 /* fill the listbox with the completions */
393 for (i = num_compl - 1; i >= 0; i--) /* reverse order */
394 listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0, (char *) compl[i]->str, NULL,
395 FALSE);
397 /* pop up the dialog and apply the chosen completion */
398 if (dlg_run (compl_dlg) == B_ENTER)
400 listbox_get_current (compl_list, &curr, NULL);
401 curr = g_strdup (curr);
404 /* destroy dialog before return */
405 dlg_destroy (compl_dlg);
407 return curr;
410 /* --------------------------------------------------------------------------------------------- */
411 /* let the user select where function definition */
413 void
414 editcmd_dialog_select_definition_show (WEdit * edit, char *match_expr, int max_len, int word_len,
415 etags_hash_t * def_hash, int num_lines)
418 int start_x, start_y, offset, i;
419 char *curr = NULL;
420 etags_hash_t *curr_def = NULL;
421 WDialog *def_dlg;
422 WListbox *def_list;
423 int def_dlg_h; /* dialog height */
424 int def_dlg_w; /* dialog width */
426 (void) word_len;
427 /* calculate the dialog metrics */
428 def_dlg_h = num_lines + 2;
429 def_dlg_w = max_len + 4;
430 start_x = edit->curs_col + edit->start_col - (def_dlg_w / 2) +
431 EDIT_TEXT_HORIZONTAL_OFFSET + (edit->fullscreen ? 0 : 1) + option_line_state_width;
432 start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + (edit->fullscreen ? 0 : 1) + 1;
434 if (start_x < 0)
435 start_x = 0;
436 if (def_dlg_w > COLS)
437 def_dlg_w = COLS;
438 if (def_dlg_h > LINES - 2)
439 def_dlg_h = LINES - 2;
441 offset = start_x + def_dlg_w - COLS;
442 if (offset > 0)
443 start_x -= offset;
444 offset = start_y + def_dlg_h - LINES;
445 if (offset > 0)
446 start_y -= (offset + 1);
448 /* create the dialog */
449 def_dlg = dlg_create (TRUE, start_y, start_x, def_dlg_h, def_dlg_w, WPOS_KEEP_DEFAULT, TRUE,
450 dialog_colors, NULL, NULL, "[Definitions]", match_expr);
452 /* create the listbox */
453 def_list = listbox_new (1, 1, def_dlg_h - 2, def_dlg_w - 2, FALSE, NULL);
455 /* add the dialog */
456 add_widget (def_dlg, def_list);
458 /* fill the listbox with the completions */
459 for (i = 0; i < num_lines; i++)
461 char *label_def;
463 label_def =
464 g_strdup_printf ("%s -> %s:%ld", def_hash[i].short_define, def_hash[i].filename,
465 def_hash[i].line);
466 listbox_add_item (def_list, LISTBOX_APPEND_AT_END, 0, label_def, &def_hash[i], FALSE);
467 g_free (label_def);
470 /* pop up the dialog and apply the chosen completion */
471 if (dlg_run (def_dlg) == B_ENTER)
473 char *tmp_curr_def = (char *) curr_def;
474 int do_moveto = 0;
476 listbox_get_current (def_list, &curr, (void **) &tmp_curr_def);
477 curr_def = (etags_hash_t *) tmp_curr_def;
478 if (edit->modified)
480 if (!edit_query_dialog2
481 (_("Warning"),
482 _("Current text was modified without a file save.\n"
483 "Continue discards these changes."), _("C&ontinue"), _("&Cancel")))
485 edit->force |= REDRAW_COMPLETELY;
486 do_moveto = 1;
489 else
491 do_moveto = 1;
494 if (curr && do_moveto)
496 if (edit_stack_iterator + 1 < MAX_HISTORY_MOVETO)
498 vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath);
499 if (edit->dir_vpath != NULL)
501 edit_history_moveto[edit_stack_iterator].filename_vpath =
502 vfs_path_append_vpath_new (edit->dir_vpath, edit->filename_vpath, NULL);
504 else
506 edit_history_moveto[edit_stack_iterator].filename_vpath =
507 vfs_path_clone (edit->filename_vpath);
509 edit_history_moveto[edit_stack_iterator].line = edit->start_line +
510 edit->curs_row + 1;
511 edit_stack_iterator++;
512 vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath);
513 edit_history_moveto[edit_stack_iterator].filename_vpath =
514 vfs_path_from_str ((char *) curr_def->fullpath);
515 edit_history_moveto[edit_stack_iterator].line = curr_def->line;
516 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath,
517 edit_history_moveto[edit_stack_iterator].line);
522 /* clear definition hash */
523 for (i = 0; i < MAX_DEFINITIONS; i++)
525 g_free (def_hash[i].filename);
528 /* destroy dialog before return */
529 dlg_destroy (def_dlg);
532 /* --------------------------------------------------------------------------------------------- */