Skip to content

Commit 9ed2c95

Browse files
64-bitmanchrisbra
authored andcommitted
patch 9.2.0722: GTK4: find/replace dialog can be improved
Problem: GTK4: find/replace dialog can be improved Solution: Store the action buttons in the dialog struct, update their sensitivity when the search field changes, close the dialog on Escape and set the dialog's default widget (Foxe Chen) closes: #20613 Signed-off-by: Foxe Chen <chen.foxe@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
1 parent 37d9805 commit 9ed2c95

2 files changed

Lines changed: 97 additions & 7 deletions

File tree

src/gui_gtk4.c

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5297,6 +5297,9 @@ typedef struct
52975297
GtkWidget *mcase; // Match case check
52985298
GtkWidget *up; // Direction up radio
52995299
GtkWidget *down; // Direction down radio
5300+
GtkWidget *find; // 'Find Next' action button
5301+
GtkWidget *replace; // 'Replace With' action button
5302+
GtkWidget *all; // 'Replace All' action button
53005303
} SharedFindReplace;
53015304

53025305
static SharedFindReplace find_widgets = {0};
@@ -5347,6 +5350,61 @@ dialog_destroyed_cb(GtkWidget *widget UNUSED, gpointer data)
53475350
*(GtkWidget **)data = NULL;
53485351
}
53495352

5353+
static void
5354+
entry_changed_cb(GtkWidget *entry, GtkWidget *dialog)
5355+
{
5356+
const gchar *entry_text;
5357+
gboolean nonempty;
5358+
5359+
entry_text = gtk_editable_get_text(GTK_EDITABLE(entry));
5360+
5361+
if (!entry_text)
5362+
return; // Shouldn't happen
5363+
5364+
nonempty = (entry_text[0] != '\0');
5365+
5366+
if (dialog == find_widgets.dialog)
5367+
gtk_widget_set_sensitive(find_widgets.find, nonempty);
5368+
5369+
if (dialog == repl_widgets.dialog)
5370+
{
5371+
gtk_widget_set_sensitive(repl_widgets.find, nonempty);
5372+
gtk_widget_set_sensitive(repl_widgets.replace, nonempty);
5373+
gtk_widget_set_sensitive(repl_widgets.all, nonempty);
5374+
}
5375+
}
5376+
5377+
static gboolean
5378+
find_key_pressed_cb(
5379+
GtkEventControllerKey *controller,
5380+
guint keyval,
5381+
guint keycode,
5382+
GdkModifierType state,
5383+
SharedFindReplace *frdp)
5384+
{
5385+
// If the user is holding one of the key modifiers we will just bail out,
5386+
// thus preserving the possibility of normal focus traversal.
5387+
if (state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
5388+
return FALSE;
5389+
5390+
// the Escape key synthesizes a cancellation action
5391+
if (keyval == GDK_KEY_Escape)
5392+
{
5393+
// Destroy rather than hide the dialog: reusing a hidden toplevel loses
5394+
// window decorations on Wayland
5395+
gtk_window_destroy(GTK_WINDOW(frdp->dialog));
5396+
return TRUE;
5397+
}
5398+
5399+
return FALSE;
5400+
}
5401+
5402+
static void
5403+
entry_activate_cb(GtkWidget *widget UNUSED, void *udata)
5404+
{
5405+
gtk_widget_grab_focus(GTK_WIDGET(udata));
5406+
}
5407+
53505408
static void
53515409
find_replace_dialog_create(char_u *arg, int do_replace)
53525410
{
@@ -5356,6 +5414,7 @@ find_replace_dialog_create(char_u *arg, int do_replace)
53565414
int mcase = !p_ic;
53575415
GtkWidget *vertbox, *grid, *hbox, *tmp, *btn;
53585416
gboolean sensitive;
5417+
GtkEventController *key_controller;
53595418

53605419
frdp = do_replace ? &repl_widgets : &find_widgets;
53615420
entry_text = get_find_dialog_text(arg, &wword, &mcase);
@@ -5368,7 +5427,7 @@ find_replace_dialog_create(char_u *arg, int do_replace)
53685427
}
53695428

53705429
// If the dialog already exists, just raise it.
5371-
if (frdp->dialog)
5430+
if (frdp->dialog != NULL)
53725431
{
53735432
if (entry_text != NULL)
53745433
{
@@ -5380,7 +5439,15 @@ find_replace_dialog_create(char_u *arg, int do_replace)
53805439
(gboolean)mcase);
53815440
}
53825441
gtk_window_present(GTK_WINDOW(frdp->dialog));
5442+
5443+
// For :promptfind dialog, always give keyboard focus to 'what' entry.
5444+
// For :promptrepl dialog, give it to 'with' entry if 'what' has a
5445+
// non-empty entry; otherwise, to 'what' entry.
53835446
gtk_widget_grab_focus(frdp->what);
5447+
if (do_replace && g_utf8_strlen(
5448+
gtk_editable_get_text(GTK_EDITABLE(frdp->what)), -1) > 0)
5449+
gtk_widget_grab_focus(frdp->with);
5450+
53845451
vim_free(entry_text);
53855452
return;
53865453
}
@@ -5392,7 +5459,7 @@ find_replace_dialog_create(char_u *arg, int do_replace)
53925459
gtk_window_set_destroy_with_parent(GTK_WINDOW(frdp->dialog), TRUE);
53935460
gtk_window_set_title(GTK_WINDOW(frdp->dialog),
53945461
do_replace ? _("VIM - Search and Replace...")
5395-
: _("VIM - Search..."));
5462+
: _("VIM - Search..."));
53965463
gtk_window_set_resizable(GTK_WINDOW(frdp->dialog), FALSE);
53975464

