88#include <glib/gi18n-lib.h>
99#include <gio/gio.h>
1010#include <gtk/gtk.h>
11+ #include <gdk/gdkkeysyms.h>
1112
1213#include "translate-preferences.h"
1314#include "translate-utils.h"
@@ -29,6 +30,111 @@ static const Lang k_langs[] = {
2930 {"ja" , N_ ("Japanese" )}, {"ko" , N_ ("Korean" )}, {"zh" , N_ ("Chinese" )},
3031};
3132
33+ /* ============================================================================
34+ * Shortcut capture button
35+ * ============================================================================ */
36+
37+ typedef struct {
38+ gchar * accel ; /* current accelerator string, owned */
39+ gboolean capturing ;
40+ gulong key_handler_id ;
41+ GtkWidget * dialog ;
42+ } ShortcutButtonData ;
43+
44+ static void
45+ shortcut_button_data_free (gpointer ptr )
46+ {
47+ ShortcutButtonData * data = ptr ;
48+ g_free (data -> accel );
49+ g_free (data );
50+ }
51+
52+ static gboolean
53+ shortcut_key_press_cb (GtkWidget * widget ,
54+ GdkEventKey * event ,
55+ gpointer user_data )
56+ {
57+ GtkButton * button = GTK_BUTTON (user_data );
58+ ShortcutButtonData * data = g_object_get_data (G_OBJECT (button ), "shortcut-data" );
59+
60+ if (!data || !data -> capturing )
61+ return FALSE;
62+
63+ /* Ignore standalone modifier key presses */
64+ if (event -> is_modifier )
65+ return TRUE;
66+
67+ data -> capturing = FALSE;
68+ g_signal_handler_disconnect (data -> dialog , data -> key_handler_id );
69+ data -> key_handler_id = 0 ;
70+
71+ if (event -> keyval == GDK_KEY_Escape ) {
72+ /* Restore previous label */
73+ guint kval = 0 ;
74+ GdkModifierType mods = 0 ;
75+ if (data -> accel && * data -> accel )
76+ gtk_accelerator_parse (data -> accel , & kval , & mods );
77+ gchar * label = kval ? gtk_accelerator_get_label (kval , mods )
78+ : g_strdup (data -> accel && * data -> accel ? data -> accel : _ ("(none)" ));
79+ gtk_button_set_label (button , label );
80+ g_free (label );
81+ } else {
82+ GdkModifierType mods = event -> state & gtk_accelerator_get_default_mod_mask ();
83+ g_free (data -> accel );
84+ data -> accel = gtk_accelerator_name (event -> keyval , mods );
85+ gchar * label = gtk_accelerator_get_label (event -> keyval , mods );
86+ gtk_button_set_label (button , label );
87+ g_free (label );
88+ }
89+
90+ return TRUE;
91+ }
92+
93+ static void
94+ shortcut_button_clicked_cb (GtkButton * button ,
95+ gpointer user_data )
96+ {
97+ ShortcutButtonData * data = g_object_get_data (G_OBJECT (button ), "shortcut-data" );
98+
99+ if (!data || data -> capturing )
100+ return ;
101+
102+ data -> capturing = TRUE;
103+ gtk_button_set_label (button , _ ("Press shortcut\xe2\x80\xa6" ));
104+ data -> key_handler_id = g_signal_connect (data -> dialog , "key-press-event" ,
105+ G_CALLBACK (shortcut_key_press_cb ), button );
106+ }
107+
108+ static GtkWidget *
109+ create_shortcut_button (const gchar * accel ,
110+ GtkWidget * dialog )
111+ {
112+ ShortcutButtonData * data = g_new0 (ShortcutButtonData , 1 );
113+ data -> accel = g_strdup (accel ? accel : "" );
114+ data -> capturing = FALSE;
115+ data -> key_handler_id = 0 ;
116+ data -> dialog = dialog ;
117+
118+ guint kval = 0 ;
119+ GdkModifierType mods = 0 ;
120+ if (accel && * accel )
121+ gtk_accelerator_parse (accel , & kval , & mods );
122+ gchar * label = kval ? gtk_accelerator_get_label (kval , mods )
123+ : g_strdup (accel && * accel ? accel : _ ("(none)" ));
124+ GtkWidget * button = gtk_button_new_with_label (label );
125+ g_free (label );
126+
127+ g_object_set_data_full (G_OBJECT (button ), "shortcut-data" , data ,
128+ shortcut_button_data_free );
129+ g_signal_connect (button , "clicked" , G_CALLBACK (shortcut_button_clicked_cb ), NULL );
130+
131+ return button ;
132+ }
133+
134+ /* ============================================================================
135+ * Preferences dialog
136+ * ============================================================================ */
137+
32138void
33139translate_preferences_show (GtkWindow * parent )
34140{
@@ -73,13 +179,27 @@ translate_preferences_show (GtkWindow *parent)
73179 gboolean current_install_on_demand = g_settings_get_boolean (provider_settings , "install-on-demand" );
74180 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (install_on_demand ), current_install_on_demand );
75181
182+ /* Load current shortcut */
183+ g_autofree gchar * cur_translate_shortcut = g_settings_get_string (settings , "translate-shortcut" );
184+
185+ GtkWidget * lbl_translate_shortcut = gtk_label_new (_ ("Translate shortcut:" ));
186+ gtk_widget_set_halign (lbl_translate_shortcut , GTK_ALIGN_START );
187+ GtkWidget * translate_shortcut_btn = create_shortcut_button (cur_translate_shortcut , dlg );
188+
76189 gtk_grid_attach (GTK_GRID (grid ), lbl_lang , 0 , 0 , 1 , 1 );
77190 gtk_grid_attach (GTK_GRID (grid ), combo , 1 , 0 , 1 , 1 );
78191 gtk_grid_attach (GTK_GRID (grid ), lbl_provider , 0 , 1 , 1 , 1 );
79192 gtk_grid_attach (GTK_GRID (grid ), provider_combo , 1 , 1 , 1 , 1 );
80193 gtk_grid_attach (GTK_GRID (grid ), lbl_venv , 0 , 2 , 1 , 1 );
81194 gtk_grid_attach (GTK_GRID (grid ), venv_entry , 1 , 2 , 1 , 1 );
82195 gtk_grid_attach (GTK_GRID (grid ), install_on_demand , 1 , 3 , 1 , 1 );
196+ GtkWidget * lbl_shortcut_hint = gtk_label_new ("Takes effect after restarting Evolution." );
197+ gtk_widget_set_halign (lbl_shortcut_hint , GTK_ALIGN_START );
198+ gtk_style_context_add_class (gtk_widget_get_style_context (lbl_shortcut_hint ), "dim-label" );
199+
200+ gtk_grid_attach (GTK_GRID (grid ), lbl_translate_shortcut , 0 , 4 , 1 , 1 );
201+ gtk_grid_attach (GTK_GRID (grid ), translate_shortcut_btn , 1 , 4 , 1 , 1 );
202+ gtk_grid_attach (GTK_GRID (grid ), lbl_shortcut_hint , 1 , 5 , 1 , 1 );
83203
84204 gtk_widget_show_all (dlg );
85205 if (gtk_dialog_run (GTK_DIALOG (dlg )) == GTK_RESPONSE_OK ) {
@@ -97,6 +217,11 @@ translate_preferences_show (GtkWindow *parent)
97217 gboolean install_enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (install_on_demand ));
98218 g_settings_set_boolean (provider_settings , "install-on-demand" , install_enabled );
99219
220+ /* Save shortcut */
221+ ShortcutButtonData * ts_data = g_object_get_data (G_OBJECT (translate_shortcut_btn ), "shortcut-data" );
222+ if (ts_data && ts_data -> accel )
223+ g_settings_set_string (settings , "translate-shortcut" , ts_data -> accel );
224+
100225 /* venv_entry not yet implemented */
101226 (void )venv_entry ;
102227 }
0 commit comments