Drop old QuickWidget engine.
[midnight-commander.git] / src / editor / editcmd_dialogs.c
blob09e39428366fa88ae4947d190cf13d0e05340e1a
1 /*
2 Editor dialogs for high level editing commands
4 Copyright (C) 2009, 2011, 2012
5 The Free Software Foundation, Inc.
7 Written by:
8 Slava Zanko <slavazanko@gmail.com>, 2009.
9 Andrew Borodin, <aborodin@vmail.ru>, 2012.
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 (struct Dlg_head *h, Widget * sender,
72 dlg_msg_t msg, int parm, void *data)
74 switch (msg)
76 case DLG_KEY:
77 h->ret_value = parm;
78 dlg_stop (h);
79 return MSG_HANDLED;
80 default:
81 return default_dlg_callback (h, sender, msg, parm, data);
85 /* --------------------------------------------------------------------------------------------- */
86 /*** public functions ****************************************************************************/
87 /* --------------------------------------------------------------------------------------------- */
89 gboolean
90 editcmd_dialog_search_show (WEdit * edit)
92 char *search_text;
93 size_t num_of_types;
94 gchar **list_of_types;
95 int dialog_result;
97 list_of_types = mc_search_get_types_strings_array (&num_of_types);
100 quick_widget_t quick_widgets[] = {
101 /* *INDENT-OFF* */
102 QUICK_LABELED_INPUT (N_("Enter search string:"), input_label_above,
103 INPUT_LAST_TEXT, 0, MC_HISTORY_SHARED_SEARCH, &search_text, NULL),
104 QUICK_SEPARATOR (TRUE),
105 QUICK_START_COLUMNS,
106 QUICK_RADIO (num_of_types, (const char **) list_of_types,
107 (int *) &edit_search_options.type, NULL),
108 QUICK_NEXT_COLUMN,
109 QUICK_CHECKBOX (N_("Cas&e sensitive"), &edit_search_options.case_sens, NULL),
110 QUICK_CHECKBOX (N_("&Backwards"), &edit_search_options.backwards, NULL),
111 QUICK_CHECKBOX (N_("In se&lection"), &edit_search_options.only_in_selection, NULL),
112 QUICK_CHECKBOX (N_("&Whole words"), &edit_search_options.whole_words, NULL),
113 #ifdef HAVE_CHARSET
114 QUICK_CHECKBOX (N_("&All charsets"), &edit_search_options.all_codepages, NULL),
115 #endif
116 QUICK_STOP_COLUMNS,
117 QUICK_START_BUTTONS (TRUE, TRUE),
118 QUICK_BUTTON (N_("&OK"), B_ENTER, NULL, NULL),
119 QUICK_BUTTON (N_("&Find all"), B_USER, NULL, NULL),
120 QUICK_BUTTON (N_("&Cancel"), B_CANCEL, NULL, NULL),
121 QUICK_END
122 /* *INDENT-ON* */
125 quick_dialog_t qdlg = {
126 -1, -1, 58,
127 N_("Search"), "[Input Line Keys]",
128 quick_widgets, NULL, NULL
131 dialog_result = quick_dialog (&qdlg);
134 g_strfreev (list_of_types);
136 if ((dialog_result == B_CANCEL) || (search_text == NULL) || (search_text[0] == '\0'))
138 g_free (search_text);
139 return FALSE;
142 if (dialog_result == B_USER)
143 search_create_bookmark = TRUE;
145 #ifdef HAVE_CHARSET
147 GString *tmp;
149 tmp = str_convert_to_input (search_text);
150 if (tmp != NULL)
152 g_free (search_text);
153 search_text = g_string_free (tmp, FALSE);
156 #endif
158 g_free (edit->last_search_string);
159 edit->last_search_string = search_text;
160 mc_search_free (edit->search);
162 edit->search = mc_search_new (edit->last_search_string, -1);
163 if (edit->search != NULL)
165 edit->search->search_type = edit_search_options.type;
166 edit->search->is_all_charsets = edit_search_options.all_codepages;
167 edit->search->is_case_sensitive = edit_search_options.case_sens;
168 edit->search->whole_words = edit_search_options.whole_words;
169 edit->search->search_fn = edit_search_cmd_callback;
172 return (edit->search != NULL);
175 /* --------------------------------------------------------------------------------------------- */
177 void
178 editcmd_dialog_replace_show (WEdit * edit, const char *search_default, const char *replace_default,
179 /*@out@ */ char **search_text, /*@out@ */ char **replace_text)
181 size_t num_of_types;
182 gchar **list_of_types;
184 if ((search_default == NULL) || (*search_default == '\0'))
185 search_default = INPUT_LAST_TEXT;
187 list_of_types = mc_search_get_types_strings_array (&num_of_types);
190 quick_widget_t quick_widgets[] = {
191 /* *INDENT-OFF* */
192 QUICK_LABELED_INPUT (N_("Enter search string:"), input_label_above,
193 search_default, 0, MC_HISTORY_SHARED_SEARCH, search_text, NULL),
194 QUICK_LABELED_INPUT (N_("Enter replacement string:"), input_label_above,
195 replace_default, 0, "replace", replace_text, NULL),
196 QUICK_SEPARATOR (TRUE),
197 QUICK_START_COLUMNS,
198 QUICK_RADIO (num_of_types, (const char **) list_of_types,
199 (int *) &edit_search_options.type, NULL),
200 QUICK_NEXT_COLUMN,
201 QUICK_CHECKBOX (N_("Cas&e sensitive"), &edit_search_options.case_sens, NULL),
202 QUICK_CHECKBOX (N_("&Backwards"), &edit_search_options.backwards, NULL),
203 QUICK_CHECKBOX (N_("In se&lection"), &edit_search_options.only_in_selection, NULL),
204 QUICK_CHECKBOX (N_("&Whole words"), &edit_search_options.whole_words, NULL),
205 #ifdef HAVE_CHARSET
206 QUICK_CHECKBOX (N_("&All charsets"), &edit_search_options.all_codepages, NULL),
207 #endif
208 QUICK_STOP_COLUMNS,
209 QUICK_START_BUTTONS (TRUE, TRUE),
210 QUICK_BUTTON (N_("&OK"), B_ENTER, NULL, NULL),
211 QUICK_BUTTON (N_("&Cancel"), B_CANCEL, NULL, NULL),
212 QUICK_END
213 /* *INDENT-ON* */
216 quick_dialog_t qdlg = {
217 -1, -1, 58,
218 N_("Replace"), "[Input Line Keys]",
219 quick_widgets, NULL, NULL
222 if (quick_dialog (&qdlg) != B_CANCEL)
223 edit->replace_mode = 0;
224 else
226 *replace_text = NULL;
227 *search_text = NULL;
231 g_strfreev (list_of_types);
234 /* --------------------------------------------------------------------------------------------- */
237 editcmd_dialog_replace_prompt_show (WEdit * edit, char *from_text, char *to_text, int xpos,
238 int ypos)
240 Widget *w = WIDGET (edit);
242 /* dialog size */
243 int dlg_height = 10;
245 char tmp[BUF_MEDIUM];
246 char *repl_from, *repl_to;
247 int retval;
249 if (xpos == -1)
250 xpos = w->x + option_line_state_width + 1;
251 if (ypos == -1)
252 ypos = w->y + w->lines / 2;
253 /* Sometimes menu can hide replaced text. I don't like it */
254 if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + dlg_height - 1))
255 ypos -= dlg_height;
257 g_snprintf (tmp, sizeof (tmp), "\"%s\"", from_text);
258 repl_from = g_strdup (str_trunc (tmp, - 7));
260 g_snprintf (tmp, sizeof (tmp), "\"%s\"", to_text);
261 repl_to = g_strdup (str_trunc (tmp, - 7));
264 quick_widget_t quick_widgets[] = {
265 /* *INDENT-OFF* */
266 QUICK_LABEL (repl_from, NULL),
267 QUICK_LABEL (N_("Replace with:"), NULL),
268 QUICK_LABEL (repl_to, NULL),
269 QUICK_START_BUTTONS (TRUE, TRUE),
270 QUICK_BUTTON (N_("&Replace"), B_ENTER, NULL, NULL),
271 QUICK_BUTTON (N_("A&ll"), B_REPLACE_ALL, NULL, NULL),
272 QUICK_BUTTON (N_("&Skip"), B_SKIP_REPLACE, NULL, NULL),
273 QUICK_BUTTON (N_("&Cancel"), B_CANCEL, NULL, NULL),
274 QUICK_END
275 /* *INDENT-ON* */
278 quick_dialog_t qdlg = {
279 ypos, xpos, -1,
280 N_("Confirm replace"), NULL,
281 quick_widgets, NULL, NULL
284 retval = quick_dialog (&qdlg);
287 g_free (repl_from);
288 g_free (repl_to);
290 return retval;
293 /* --------------------------------------------------------------------------------------------- */
294 /* gets a raw key from the keyboard. Passing cancel = 1 draws
295 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
296 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
297 and Esc are cannot returned */
300 editcmd_dialog_raw_key_query (const char *heading, const char *query, gboolean cancel)
302 int w;
303 struct Dlg_head *raw_dlg;
305 w = str_term_width1 (query) + 7;
307 raw_dlg =
308 create_dlg (TRUE, 0, 0, 7, w, dialog_colors, editcmd_dialog_raw_key_query_cb, NULL,
309 NULL, heading, DLG_CENTER | DLG_TRYUP | DLG_WANT_TAB);
310 add_widget (raw_dlg, input_new (3 - cancel, w - 5, input_get_default_colors (),
311 2, "", 0, INPUT_COMPLETE_DEFAULT));
312 add_widget (raw_dlg, label_new (3 - cancel, 2, query));
313 if (cancel)
314 add_widget (raw_dlg, button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON, _("Cancel"), 0));
315 w = run_dlg (raw_dlg);
316 destroy_dlg (raw_dlg);
318 return (cancel && (w == ESC_CHAR || w == B_CANCEL)) ? 0 : w;
321 /* --------------------------------------------------------------------------------------------- */
322 /* let the user select its preferred completion */
324 void
325 editcmd_dialog_completion_show (WEdit * edit, int max_len, int word_len,
326 struct selection *compl, int num_compl)
329 int start_x, start_y, offset, i;
330 char *curr = NULL;
331 Dlg_head *compl_dlg;
332 WListbox *compl_list;
333 int compl_dlg_h; /* completion dialog height */
334 int compl_dlg_w; /* completion dialog width */
336 /* calculate the dialog metrics */
337 compl_dlg_h = num_compl + 2;
338 compl_dlg_w = max_len + 4;
339 start_x = edit->curs_col + edit->start_col - (compl_dlg_w / 2) +
340 EDIT_TEXT_HORIZONTAL_OFFSET + (edit->fullscreen ? 0 : 1) + option_line_state_width;
341 start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + (edit->fullscreen ? 0 : 1) + 1;
343 if (start_x < 0)
344 start_x = 0;
345 if (compl_dlg_w > COLS)
346 compl_dlg_w = COLS;
347 if (compl_dlg_h > LINES - 2)
348 compl_dlg_h = LINES - 2;
350 offset = start_x + compl_dlg_w - COLS;
351 if (offset > 0)
352 start_x -= offset;
353 offset = start_y + compl_dlg_h - LINES;
354 if (offset > 0)
355 start_y -= (offset + 1);
357 /* create the dialog */
358 compl_dlg =
359 create_dlg (TRUE, start_y, start_x, compl_dlg_h, compl_dlg_w,
360 dialog_colors, NULL, NULL, "[Completion]", NULL, DLG_COMPACT);
362 /* create the listbox */
363 compl_list = listbox_new (1, 1, compl_dlg_h - 2, compl_dlg_w - 2, FALSE, NULL);
365 /* add the dialog */
366 add_widget (compl_dlg, compl_list);
368 /* fill the listbox with the completions */
369 for (i = num_compl - 1; i >= 0; i--) /* reverse order */
370 listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0, (char *) compl[i].text, NULL);
372 /* pop up the dialog and apply the choosen completion */
373 if (run_dlg (compl_dlg) == B_ENTER)
375 listbox_get_current (compl_list, &curr, NULL);
376 if (curr)
378 #ifdef HAVE_CHARSET
379 GString *temp, *temp2;
380 temp = g_string_new ("");
381 for (curr += word_len; *curr; curr++)
382 g_string_append_c (temp, *curr);
384 temp2 = str_convert_to_input (temp->str);
386 if (temp2 && temp2->len)
388 g_string_free (temp, TRUE);
389 temp = temp2;
391 else
392 g_string_free (temp2, TRUE);
393 for (curr = temp->str; *curr; curr++)
394 edit_insert (edit, *curr);
395 g_string_free (temp, TRUE);
396 #else
397 for (curr += word_len; *curr; curr++)
398 edit_insert (edit, *curr);
399 #endif
403 /* destroy dialog before return */
404 destroy_dlg (compl_dlg);
407 /* --------------------------------------------------------------------------------------------- */
408 /* let the user select where function definition */
410 void
411 editcmd_dialog_select_definition_show (WEdit * edit, char *match_expr, int max_len, int word_len,
412 etags_hash_t * def_hash, int num_lines)
415 int start_x, start_y, offset, i;
416 char *curr = NULL;
417 etags_hash_t *curr_def = NULL;
418 Dlg_head *def_dlg;
419 WListbox *def_list;
420 int def_dlg_h; /* dialog height */
421 int def_dlg_w; /* dialog width */
422 char *label_def = NULL;
424 (void) word_len;
425 /* calculate the dialog metrics */
426 def_dlg_h = num_lines + 2;
427 def_dlg_w = max_len + 4;
428 start_x = edit->curs_col + edit->start_col - (def_dlg_w / 2) +
429 EDIT_TEXT_HORIZONTAL_OFFSET + (edit->fullscreen ? 0 : 1) + option_line_state_width;
430 start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + (edit->fullscreen ? 0 : 1) + 1;
432 if (start_x < 0)
433 start_x = 0;
434 if (def_dlg_w > COLS)
435 def_dlg_w = COLS;
436 if (def_dlg_h > LINES - 2)
437 def_dlg_h = LINES - 2;
439 offset = start_x + def_dlg_w - COLS;
440 if (offset > 0)
441 start_x -= offset;
442 offset = start_y + def_dlg_h - LINES;
443 if (offset > 0)
444 start_y -= (offset + 1);
446 /* create the dialog */
447 def_dlg = create_dlg (TRUE, start_y, start_x, def_dlg_h, def_dlg_w,
448 dialog_colors, NULL, NULL, "[Definitions]", match_expr, DLG_COMPACT);
450 /* create the listbox */
451 def_list = listbox_new (1, 1, def_dlg_h - 2, def_dlg_w - 2, FALSE, NULL);
453 /* add the dialog */
454 add_widget (def_dlg, def_list);
456 /* fill the listbox with the completions */
457 for (i = 0; i < num_lines; i++)
459 label_def =
460 g_strdup_printf ("%s -> %s:%ld", def_hash[i].short_define, def_hash[i].filename,
461 def_hash[i].line);
462 listbox_add_item (def_list, LISTBOX_APPEND_AT_END, 0, label_def, &def_hash[i]);
463 g_free (label_def);
466 /* pop up the dialog and apply the choosen completion */
467 if (run_dlg (def_dlg) == B_ENTER)
469 char *tmp_curr_def = (char *) curr_def;
470 int do_moveto = 0;
472 listbox_get_current (def_list, &curr, (void **) &tmp_curr_def);
473 curr_def = (etags_hash_t *) tmp_curr_def;
474 if (edit->modified)
476 if (!edit_query_dialog2
477 (_("Warning"),
478 _("Current text was modified without a file save.\n"
479 "Continue discards these changes."), _("C&ontinue"), _("&Cancel")))
481 edit->force |= REDRAW_COMPLETELY;
482 do_moveto = 1;
485 else
487 do_moveto = 1;
490 if (curr && do_moveto)
492 if (edit_stack_iterator + 1 < MAX_HISTORY_MOVETO)
494 vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath);
495 if (edit->dir_vpath != NULL)
497 edit_history_moveto[edit_stack_iterator].filename_vpath =
498 vfs_path_append_vpath_new (edit->dir_vpath, edit->filename_vpath, NULL);
500 else
502 edit_history_moveto[edit_stack_iterator].filename_vpath =
503 vfs_path_clone (edit->filename_vpath);
505 edit_history_moveto[edit_stack_iterator].line = edit->start_line +
506 edit->curs_row + 1;
507 edit_stack_iterator++;
508 vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath);
509 edit_history_moveto[edit_stack_iterator].filename_vpath =
510 vfs_path_from_str ((char *) curr_def->fullpath);
511 edit_history_moveto[edit_stack_iterator].line = curr_def->line;
512 edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath,
513 edit_history_moveto[edit_stack_iterator].line);
518 /* clear definition hash */
519 for (i = 0; i < MAX_DEFINITIONS; i++)
521 g_free (def_hash[i].filename);
524 /* destroy dialog before return */
525 destroy_dlg (def_dlg);
528 /* --------------------------------------------------------------------------------------------- */