53985465
g_signal_connect(frdp->dialog, "destroy",
@@ -5433,7 +5500,17 @@ find_replace_dialog_create(char_u *arg, int do_replace)
54335500
frdp->with = gtk_entry_new();
54345501
gtk_widget_set_hexpand(frdp->with, TRUE);
54355502
gtk_grid_attach(GTK_GRID(grid), frdp->with, 1, 1, 1, 1);
5503+
gtk_entry_set_activates_default(GTK_ENTRY(frdp->with), TRUE);
5504+
5505+
// Make the entry activation only change the input focus onto the
5506+
// with item.
5507+
gtk_entry_set_activates_default(GTK_ENTRY(frdp->what), FALSE);
5508+
g_signal_connect(G_OBJECT(frdp->what), "activate",
5509+
G_CALLBACK(entry_activate_cb), frdp->with);
54365510
}
5511+
else
5512+
// Make the entry activation do the search.
5513+
gtk_entry_set_activates_default(GTK_ENTRY(frdp->what), TRUE);
54375514

54385515
// Checkboxes
54395516
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
@@ -5472,20 +5549,36 @@ find_replace_dialog_create(char_u *arg, int do_replace)
54725549

54735550
btn = gtk_button_new_with_label(_("Find Next"));
54745551
gtk_widget_set_sensitive(btn, sensitive);
5552+
frdp->find = btn;
5553+
5554+
key_controller = gtk_event_controller_key_new();
5555+
g_signal_connect(key_controller, "key-pressed",
5556+
G_CALLBACK(find_key_pressed_cb), frdp);
5557+
gtk_widget_add_controller(GTK_WIDGET(frdp->dialog), key_controller);
5558+
5559+
g_signal_connect(G_OBJECT(frdp->what), "changed",
5560+
G_CALLBACK(entry_changed_cb), frdp->dialog);
5561+
5562+
// Make it so that when entry is activated, this button will be activated.
5563+
gtk_window_set_default_widget(GTK_WINDOW(frdp->dialog), btn);
54755564
g_signal_connect(btn, "clicked", G_CALLBACK(find_replace_cb),
54765565
GINT_TO_POINTER(do_replace ? FRD_R_FINDNEXT : FRD_FINDNEXT));
54775566
gtk_box_append(GTK_BOX(hbox), btn);
54785567

54795568
if (do_replace)
54805569
{
54815570
btn = gtk_button_new_with_label(_("Replace"));
5571+
gtk_widget_set_sensitive(btn, sensitive);
54825572
g_signal_connect(btn, "clicked", G_CALLBACK(find_replace_cb),
54835573
GINT_TO_POINTER(FRD_REPLACE));
5574+
frdp->replace = btn;
54845575
gtk_box_append(GTK_BOX(hbox), btn);
54855576

54865577
btn = gtk_button_new_with_label(_("Replace All"));
5578+
gtk_widget_set_sensitive(btn, sensitive);
54875579
g_signal_connect(btn, "clicked", G_CALLBACK(find_replace_cb),
54885580
GINT_TO_POINTER(FRD_REPLACEALL));
5581+
frdp->all = btn;
54895582
gtk_box_append(GTK_BOX(hbox), btn);
54905583
}
54915584

@@ -5494,11 +5587,6 @@ find_replace_dialog_create(char_u *arg, int do_replace)
54945587
G_CALLBACK(gtk_window_destroy), frdp->dialog);
54955588
gtk_box_append(GTK_BOX(hbox), btn);
54965589

5497-
// Connect Enter key in entry to Find Next
5498-
g_signal_connect_swapped(frdp->what, "activate",
5499-
G_CALLBACK(find_replace_cb),
5500-
GINT_TO_POINTER(do_replace ? FRD_R_FINDNEXT : FRD_FINDNEXT));
5501-
55025590
gtk_window_present(GTK_WINDOW(frdp->dialog));
55035591
gtk_widget_grab_focus(frdp->what);
55045592
if (do_replace && entry_text != NULL && entry_text[0] != NUL)

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,8 @@ static char *(features[]) =
759759

760760
static int included_patches[] =
761761
{ /* Add new patch number below this line */
762+
/**/
763+
722,
762764
/**/
763765
721,
764766
/**/

0 commit comments

Comments
 (0)