2 Editor dialogs for high level editing commands
4 Copyright (C) 2009 The Free Software Foundation, Inc.
7 Slava Zanko <slavazanko@gmail.com>, 2009.
9 This file is part of the Midnight Commander.
11 The Midnight Commander is free software; you can redistribute it
12 and/or modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version.
16 The Midnight Commander is distributed in the hope that it will be
17 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
18 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
29 #include "../src/global.h"
31 #include "../src/tty/tty.h"
32 #include "../src/tty/color.h" /* INPUT_COLOR */
33 #include "../src/tty/key.h"
35 #include "../src/search/search.h"
37 #include "../src/strutil.h"
38 #include "../src/widget.h"
39 #include "../src/wtools.h"
40 #include "../src/dialog.h" /* do_refresh() */
41 #include "../src/main.h"
42 #include "../src/history.h"
44 #include "../edit/edit-widget.h"
45 #include "../edit/etags.h"
46 #include "../edit/editcmd_dialogs.h"
49 /*** global variables **************************************************/
51 /*** file scope macro definitions **************************************/
53 #define SEARCH_DLG_WIDTH 58
54 #define SEARCH_DLG_MIN_HEIGHT 11
55 #define SEARCH_DLG_HEIGHT_SUPPLY 3
57 #define REPLACE_DLG_WIDTH 58
58 #define REPLACE_DLG_MIN_HEIGHT 16
59 #define REPLACE_DLG_HEIGHT_SUPPLY 5
61 /*** file scope type declarations **************************************/
63 /*** file scope variables **********************************************/
66 /*** file scope functions **********************************************/
69 editcmd_dialog_raw_key_query_cb (struct Dlg_head
*h
, dlg_msg_t msg
, int parm
)
77 return default_dlg_callback (h
, msg
, parm
);
81 /*** public functions **************************************************/
84 editcmd_dialog_replace_show (WEdit
* edit
, const char *search_default
, const char *replace_default
,
85 /*@out@ */ char **search_text
, /*@out@ */ char **replace_text
)
87 int treplace_backwards
= edit
->replace_backwards
;
88 int treplace_case
= edit
->replace_case
;
89 int tall_codepages
= edit
->all_codepages
;
90 mc_search_type_t ttype_of_search
= edit
->search_type
;
92 gchar
**list_of_types
= mc_search_get_types_strings_array();
94 int REPLACE_DLG_HEIGHT
= REPLACE_DLG_MIN_HEIGHT
+ g_strv_length (list_of_types
) - REPLACE_DLG_HEIGHT_SUPPLY
;
97 search_default
= INPUT_LAST_TEXT
;
99 QuickWidget quick_widgets
[] = {
101 {quick_button
, 6, 10, 12, REPLACE_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
,
102 0, 0, NULL
, NULL
, NULL
},
104 {quick_button
, 2, 10, 12, REPLACE_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
,
105 0, 0, NULL
, NULL
, NULL
},
108 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 9, REPLACE_DLG_HEIGHT
, N_("All charsets"), 0, 0,
109 &tall_codepages
, 0, NULL
, NULL
, NULL
},
112 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 8, REPLACE_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
113 &treplace_backwards
, 0, NULL
, NULL
, NULL
},
115 {quick_checkbox
, 33, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
116 &treplace_case
, 0, NULL
, NULL
, NULL
},
119 {quick_radio
, 3, REPLACE_DLG_WIDTH
, 7, REPLACE_DLG_HEIGHT
, "", g_strv_length (list_of_types
), ttype_of_search
,
120 (void *) &ttype_of_search
, const_cast (char **, list_of_types
), NULL
, NULL
, NULL
},
122 {quick_label
, 2, REPLACE_DLG_WIDTH
, 4, REPLACE_DLG_HEIGHT
, N_(" Enter replacement string:"),
123 0, 0, 0, 0, 0, NULL
, NULL
},
125 {quick_input
, 3, REPLACE_DLG_WIDTH
, 5, REPLACE_DLG_HEIGHT
, replace_default
, 52, 0,
126 0, replace_text
, "replace", NULL
, NULL
},
129 {quick_label
, 2, REPLACE_DLG_WIDTH
, 2, REPLACE_DLG_HEIGHT
, N_(" Enter search string:"), 0,
130 0, 0, 0, 0, NULL
, NULL
},
132 {quick_input
, 3, REPLACE_DLG_WIDTH
, 3, REPLACE_DLG_HEIGHT
, search_default
, 52, 0,
133 0, search_text
, MC_HISTORY_SHARED_SEARCH
, NULL
, NULL
},
140 QuickDialog Quick_input
= {
151 dialog_result
= quick_dialog (&Quick_input
);
152 g_strfreev (list_of_types
);
154 if (dialog_result
!= B_CANCEL
) {
155 edit
->search_type
= ttype_of_search
;
156 edit
->replace_mode
= 0;
157 edit
->all_codepages
= tall_codepages
;
158 edit
->replace_backwards
= treplace_backwards
;
159 edit
->replace_case
= treplace_case
;
162 *replace_text
= NULL
;
168 /* --------------------------------------------------------------------------------------------- */
171 editcmd_dialog_search_show (WEdit
* edit
, char **search_text
)
173 int tsearch_case
= edit
->replace_case
;
174 int tsearch_backwards
= edit
->replace_backwards
;
175 int tall_codepages
= edit
->all_codepages
;
176 mc_search_type_t ttype_of_search
= edit
->search_type
;
177 gchar
**list_of_types
= mc_search_get_types_strings_array();
178 int SEARCH_DLG_HEIGHT
= SEARCH_DLG_MIN_HEIGHT
+ g_strv_length (list_of_types
) - SEARCH_DLG_HEIGHT_SUPPLY
;
181 *search_text
= INPUT_LAST_TEXT
;
183 QuickWidget quick_widgets
[] = {
184 {quick_button
, 6, 10, 9, SEARCH_DLG_HEIGHT
, N_("&Cancel"), 0, B_CANCEL
, 0,
185 0, NULL
, NULL
, NULL
},
186 {quick_button
, 2, 10, 9, SEARCH_DLG_HEIGHT
, N_("&OK"), 0, B_ENTER
, 0,
187 0, NULL
, NULL
, NULL
},
190 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 7, SEARCH_DLG_HEIGHT
, N_("All charsets"), 0, 0,
191 &tall_codepages
, 0, NULL
, NULL
, NULL
},
194 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 6, SEARCH_DLG_HEIGHT
, N_("&Backwards"), 0, 0,
195 &tsearch_backwards
, 0, NULL
, NULL
, NULL
},
196 {quick_checkbox
, 33, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, N_("case &Sensitive"), 0, 0,
197 &tsearch_case
, 0, NULL
, NULL
, NULL
},
200 {quick_radio
, 3, SEARCH_DLG_WIDTH
, 5, SEARCH_DLG_HEIGHT
, 0, g_strv_length (list_of_types
), ttype_of_search
,
201 (void *) &ttype_of_search
, const_cast (char **, list_of_types
), NULL
, NULL
, NULL
},
203 {quick_input
, 3, SEARCH_DLG_WIDTH
, 3, SEARCH_DLG_HEIGHT
, *search_text
, 52, 0, 0,
204 search_text
, MC_HISTORY_SHARED_SEARCH
, NULL
, NULL
},
205 {quick_label
, 2, SEARCH_DLG_WIDTH
, 2, SEARCH_DLG_HEIGHT
, N_(" Enter search string:"), 0, 0,
206 0, 0, 0, NULL
, NULL
},
212 QuickDialog Quick_input
= { SEARCH_DLG_WIDTH
, SEARCH_DLG_HEIGHT
, -1, 0, N_("Search"),
213 "[Input Line Keys]", quick_widgets
, 0
217 if (quick_dialog (&Quick_input
) != B_CANCEL
) {
218 edit
->search_type
= ttype_of_search
;
219 edit
->replace_backwards
= tsearch_backwards
;
220 edit
->all_codepages
= tall_codepages
;
221 edit
->replace_case
= tsearch_case
;
227 /* --------------------------------------------------------------------------------------------- */
229 /* gets a raw key from the keyboard. Passing cancel = 1 draws
230 a cancel button thus allowing c-c etc. Alternatively, cancel = 0
231 will return the next key pressed. ctrl-a (=B_CANCEL), ctrl-g, ctrl-c,
232 and Esc are cannot returned */
235 editcmd_dialog_raw_key_query (const char *heading
, const char *query
, int cancel
)
237 int w
= str_term_width1 (query
) + 7;
238 struct Dlg_head
*raw_dlg
=
239 create_dlg (0, 0, 7, w
, dialog_colors
, editcmd_dialog_raw_key_query_cb
,
241 DLG_CENTER
| DLG_TRYUP
| DLG_WANT_TAB
);
243 input_new (3 - cancel
, w
- 5, INPUT_COLOR
, 2, "", 0, INPUT_COMPLETE_DEFAULT
));
244 add_widget (raw_dlg
, label_new (3 - cancel
, 2, query
));
246 add_widget (raw_dlg
, button_new (4, w
/ 2 - 5, B_CANCEL
, NORMAL_BUTTON
, _("Cancel"), 0));
248 w
= raw_dlg
->ret_value
;
249 destroy_dlg (raw_dlg
);
251 if (w
== XCTRL ('g') || w
== XCTRL ('c') || w
== ESC_CHAR
|| w
== B_CANCEL
)
258 /* --------------------------------------------------------------------------------------------- */
260 /* let the user select its preferred completion */
262 editcmd_dialog_completion_show (WEdit
* edit
, int max_len
, int word_len
,
263 struct selection
*compl, int num_compl
)
266 int start_x
, start_y
, offset
, i
;
269 WListbox
*compl_list
;
270 int compl_dlg_h
; /* completion dialog height */
271 int compl_dlg_w
; /* completion dialog width */
273 /* calculate the dialog metrics */
274 compl_dlg_h
= num_compl
+ 2;
275 compl_dlg_w
= max_len
+ 4;
276 start_x
= edit
->curs_col
+ edit
->start_col
- (compl_dlg_w
/ 2) +
277 EDIT_TEXT_HORIZONTAL_OFFSET
+ option_line_state_width
;
278 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
282 if (compl_dlg_w
> COLS
)
284 if (compl_dlg_h
> LINES
- 2)
285 compl_dlg_h
= LINES
- 2;
287 offset
= start_x
+ compl_dlg_w
- COLS
;
290 offset
= start_y
+ compl_dlg_h
- LINES
;
292 start_y
-= (offset
+ 1);
294 /* create the dialog */
296 create_dlg (start_y
, start_x
, compl_dlg_h
, compl_dlg_w
,
297 dialog_colors
, NULL
, "[Completion]", NULL
, DLG_COMPACT
);
299 /* create the listbox */
300 compl_list
= listbox_new (1, 1, compl_dlg_h
- 2, compl_dlg_w
- 2, NULL
);
303 add_widget (compl_dlg
, compl_list
);
305 /* fill the listbox with the completions */
306 for (i
= 0; i
< num_compl
; i
++)
307 listbox_add_item (compl_list
, LISTBOX_APPEND_AT_END
, 0, (char *) compl[i
].text
, NULL
);
309 /* pop up the dialog */
312 /* apply the choosen completion */
313 if (compl_dlg
->ret_value
== B_ENTER
) {
314 listbox_get_current (compl_list
, &curr
, NULL
);
316 for (curr
+= word_len
; *curr
; curr
++)
317 edit_insert (edit
, *curr
);
320 /* destroy dialog before return */
321 destroy_dlg (compl_dlg
);
324 /* --------------------------------------------------------------------------------------------- */
326 /* let the user select where function definition */
328 editcmd_dialog_select_definition_show (WEdit
* edit
, char *match_expr
, int max_len
, int word_len
,
329 etags_hash_t
* def_hash
, int num_lines
)
332 int start_x
, start_y
, offset
, i
;
334 etags_hash_t
*curr_def
= NULL
;
337 int def_dlg_h
; /* dialog height */
338 int def_dlg_w
; /* dialog width */
339 char *label_def
= NULL
;
342 /* calculate the dialog metrics */
343 def_dlg_h
= num_lines
+ 2;
344 def_dlg_w
= max_len
+ 4;
345 start_x
= edit
->curs_col
+ edit
->start_col
- (def_dlg_w
/ 2) +
346 EDIT_TEXT_HORIZONTAL_OFFSET
+ option_line_state_width
;
347 start_y
= edit
->curs_row
+ EDIT_TEXT_VERTICAL_OFFSET
+ 1;
351 if (def_dlg_w
> COLS
)
353 if (def_dlg_h
> LINES
- 2)
354 def_dlg_h
= LINES
- 2;
356 offset
= start_x
+ def_dlg_w
- COLS
;
359 offset
= start_y
+ def_dlg_h
- LINES
;
361 start_y
-= (offset
+ 1);
363 /* create the dialog */
364 def_dlg
= create_dlg (start_y
, start_x
, def_dlg_h
, def_dlg_w
,
365 dialog_colors
, NULL
, "[Definitions]", match_expr
, DLG_COMPACT
);
367 /* create the listbox */
368 def_list
= listbox_new (1, 1, def_dlg_h
- 2, def_dlg_w
- 2, NULL
);
371 add_widget (def_dlg
, def_list
);
374 /* fill the listbox with the completions */
375 for (i
= 0; i
< num_lines
; i
++) {
377 g_strdup_printf ("%s -> %s:%ld", def_hash
[i
].short_define
, def_hash
[i
].filename
,
379 listbox_add_item (def_list
, LISTBOX_APPEND_AT_END
, 0, label_def
, &def_hash
[i
]);
382 /* pop up the dialog */
385 /* apply the choosen completion */
386 if (def_dlg
->ret_value
== B_ENTER
) {
387 char *tmp_curr_def
= (char *) curr_def
;
390 listbox_get_current (def_list
, &curr
, &tmp_curr_def
);
391 curr_def
= (etags_hash_t
*) tmp_curr_def
;
392 if (edit
->modified
) {
393 if (!edit_query_dialog2
395 _(" Current text was modified without a file save. \n"
396 " Continue discards these changes. "), _("C&ontinue"), _("&Cancel"))) {
397 edit
->force
|= REDRAW_COMPLETELY
;
403 if (curr
&& do_moveto
) {
404 if (edit_stack_iterator
+ 1 < MAX_HISTORY_MOVETO
) {
405 g_free (edit_history_moveto
[edit_stack_iterator
].filename
);
407 edit_history_moveto
[edit_stack_iterator
].filename
=
408 g_strdup_printf ("%s/%s", edit
->dir
, edit
->filename
);
410 edit_history_moveto
[edit_stack_iterator
].filename
= g_strdup (edit
->filename
);
412 edit_history_moveto
[edit_stack_iterator
].line
= edit
->start_line
+
414 edit_stack_iterator
++;
415 g_free (edit_history_moveto
[edit_stack_iterator
].filename
);
416 edit_history_moveto
[edit_stack_iterator
].filename
=
417 g_strdup ((char *) curr_def
->fullpath
);
418 edit_history_moveto
[edit_stack_iterator
].line
= curr_def
->line
;
419 edit_reload_line (edit
, edit_history_moveto
[edit_stack_iterator
].filename
,
420 edit_history_moveto
[edit_stack_iterator
].line
);
425 /* clear definition hash */
426 for (i
= 0; i
< MAX_DEFINITIONS
; i
++) {
427 g_free (def_hash
[i
].filename
);
430 /* destroy dialog before return */
431 destroy_dlg (def_dlg
);
434 /* --------------------------------------------------------------------------------------------- */
437 editcmd_dialog_replace_prompt_show (WEdit
* edit
, char *from_text
, char *to_text
, int xpos
, int ypos
)
447 char *repl_from
, *repl_to
;
448 char tmp
[BUF_MEDIUM
];
450 QuickWidget quick_widgets
[] = {
451 {quick_button
, 44, dlg_width
, 6, dlg_height
, N_("&Cancel"),
452 0, B_CANCEL
, 0, 0, NULL
, NULL
, NULL
},
453 {quick_button
, 29, dlg_width
, 6, dlg_height
, N_("&Skip"),
454 0, B_SKIP_REPLACE
, 0, 0, NULL
, NULL
, NULL
},
455 {quick_button
, 21, dlg_width
, 6, dlg_height
, N_("A&ll"),
456 0, B_REPLACE_ALL
, 0, 0, NULL
, NULL
, NULL
},
457 {quick_button
, 4, dlg_width
, 6, dlg_height
, N_("&Replace"),
458 0, B_ENTER
, 0, 0, NULL
, NULL
, NULL
},
459 {quick_label
, 3, dlg_width
, 2, dlg_height
, 0,
460 0, 0, 0, 0, 0, NULL
, NULL
},
461 {quick_label
, 2, dlg_width
, 3, dlg_height
, 0,
462 0, 0, 0, 0, 0, NULL
, NULL
},
463 {quick_label
, 3, dlg_width
, 4, dlg_height
, 0,
464 0, 0, 0, 0, 0, NULL
, NULL
},
469 for (i
= 0; i
< 4; i
++)
470 quick_widgets
[i
].text
= _(quick_widgets
[i
].text
);
473 /* calculate button positions */
476 for (i
= 3; i
> -1; i
--) {
477 quick_widgets
[i
].relative_x
= btn_pos
;
479 btn_pos
+= str_term_width1 (quick_widgets
[i
].text
) + 5;
481 if (i
== 3) /* default button */
485 dlg_width
= btn_pos
+ 2;
487 /* correct widget coordinates */
488 for (i
= 0; i
< 7; i
++)
489 quick_widgets
[i
].x_divisions
= dlg_width
;
491 g_snprintf (tmp
, sizeof (tmp
), " '%s'", from_text
);
492 repl_from
= g_strdup (str_fit_to_term (tmp
, dlg_width
- 7, J_LEFT
));
494 g_snprintf (tmp
, sizeof (tmp
), " '%s'", to_text
);
495 repl_to
= g_strdup (str_fit_to_term (tmp
, dlg_width
- 7, J_LEFT
));
497 quick_widgets
[4].text
= repl_from
;
498 quick_widgets
[5].text
= _(" Replace with: ");
499 quick_widgets
[6].text
= repl_to
;
502 xpos
= (edit
->num_widget_columns
- dlg_width
) / 2;
505 ypos
= edit
->num_widget_lines
* 2 / 3;
508 QuickDialog Quick_input
=
509 {dlg_width
, dlg_height
, 0, 0, N_ (" Confirm replace "),
510 "[Input Line Keys]", 0 /*quick_widgets */, 0 };
512 Quick_input
.widgets
= quick_widgets
;
514 Quick_input
.xpos
= xpos
;
516 /* Sometimes menu can hide replaced text. I don't like it */
518 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ dlg_height
- 1))
521 Quick_input
.ypos
= ypos
;
522 retval
= quick_dialog (&Quick_input
);
529 /* --------------------------------------------------------------------------------------------- */