1 /* kbd-interface.c
2 * functions for implementing the customize keyboard dialog
3 *
4 * for Denemo, thu GNU graphical music notation editor
5 * (c) 2000-2005 Matthew Hiller
6 */
7
8 #include <config.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <string.h>
13
14 #include <gdk/gdkkeysyms.h>
15 #include <gtk/gtk.h>
16
17 #include "core/kbd-custom.h"
18 #include "core/prefops.h"
19 #include "ui/mousing.h"
20 #include "ui/palettes.h"
21 #include "core/utils.h"
22 #include "core/view.h"
23
24
25 static gint
get_command_position(GtkTreeModel * model,gint command_idx)26 get_command_position(GtkTreeModel* model, gint command_idx){
27 gboolean valid;
28 command_row* row1 = NULL;
29 command_row* row2 = NULL;
30 gint i = 0;
31 GtkTreeIter iter;
32
33 valid = gtk_tree_model_get_iter_first (model, &iter);
34 keymap_get_command_row(Denemo.map, &row2, command_idx);
35
36 while (valid){
37 gtk_tree_model_get (model, &iter, COL_ROW, &row1, -1);
38 if(row1 && row1 == row2)
39 return i;
40 i++;
41 valid = gtk_tree_model_iter_next (model, &iter);
42 }
43 return -1;
44 }
45
46 #if 0
47 static void
48 validate_keymap_name (GtkEntry * entry, GtkDialog * dialog)
49 {
50 const gchar *name = gtk_entry_get_text (GTK_ENTRY (entry));
51 gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, strlen (name) > 0);
52 }
53 #endif
54
55 static gboolean
capture_add_binding(GtkWidget * widget,GdkEventKey * event,gpointer user_data)56 capture_add_binding (GtkWidget * widget, GdkEventKey * event, gpointer user_data)
57 {
58 GdkModifierType modifiers;
59 guint command_idx;
60 GtkTreeModel *model;
61 GtkTreeSelection *selection;
62 GtkTreeIter iter;
63 GtkTreePath *path;
64 gint *array;
65 keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
66 //get the shortcut
67 if (isModifier (event))
68 return TRUE;
69 dnm_clean_event (event);
70 modifiers = dnm_sanitize_key_state (event);
71 gchar *name = dnm_accelerator_name (event->keyval, event->state);
72 if (!strcmp(name, "VoidSymbol"))
73 {
74 warningdialog (_("VoidSymbol not allowed"));
75 return TRUE;
76 }
77 if (cbdata->two_key == 1)
78 {
79 gint command_idx = lookup_command_for_keybinding_name (Denemo.map, name);
80 if (command_idx == -1)
81 {
82 cbdata->first_keyval = event->keyval;
83 cbdata->first_modifiers = modifiers;
84 cbdata->two_key = 2;
85 return TRUE;
86 }
87 else
88 {
89 cbdata->two_key = 0;
90 gchar *msg = g_strdup_printf (_("The command %s has the shortcut: %s\nDelete it first or start again selecting an unused keypress."), lookup_name_from_idx (Denemo.map, command_idx), name);
91 warningdialog (msg);
92 g_free (msg);
93 g_free (name);
94 g_warning ("trying to set a two key starting with a single");
95 return TRUE;
96 }
97 }
98 //get the command_index
99 selection = gtk_tree_view_get_selection (cbdata->command_view);
100 gtk_tree_selection_get_selected (selection, &model, &iter);
101 path = gtk_tree_model_get_path (model, &iter);
102 array = gtk_tree_path_get_indices (path);
103 command_idx = array[0]; //this fails in general, yielding the value in cbdata, instead ...
104 gchar* cname = NULL;
105 gtk_tree_model_get (model, &iter, COL_NAME, &cname, -1);
106 command_idx = lookup_command_from_name (Denemo.map, cname);
107 if(command_idx != cbdata->command_id)
108 g_warning("correct command idx %d compare %d for action of name %s\n", command_idx, cbdata->command_id, cname);
109 gtk_tree_path_free (path);
110
111
112 if (cbdata->two_key == 0 && (GList *) g_hash_table_lookup (Denemo.map->continuations_table, name))
113 {
114 //g_warning("There is a two key binding starting with this");
115 gchar *msg = g_strdup_printf (_("There is at least one two-key shortcut that starts with: %s\nFind them using the Find button\nDelete it/those first or start again selecting an unused keypress."), name);
116 warningdialog (msg);
117 g_free (msg);
118 g_free (name);
119 return TRUE;
120 }
121 g_free (name);
122 //set the new binding
123 if (cbdata->two_key == 2)
124 add_twokeybinding_to_idx (Denemo.map, cbdata->first_keyval, cbdata->first_modifiers, event->keyval, modifiers, command_idx, POS_FIRST);
125 else
126 add_keybinding_to_idx (Denemo.map, event->keyval, modifiers, command_idx, POS_FIRST);
127
128 command_row* row = NULL;
129 keymap_get_command_row (Denemo.map, &row, command_idx);
130 GtkListStore* bindings_model = GTK_LIST_STORE(gtk_tree_view_get_model(cbdata->binding_view));
131 update_bindings_model(bindings_model, row->bindings);
132
133 gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
134 g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_key_press);
135 g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_focus_out);
136 cbdata->two_key = 0;
137 return TRUE;
138 }
139
140 static gboolean
capture_look_binding(GtkWidget * widget,GdkEventKey * event,gpointer user_data)141 capture_look_binding (GtkWidget * widget, GdkEventKey * event, gpointer user_data)
142 {
143 GdkModifierType modifiers;
144 GtkTreeModel *model;
145 GtkTreeSelection *selection;
146 GtkTreeIter iter;
147 GtkTreePath *path;
148 gint command_idx;
149 keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
150 gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
151 //get the shortcut
152 if (isModifier (event))
153 return TRUE;
154 dnm_clean_event (event);
155 modifiers = dnm_sanitize_key_state (event);
156
157 //look for the keybinding
158 command_idx = lookup_command_for_keybinding (Denemo.map, event->keyval, modifiers);
159 //if the binding is associated to a command
160 if (command_idx == -1)
161 {
162 gchar *name = dnm_accelerator_name (event->keyval, event->state);
163 GList *g = (GList *) g_hash_table_lookup (Denemo.map->continuations_table, name);
164
165 GString *continuations = g_string_new ("");
166 GString *final_list = g_string_new ("");
167 for (; g; g = g->next)
168 {
169 g_string_append_printf (continuations, "%s%s%s", name, ",", (gchar *) g->data);
170 command_idx = lookup_command_for_keybinding_name (Denemo.map, continuations->str);
171 const gchar *this = lookup_name_from_idx (Denemo.map, command_idx);
172 g_string_append_printf (final_list, "%s,%s=%s ", name, (gchar *) g->data, this);
173 g_string_assign (continuations, "");
174 }
175 if (final_list->len)
176 cbdata->twokeylist = final_list;
177 }
178 if (command_idx != -1)
179 {
180 model = gtk_tree_view_get_model (cbdata->command_view);
181 gint pos = get_command_position(model, command_idx);
182 selection = gtk_tree_view_get_selection (cbdata->command_view);
183 gtk_tree_model_iter_nth_child (model, &iter, NULL, pos);
184 gtk_tree_selection_select_iter (selection, &iter);
185 path = gtk_tree_model_get_path (model, &iter);
186 gtk_tree_view_scroll_to_cell (cbdata->command_view, path, NULL, FALSE, 0, 0);
187 gtk_tree_path_free (path);
188 }
189 else
190 gtk_statusbar_push (cbdata->statusbar, cbdata->context_id, _("No command has this keyboard shortcut"));
191 if (cbdata->twokeylist)
192 {
193 gtk_statusbar_push (cbdata->statusbar, cbdata->context_id, cbdata->twokeylist->str);
194 g_string_free (cbdata->twokeylist, TRUE);
195 cbdata->twokeylist = NULL;
196 }
197 //clean the GUI
198 g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_key_press);
199 g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_focus_out);
200
201 return TRUE;
202 }
203
204 static gboolean
stop_capture_binding(GtkWidget * widget,G_GNUC_UNUSED GdkEventFocus * event,gpointer user_data)205 stop_capture_binding (GtkWidget * widget, G_GNUC_UNUSED GdkEventFocus * event, gpointer user_data)
206 {
207 keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
208 gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
209 g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_key_press);
210 g_signal_handler_disconnect (GTK_WIDGET (widget), cbdata->handler_focus_out);
211 return FALSE;
212 }
213
214 static void
kbd_interface_add_binding(GtkButton * button,gpointer user_data)215 kbd_interface_add_binding (GtkButton * button, gpointer user_data)
216 {
217 GtkTreeSelection *selection;
218 keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
219 gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
220 // check a command is selected
221 selection = gtk_tree_view_get_selection (cbdata->command_view);
222 if (!gtk_tree_selection_get_selected (selection, NULL, NULL))
223 return;
224 gtk_statusbar_push (cbdata->statusbar, cbdata->context_id, _("Press a shortcut sequence for this command"));
225 cbdata->handler_key_press = g_signal_connect (GTK_WIDGET (button), "key-press-event", G_CALLBACK (capture_add_binding), user_data);
226 cbdata->handler_focus_out = g_signal_connect (GTK_WIDGET (button), "focus-out-event", G_CALLBACK (stop_capture_binding), user_data);
227 Denemo.accelerator_status = TRUE;
228 }
229
230 static void
kbd_interface_add_2binding(GtkButton * button,gpointer user_data)231 kbd_interface_add_2binding (GtkButton * button, gpointer user_data)
232 {
233 keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
234 gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
235 cbdata->two_key = 1;
236 kbd_interface_add_binding (button, user_data);
237 }
238
239 static void
kbd_interface_look_binding(GtkButton * button,gpointer user_data)240 kbd_interface_look_binding (GtkButton * button, gpointer user_data)
241 {
242 keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
243 gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
244 gtk_statusbar_push (cbdata->statusbar, cbdata->context_id, _("Press a shortcut sequence whose command you seek"));
245 cbdata->handler_key_press = g_signal_connect (GTK_WIDGET (button), "key-press-event", G_CALLBACK (capture_look_binding), user_data);
246 cbdata->handler_focus_out = g_signal_connect (GTK_WIDGET (button), "focus-out-event", G_CALLBACK (stop_capture_binding), user_data);
247 }
248
249 static void
kbd_interface_del_binding(G_GNUC_UNUSED GtkButton * button,gpointer user_data)250 kbd_interface_del_binding (G_GNUC_UNUSED GtkButton * button, gpointer user_data)
251 {
252 GtkTreeSelection *selection;
253 gchar *binding;
254 GtkTreeModel *model;
255 GtkTreeIter iter;
256 command_row* row = NULL;
257 keyboard_dialog_data *cbdata = (keyboard_dialog_data *) user_data;
258 gtk_statusbar_pop (cbdata->statusbar, cbdata->context_id);
259 selection = gtk_tree_view_get_selection (cbdata->binding_view);
260 //if no binding is selected, we do nothing
261 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
262 return;
263 //else get the binding and remove it
264 gtk_tree_model_get (model, &iter, 0, &binding, -1);
265
266 gint command_id_ptr = lookup_command_for_keybinding_name(Denemo.map, binding);
267 remove_keybinding_from_name (Denemo.map, binding);
268
269 if(command_id_ptr > -1){
270 if(keymap_get_command_row (Denemo.map, &row, command_id_ptr))
271 update_bindings_model(GTK_LIST_STORE(model), row->bindings);
272 }
273 else
274 g_debug("Cannot find command to delete.\n");
275 g_free (binding);
276 Denemo.accelerator_status = TRUE;
277 }
278
279 static void
execute_current(keyboard_dialog_data * data)280 execute_current (keyboard_dialog_data *data)
281 {
282 GtkTreeModel *model;
283 GtkTreeSelection *selection;
284 GtkTreeIter iter;
285 gchar* cname = NULL;
286 selection = gtk_tree_view_get_selection (data->command_view);
287 gtk_tree_selection_get_selected (selection, &model, &iter);
288 gtk_tree_model_get (model, &iter, COL_NAME, &cname, -1);
289 gint command_idx = lookup_command_from_name (Denemo.map, cname);
290 if(command_idx != data->command_id)
291 g_warning("correct command idx %d compare %d for action of name %s\n", command_idx, data->command_id, cname);
292 execute_callback_from_idx (Denemo.map, command_idx);
293 }
294 static void
add_current_to_palette(keyboard_dialog_data * data)295 add_current_to_palette (keyboard_dialog_data *data)
296 {
297 GtkTreeModel *model;
298 GtkTreeSelection *selection;
299 GtkTreeIter iter;
300 gchar* cname = NULL;
301 selection = gtk_tree_view_get_selection (data->command_view);
302 gtk_tree_selection_get_selected (selection, &model, &iter);
303 gtk_tree_model_get (model, &iter, COL_NAME, &cname, -1);
304 gint command_idx = lookup_command_from_name (Denemo.map, cname);
305 place_action_in_palette (command_idx, NULL);
306 }
307
308
309
310
311 typedef struct ModifierPointerInfo
312 {
313 guint button_mask;
314 guint cursor_number;
315 } ModifierPointerInfo;
316
317 #define DENEMO_MODIFIER_MASK (255)
318 static void
keyboard_modifier_callback(GtkWidget * w,GdkEventButton * event,ModifierPointerInfo * info)319 keyboard_modifier_callback (GtkWidget * w, GdkEventButton * event, ModifierPointerInfo * info)
320 {
321 gint mask = info->button_mask;
322 gint state = (event->state & DENEMO_MODIFIER_MASK) | mask;
323 gint cursor_number = info->cursor_number;
324 GdkCursor *cursor = gdk_cursor_new (cursor_number);
325 //g_hash_table_lookup(Denemo.map->cursors, &state);
326
327 // show_type(w, "button mod callback: ");
328 GString *str = g_string_new ("");
329 g_string_append_printf (str, "Cursor Shape:- %d\n Mouse:- %s\nKeyboard:", cursor_number, mask ? (mask & GDK_BUTTON1_MASK ? "Left Button Drag" : "Right Button Drag") : "No Button Press");
330 append_modifier_name (str, state);
331 #define POINTER_PROMPT "To change the cursor shape for a mouse/keyboard state:\nSelect Cursor Shape number\nChoose mouse state and then click here\nwhile holding modifier key\nand/or engaging Caps/Num lock for the keyboard state. Finally save command set."
332 gdk_window_set_cursor (gtk_widget_get_window (w), cursor);
333 //g_string_append(str, "\n");
334 // g_string_append(str, POINTER_PROMPT);
335
336 gtk_button_set_label ((GtkButton *) w, str->str);
337 //gtk_widget_set_tooltip(w, POINTER_PROMPT);
338 assign_cursor (state, cursor_number);
339 g_string_free (str, TRUE);
340 }
341
342
343
344
345 static void
load_system_keymap_dialog_response(void)346 load_system_keymap_dialog_response (void)
347 {
348 load_system_keymap_dialog ();
349
350 }
351
352 static void
load_keymap_dialog_response(void)353 load_keymap_dialog_response (void)
354 {
355 load_keymap_dialog ();
356
357 }
358
359 static GtkWidget *SearchEntry = NULL;
360 static GtkWidget *SearchNext = NULL;
361
362 static keyboard_dialog_data cbdata;
363
get_command_view(void)364 GtkWidget *get_command_view(void)
365 {
366 return GTK_WIDGET(cbdata.command_view);
367 }
368
369 static void
shortcut_button_choice_callback(GtkWidget * w,gboolean * left)370 shortcut_button_choice_callback (GtkWidget * w, gboolean * left)
371 {
372 g_debug ("left at %p is %d\n", left, *left);
373 *left = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
374 g_debug ("left at %p is now %d\n", left, *left);
375 }
376
377 static void
button_move_callback(GtkWidget * w,mouse_gesture * g)378 button_move_callback (GtkWidget * w, mouse_gesture * g)
379 {
380 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
381 *g = GESTURE_MOVE;
382 //g_debug("move %d\n", *g);
383 }
384
385 static void
button_press_callback(GtkWidget * w,mouse_gesture * g)386 button_press_callback (GtkWidget * w, mouse_gesture * g)
387 {
388 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
389 *g = GESTURE_PRESS;
390 //g_debug("press %d\n", *g);
391 }
392
393 static void
button_release_callback(GtkWidget * w,mouse_gesture * g)394 button_release_callback (GtkWidget * w, mouse_gesture * g)
395 {
396 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
397 *g = GESTURE_RELEASE;
398 //g_debug("release %d \n", *g);
399 }
400
401 typedef struct ModifierAction
402 {
403 GtkAction *action;
404 gint modnum; /* GdkModifierType number 0...12 */
405 mouse_gesture gesture; /* if this is for press move or release */
406 gboolean left; /* if this is for left or right mouse button */
407 } ModifierAction;
408
409
410 static void
button_modifier_callback(GtkWidget * w,GdkEventButton * event,ModifierAction * ma)411 button_modifier_callback (GtkWidget * w, GdkEventButton * event, ModifierAction * ma)
412 {
413 ma->modnum = event->state;
414 // show_type(w, "button mod callback: ");
415 GString *str = g_string_new ("Keyboard:");
416 append_modifier_name (str, ma->modnum);
417 if (!ma->modnum)
418 g_string_assign (str, _("No keyboard modifier keys\nPress with modifier key to change"));
419 else
420 g_string_append (str, _("\nPress with modifier key to change"));
421 gtk_button_set_label (GTK_BUTTON (w), str->str);
422 g_string_free (str, TRUE);
423 }
424
425
426
427 // info->action is the action for which the mouse shortcut is to be set
428 static void
setMouseAction(ModifierAction * info)429 setMouseAction (ModifierAction * info)
430 {
431 GString *modname = mouse_shortcut_name (info->modnum, info->gesture, info->left);
432 gint command_idx = lookup_command_for_keybinding_name (Denemo.map, modname->str);
433 GtkAction *current_action = NULL;
434 gchar *title = NULL;
435 gchar *prompt = NULL;
436 if (command_idx >= 0)
437 {
438 current_action = (GtkAction *) lookup_action_from_idx (Denemo.map, command_idx);
439 title = g_strdup_printf (_("The Command %s Responds to this Shortcut"), lookup_name_from_idx (Denemo.map, command_idx));
440 prompt = g_strdup_printf (_("Lose the shortcut %s for this?"), modname->str);
441 }
442 if (current_action == NULL || confirm (title, prompt))
443 {
444 remove_keybinding_from_name (Denemo.map, modname->str); //by_name
445 const gchar *name = gtk_action_get_name (info->action);
446 command_idx = lookup_command_from_name (Denemo.map, name);
447 if (command_idx >= 0)
448 add_named_binding_to_idx (Denemo.map, modname->str, command_idx, POS_LAST);
449 }
450 g_free (title);
451 g_free (prompt);
452 g_string_free (modname, TRUE);
453 }
454
455 static void
mouse_shortcut_dialog(ModifierAction * info)456 mouse_shortcut_dialog (ModifierAction * info)
457 {
458 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Set Mouse Shortcut"),
459 GTK_WINDOW (Denemo.window),
460 (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
461 _("_OK"), GTK_RESPONSE_ACCEPT,
462 _("_Cancel"), GTK_RESPONSE_REJECT,
463 NULL);
464
465
466 GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
467
468 GtkWidget *hbox = gtk_hbox_new (FALSE, 1);
469 GtkWidget *vbox = gtk_vbox_new (FALSE, 1);
470 gtk_container_add (GTK_CONTAINER (content_area), hbox);
471 gtk_container_add (GTK_CONTAINER (hbox), vbox);
472
473 gchar *name = (gchar *) gtk_action_get_name (info->action);
474 gchar *prompt = g_strdup_printf (_("Setting mouse shortcut for %s"), name);
475 GtkWidget *label = gtk_label_new (prompt);
476 g_free (prompt);
477 gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
478 GtkWidget *frame = gtk_frame_new (_("Choose the mouse button"));
479 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
480 gtk_container_add (GTK_CONTAINER (vbox), frame);
481 GtkWidget *vbox2 = gtk_vbox_new (FALSE, 8);
482 gtk_container_add (GTK_CONTAINER (frame), vbox2);
483
484 info->left = TRUE;
485 GtkWidget *widget = gtk_radio_button_new_with_label (NULL, _("Left"));
486 g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (shortcut_button_choice_callback), &info->left);
487 gtk_box_pack_start (GTK_BOX (vbox2), widget, FALSE, TRUE, 0);
488 GtkWidget *widget2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (widget), _("Right"));
489 gtk_box_pack_start (GTK_BOX (vbox2), widget2, FALSE, TRUE, 0);
490
491
492 frame = gtk_frame_new (_("Choose mouse action"));
493 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
494 gtk_container_add (GTK_CONTAINER (vbox), frame);
495 vbox2 = gtk_vbox_new (FALSE, 8);
496 gtk_container_add (GTK_CONTAINER (frame), vbox2);
497 info->gesture = GESTURE_PRESS;
498 widget = gtk_radio_button_new_with_label (NULL, _("Press Button"));
499 g_signal_connect (G_OBJECT (widget), "toggled", G_CALLBACK (button_press_callback), &info->gesture);
500 gtk_box_pack_start (GTK_BOX (vbox2), widget, FALSE, TRUE, 0);
501 widget2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (widget), _("Release Button"));
502 g_signal_connect (G_OBJECT (widget2), "toggled", G_CALLBACK (button_release_callback), &info->gesture);
503 gtk_box_pack_start (GTK_BOX (vbox2), widget2, FALSE, TRUE, 0);
504 widget2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (widget), _("Drag"));
505 g_signal_connect (G_OBJECT (widget2), "toggled", G_CALLBACK (button_move_callback), &info->gesture);
506 gtk_box_pack_start (GTK_BOX (vbox2), widget2, FALSE, TRUE, 0);
507
508 widget = gtk_button_new_with_label (_("Hold Modifier Keys, Engage Caps or Num Lock\nand click here to set shortcut."));
509 g_signal_connect (G_OBJECT (widget), "button-release-event", G_CALLBACK (button_modifier_callback), info);
510 gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, TRUE, 0);
511
512
513
514 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
515 gtk_widget_show_all (dialog);
516 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
517 {
518 setMouseAction (info);
519 Denemo.accelerator_status = TRUE;
520 }
521 gtk_widget_destroy (dialog);
522 }
523
524
525 static void
createMouseShortcut(GtkAction * action)526 createMouseShortcut (GtkAction * action)
527 {
528 static ModifierAction info;
529 info.action = action;
530 info.gesture = GESTURE_PRESS;
531 info.modnum = 0;
532 info.left = TRUE;
533 mouse_shortcut_dialog (&info);
534 }
535
createMouseShortcut_from_data(keyboard_dialog_data * data)536 static void createMouseShortcut_from_data (keyboard_dialog_data *data) {
537 GtkTreeModel *model;
538 GtkTreeSelection *selection;
539 GtkTreeIter iter;
540 gchar* cname = NULL;
541 selection = gtk_tree_view_get_selection (data->command_view);
542 gtk_tree_selection_get_selected (selection, &model, &iter);
543 gtk_tree_model_get (model, &iter, COL_NAME, &cname, -1);
544 gint command_idx = lookup_command_from_name (Denemo.map, cname);
545 if(command_idx != -1)
546 {
547 GtkAction *action = (GtkAction *) lookup_action_from_idx (Denemo.map, command_idx);
548 createMouseShortcut (action);
549 }
550 }
551 void
configure_keyboard_dialog_init_idx(GtkAction * dummy,gint command_idx)552 configure_keyboard_dialog_init_idx (GtkAction * dummy, gint command_idx)
553 {
554 GtkWidget *frame;
555 GtkWidget *vbox, *outer_hbox;
556 GtkWidget *table;
557 GtkWidget *label;
558 GtkWidget *addbutton;
559 GtkWidget *add2button;
560 GtkWidget *delbutton;
561 GtkWidget *lookbutton;
562 GtkWidget *statusbar;
563 GtkWidget *button_save;
564 GtkWidget *button_save_as;
565 GtkWidget *button_load;
566 GtkWidget *button_load_from;
567
568 GtkWidget *command_view;
569 GtkWidget *binding_view;
570 GtkWidget *command_tree_view;
571 GtkWidget *binding_tree_view;
572 GtkWidget *text_view;
573 GtkWidget *scrolled_text_view;
574
575 GtkTreeSelection *selection;
576 GtkTreeIter iter;
577 GtkTreeModel *model;
578 GtkTreePath *path;
579 guint context_id;
580
581 if(Denemo.command_manager) {
582 model = gtk_tree_view_get_model (GTK_TREE_VIEW (cbdata.command_view));
583 if (command_idx == -1)
584 {
585 //selecting the first command
586 gtk_tree_model_get_iter_first (model, &iter);
587 }
588 else
589 {
590 gint pos = get_command_position(model, command_idx);
591 gtk_tree_model_iter_nth_child (model, &iter, NULL, pos);
592 }
593 gtk_widget_grab_focus (SearchEntry);
594 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cbdata.command_view));
595 gtk_tree_selection_select_iter (selection, &iter);
596 path = gtk_tree_model_get_path (model, &iter);
597 gtk_tree_view_scroll_to_cell ((GtkTreeView *) cbdata.command_view, path, NULL, FALSE, 0, 0);
598 gtk_tree_path_free (path);
599 if(!gtk_widget_get_visible(Denemo.command_manager))
600 activate_action ("/MainMenu/ViewMenu/" "ToggleCommandManager");
601 return;
602 }
603 if(SearchEntry==NULL) {
604 SearchEntry = gtk_entry_new ();
605 SearchNext = gtk_button_new_with_label ("→");
606 gtk_widget_set_tooltip_text (SearchEntry, _("Type search text here. Enter words that might be in the command label,\nor part of the text of a tooltip or the internal name.\nThe search is case insensitive. It goes on to the next match each time you enter letter that doesn't match the current command so check at each keypress.\nThe search re-starts from the top when you delete a letter."));
607 gtk_widget_set_tooltip_text (SearchNext, _("Search for the next matching command. Starts again at the top once it has reached the end."));
608 } //The actual searching is done in kbd-custom.c by passing in the globals SearchEntry and SearchNext, ugh!
609 //getting a binding view and a command view and connecting the change of
610 //command selection the the change of the model displayed by the binding view
611 binding_view = keymap_get_binding_view ();
612 binding_tree_view = gtk_bin_get_child (GTK_BIN (binding_view));
613 command_view = GTK_WIDGET (keymap_get_command_view (Denemo.map, SearchEntry, SearchNext));
614 command_tree_view = gtk_bin_get_child (GTK_BIN (command_view));
615
616 Denemo.command_manager = gtk_window_new (GTK_WINDOW_TOPLEVEL);
617 gtk_window_set_title(GTK_WINDOW(Denemo.command_manager), (_("Command Center")));
618 if (Denemo.prefs.newbie)
619 gtk_widget_set_tooltip_text (Denemo.command_manager,
620 _
621 ("This window allows you find and execute commands.\nOnce you have selected a command the box at the top gives information about that command,"
622 "\nwhile the panel to the side gives any shortcuts for the command."
623 "\nYou can add a selected command to a palette, or set single-key or two-key shortcuts."
624 "\nYou can also hide commands, so they don't appear in the menus.\n"
625 "You can save the shortcuts as your default command set, or as a command set which you may wish to load in the future.\n"
626 "This window is also where you can load such a stored command set."));
627
628 outer_hbox = gtk_hbox_new (FALSE, 8);
629 gtk_container_add (GTK_CONTAINER (Denemo.command_manager), outer_hbox);
630 vbox = gtk_vbox_new (FALSE, 8);
631
632
633
634 gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
635 gtk_box_pack_start (GTK_BOX (outer_hbox), vbox, TRUE, TRUE, 0);
636
637
638 frame = gtk_frame_new (_("Help for Selected Command"));
639 gtk_frame_set_shadow_type ((GtkFrame *) frame, GTK_SHADOW_IN);
640 gtk_widget_set_size_request (frame, -1, 200);
641 gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
642 text_view = gtk_text_view_new ();
643 gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE);
644 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view), GTK_WRAP_WORD);
645 scrolled_text_view = gtk_scrolled_window_new (gtk_adjustment_new (1.0, 1.0, 2.0, 1.0, 4.0, 1.0), gtk_adjustment_new (1.0, 1.0, 2.0, 1.0, 4.0, 1.0));
646 gtk_container_add (GTK_CONTAINER (scrolled_text_view), text_view);
647 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_text_view), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
648 gtk_container_add (GTK_CONTAINER (frame), scrolled_text_view);
649
650
651
652 {
653 GtkWidget *inner_hbox = gtk_hbox_new (FALSE, 8);
654 gtk_box_pack_start (GTK_BOX (vbox), inner_hbox, TRUE, TRUE, 0);
655 gtk_box_pack_start (GTK_BOX (inner_hbox), gtk_widget_get_parent(command_view), TRUE, TRUE, 0);
656 {
657 GtkWidget *inner_vbox = gtk_vbox_new (FALSE, 8);
658 gtk_box_pack_start (GTK_BOX (inner_hbox), inner_vbox, TRUE, TRUE, 0);
659 GtkWidget *label = gtk_label_new ("");
660 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
661 gtk_label_set_markup (GTK_LABEL (label), _("List of shortcuts\nfor <i>selected</i> command\nfrom table on left.\nSelect a shortcut\nto remove\nwith button below."));
662
663 gtk_box_pack_start (GTK_BOX (inner_vbox), label, TRUE, TRUE, 0);
664 gtk_box_pack_start (GTK_BOX (inner_vbox), binding_view, FALSE, TRUE, 0);
665 delbutton = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
666 gtk_box_pack_start (GTK_BOX (inner_vbox), delbutton, FALSE, TRUE, 0);
667 }
668 }
669
670 vbox = gtk_vbox_new (FALSE, 8);
671 gtk_box_pack_end (GTK_BOX (outer_hbox), vbox, FALSE, TRUE, 0);
672
673 {
674 GtkWidget *inner_hbox = gtk_hbox_new (FALSE, 8);
675 gtk_box_pack_start (GTK_BOX (vbox), inner_hbox, FALSE, TRUE, 0);
676 button_save = gtk_button_new_with_label (_("Save as Default Command Set"));
677 gtk_box_pack_start (GTK_BOX (inner_hbox), button_save, FALSE, TRUE, 0);
678 gtk_widget_set_tooltip_text (button_save, _("Use this to save the changes you have made so that they are used every time you start Denemo. The changes are stored under a directory (folder) called .denemo-* in your home directory. Look in subdirectory actions for Default.commands"));
679 button_save_as = gtk_button_new_with_label (_("Save as a Custom Command Set"));
680 gtk_box_pack_start (GTK_BOX (inner_hbox), button_save_as, FALSE, TRUE, 0);
681
682 button_load = gtk_button_new_with_label (_("Load a Standard Command Set"));
683 inner_hbox = gtk_hbox_new (FALSE, 8);
684 gtk_box_pack_start (GTK_BOX (vbox), inner_hbox, FALSE, TRUE, 0);
685 button_load = gtk_button_new_with_label (_("Load a Standard Command Set"));
686 gtk_box_pack_start (GTK_BOX (inner_hbox), button_load, FALSE, TRUE, 0);
687
688 button_load_from = gtk_button_new_with_label (_("Load a Custom Command Set"));
689 gtk_box_pack_start (GTK_BOX (inner_hbox), button_load_from, FALSE, TRUE, 0);
690
691 }
692
693 GtkWidget *inner_hbox = gtk_hbox_new (FALSE, 1);
694 gtk_box_pack_end (GTK_BOX (vbox), inner_hbox, FALSE, TRUE, 0);
695 GtkWidget *inner_vbox = gtk_vbox_new (FALSE, 1);
696 gtk_box_pack_end (GTK_BOX (inner_hbox), inner_vbox, FALSE, TRUE, 0);
697 addbutton = gtk_button_new_from_stock (GTK_STOCK_ADD);
698 gtk_button_set_label (GTK_BUTTON (addbutton), _("Add 1-Key Shortcut"));
699 gtk_widget_set_tooltip_text (addbutton, _("Create a single keypress (with modifier keys - Control, Shift ... - if needed) as a keyboard shortcut for the currently selected command."));
700 gtk_box_pack_end (GTK_BOX (inner_vbox), addbutton, FALSE, TRUE, 0);
701
702 add2button = gtk_button_new_from_stock (GTK_STOCK_ADD);
703 gtk_button_set_label (GTK_BUTTON (add2button), _("Add 2-Key Shortcut"));
704 gtk_widget_set_tooltip_text (add2button, _("Create a two keypress sequence as a keyboard shortcut for the currently selected command."));
705 gtk_box_pack_end (GTK_BOX (inner_vbox), add2button, FALSE, TRUE, 0);
706
707 lookbutton = gtk_button_new_from_stock (GTK_STOCK_FIND);
708 gtk_button_set_label (GTK_BUTTON (lookbutton), _("Find Command for Shortcut"));
709 gtk_widget_set_tooltip_text (lookbutton, _("Finds the command (if any) for a (one key) Keyboard Shortcut\n"
710 "Click button then press the key shortcut you are looking for."));
711 gtk_box_pack_end (GTK_BOX (inner_vbox), lookbutton, FALSE, TRUE, 0);
712
713
714 inner_vbox = gtk_vbox_new (FALSE, 1);
715 gtk_box_pack_start (GTK_BOX (inner_hbox), inner_vbox, FALSE, TRUE, 0);
716 GtkWidget *execute_button = gtk_button_new_with_label (_("Execute Selected Command"));
717 gtk_widget_set_tooltip_text (execute_button, _("Executes the currently selected command in the list of commands\nEnsure the cursor is in the movement and at the position if needed for the command."));
718 gtk_box_pack_end (GTK_BOX (inner_vbox), execute_button, FALSE, TRUE, 0);
719 GtkWidget *palette_button = gtk_button_new_with_label (_("Add to Palette"));
720 gtk_widget_set_tooltip_text (palette_button, _("Adds the currently selected command in the list of commands to a palette\nYou can create a new, custom palette, and you can change the label of the button you create by right-clicking on it."));
721 gtk_box_pack_end (GTK_BOX (inner_vbox), palette_button, FALSE, TRUE, 0);
722 g_signal_connect_swapped (G_OBJECT (execute_button), "clicked", G_CALLBACK (execute_current), &cbdata);
723 g_signal_connect_swapped (G_OBJECT (palette_button), "clicked", G_CALLBACK (add_current_to_palette), &cbdata);
724
725
726
727
728
729 statusbar = gtk_statusbar_new ();
730 context_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), "");
731 //FIXME gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), FALSE);
732 gtk_box_pack_end (GTK_BOX (vbox), statusbar, FALSE, TRUE, 0);
733
734 cbdata.addbutton = GTK_BUTTON (addbutton);
735 cbdata.add2button = GTK_BUTTON (add2button);
736 cbdata.delbutton = GTK_BUTTON (delbutton);
737 cbdata.lookbutton = GTK_BUTTON (lookbutton);
738 cbdata.statusbar = GTK_STATUSBAR (statusbar);
739 cbdata.context_id = context_id;
740 cbdata.command_view = GTK_TREE_VIEW (command_tree_view);
741 cbdata.binding_view = GTK_TREE_VIEW (binding_tree_view);
742 cbdata.text_view = GTK_TEXT_VIEW (text_view);
743 cbdata.command_id = -1;
744 cbdata.two_key = 0;
745 cbdata.twokeylist = NULL;
746
747 //setup the link between command_view and binding_view
748 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (command_tree_view));
749 gtk_tree_selection_set_select_function (selection, keymap_change_binding_view_on_command_selection, &cbdata, NULL);
750
751 model = gtk_tree_view_get_model (GTK_TREE_VIEW (command_tree_view));
752 if (command_idx == -1)
753 {
754 //selecting the first command
755 gtk_tree_model_get_iter_first (model, &iter);
756 }
757 else
758 {
759 gint pos = get_command_position(model, command_idx);
760 gtk_tree_model_iter_nth_child (model, &iter, NULL, pos);
761 path = gtk_tree_model_get_path (model, &iter);
762 gtk_tree_view_scroll_to_cell ((GtkTreeView *) command_tree_view, path, NULL, FALSE, 0, 0);
763 gtk_tree_path_free (path);
764 }
765 gtk_widget_grab_focus (SearchEntry);
766 gtk_tree_selection_select_iter (selection, &iter);
767
768
769 GtkWidget *shortcut_button = gtk_button_new_with_label (_("Set Mouse Shortcut"));
770 gtk_widget_set_tooltip_text (shortcut_button, _("Set mouse shortcut"));
771 g_signal_connect_swapped (G_OBJECT (shortcut_button), "button-release-event", G_CALLBACK (createMouseShortcut_from_data), &cbdata);
772 gtk_box_pack_end (GTK_BOX (vbox), shortcut_button, FALSE, TRUE, 0);
773
774
775 //Connecting signals
776 g_signal_connect (addbutton, "clicked", G_CALLBACK (kbd_interface_add_binding), &cbdata);
777 g_signal_connect (add2button, "clicked", G_CALLBACK (kbd_interface_add_2binding), &cbdata);
778
779 g_signal_connect (lookbutton, "clicked", G_CALLBACK (kbd_interface_look_binding), &cbdata);
780 g_signal_connect (delbutton, "clicked", G_CALLBACK (kbd_interface_del_binding), &cbdata);
781
782 g_signal_connect (G_OBJECT (button_save), "clicked", G_CALLBACK (save_default_keymap_file), NULL);
783 g_signal_connect (G_OBJECT (button_save_as), "clicked", G_CALLBACK (save_keymap_dialog), NULL);
784 g_signal_connect (G_OBJECT (button_load), "clicked", G_CALLBACK (load_system_keymap_dialog_response), NULL);
785 g_signal_connect (G_OBJECT (button_load_from), "clicked", G_CALLBACK (load_keymap_dialog_response), NULL);
786
787 gtk_widget_show_all (Denemo.command_manager);
788 g_signal_connect (Denemo.command_manager, "delete-event", G_CALLBACK (keymap_cleanup_command_view), &cbdata);
789 }
790
791 void
configure_keyboard_dialog(GtkAction * action,DenemoScriptParam * param)792 configure_keyboard_dialog (GtkAction * action, DenemoScriptParam * param)
793 {
794 configure_keyboard_dialog_init_idx (action, -1);
795 }
796
797