File: shortcuts_config.tcl

package info (click to toggle)
mcu8051ide 1.4.9-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 18,820 kB
  • sloc: tcl: 94,956; xml: 2,122; sh: 2,114; asm: 246; ansic: 96; makefile: 30; awk: 18
file content (1038 lines) | stat: -rw-r--r-- 34,618 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
#!/usr/bin/tclsh
# Part of MCU 8051 IDE ( http://https://sourceforge.net/projects/mcu8051ide/ )

############################################################################
#    Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 by Martin Ošmera     #
#    martin.osmera@gmail.com                                               #
#                                                                          #
#    Copyright (C) 2014 by Moravia Microsystems, s.r.o.                    #
#    martin.osmera@gmail.com                                #
#                                                                          #
#    This program is free software; you can redistribute it and#or modify  #
#    it under the terms of the GNU General Public License as published by  #
#    the Free Software Foundation; either version 2 of the License, or     #
#    (at your option) any later version.                                   #
#                                                                          #
#    This program is distributed in the hope that it will be useful,       #
#    but WITHOUT ANY WARRANTY; without even the implied warranty of        #
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         #
#    GNU General Public License for more details.                          #
#                                                                          #
#    You should have received a copy of the GNU General Public License     #
#    along with this program; if not, write to the                         #
#    Free Software Foundation, Inc.,                                       #
#    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             #
############################################################################

# >>> File inclusion guard
if { ! [ info exists _SHORTCUTS_CONFIG_TCL ] } {
set _SHORTCUTS_CONFIG_TCL _
# <<< File inclusion guard

# --------------------------------------------------------------------------
# DESCRIPTION
# Implements shortcuts configuration dialog
# --------------------------------------------------------------------------

namespace eval shortcuts {
	variable dialog_opened	0	;# Bool: True if this dialog is already opened
	variable win			;# ID of dialog toplevel window

	variable changed		;# Bool: Settings changed
	variable anything_modified	;# Bool: Settings changed (stay set to 1 even after APPLY)
	variable local_DB		;# Array: Local database of shortcuts
	variable root_hard_cd		;# List of hadrcoded shortcuts (main window only)
	variable currentNode		;# ID of the currently selected tree node
	variable search_in_P		;# Bool: search in progress
	# Empty image
	variable empty_image [image create bitmap]
	# Font for entry "Current shortcut"
	variable current_entry_font	[font create				\
		-family $::DEFAULT_FIXED_FONT					\
		-weight [expr {$::MICROSOFT_WINDOWS ? "normal" : "bold"}]	\
		-size [expr {int(-12 * $::font_size_factor)}]			\
	]
	# Normal font for tree widget nodes
	variable node_font		[font create		\
		-family $::DEFAULT_FIXED_FONT			\
		-weight normal					\
		-size [expr {int(-12 * $::font_size_factor)}]	\
	]
	# Bold font for tree widget nodes
	variable node_font_b		[font create		\
		-family {helvetica}				\
		-weight bold					\
		-size [expr {int(-14 * $::font_size_factor)}]	\
	]

	variable status_label		;# ID of status label
	variable search_entry		;# ID of entry widget on search panel
	variable search_clear		;# ID of button "Clear search entry"
	variable treeWidget		;# ID of the tree widget
	variable bottom_lf_label	;# ID of label for bottom label frame
	variable discard_button		;# ID of button "Discard"
	variable accept_button		;# ID of button "Accept"
	variable default_entry		;# ID of label containging default key shortcut
	variable default_button		;# ID of button "Restore default" (bottom label frame)
	variable clear_button		;# ID of button "Clear"
	variable current_entry		;# ID of entry "Current shortcut"

	## Create the dialog
	 # @return void
	proc mkDialog {} {
		variable win			;# ID of toplevel dialog window
		variable dialog_opened		;# Bool: True if this dialog is already opened
		variable local_DB		;# Array: Local database of shortcuts
		variable changed		;# Bool: Settings changed
		variable anything_modified	;# Bool: Settings changed (stay set to 1 even after APPLY)
		variable search_entry		;# ID of entry widget on search panel
		variable search_clear		;# ID of button "Clear search entry"
		variable treeWidget		;# ID of the tree widget
		variable search_in_P		;# Bool: search in progress
		variable bottom_lf_label	;# ID of label for bottom label frame
		variable discard_button		;# ID of button "Discard"
		variable accept_button		;# ID of button "Accept"
		variable default_entry		;# ID of label containging default key shortcut
		variable default_button		;# ID of button "Restore default" (bottom label frame)
		variable clear_button		;# ID of button "Clear"
		variable current_entry		;# ID of entry "Current shortcut"
		variable empty_image		;# Empty image
		variable current_entry_font	;# Font for entry "Current shortcut"
		variable currentNode		;# ID of the currently selected tree node
		variable status_label		;# ID of status label
		variable root_hard_cd		;# List of hadrcoded shortcuts (main window only)
		variable node_font		;# Normal font for tree widget nodes
		variable node_font_b		;# Bold font for tree widget nodes

		# Destroy dialog window if it is already opened
		if {$dialog_opened} {
			destroy .shortcuts_config_dialog
		}
		set anything_modified 0
		set dialog_opened 1
		set currentNode {}
		set search_in_P 0
		set changed 0

		# Configure ttk styles
		ttk::style configure Shortcuts_Default.TLabel -relief sunken -borderwidth 1 -background {#F0F0F0}

		# Get settings from the program
		getSettings

		# Create list of hard-coded shortcuts related to main window
		set root_hard_cd {}
		foreach key ${::HARDCODED_SHORTCUTS} {
			lappend root_hard_cd [simplify_key_seq $key]
		}

		# Create toplevel window
		set win [toplevel .shortcuts_config_dialog -class {Configuration dialog} -bg ${::COMMON_BG_COLOR}]

		# Create window header
		label $win.header_label				\
			-compound left				\
			-image ::ICONS::32::configure		\
			-text [mc "Configure key shortcuts"]	\
			-font [font create -size [expr {int(-20 * $::font_size_factor)}]]

		# Create header labels for label frames
		set top_lf_label [label $win.top_lf_label	\
			-text [mc "available items"]		\
			-image ::ICONS::16::view_choose		\
			-compound left				\
		]
		set bottom_lf_label [label $win.bottom_lf_label	\
			-text [mc "<Nothing selected>"]		\
			-compound left -height 20		\
			-image $empty_image			\
		]

		# Create label frames
		set top_labelframe [ttk::labelframe $win.top_labelframe		\
			-labelwidget $top_lf_label -padding 7			\
		]
		set bottom_labelframe [ttk::labelframe $win.bottom_labelframe	\
			-labelwidget $bottom_lf_label -padding 7		\
		]

		# Create serach panel
		set search_frame [frame $top_labelframe.search_frame]
		pack [Label $search_frame.label	\
			-text [mc "Search:"]				\
			-helptext [mc "Enter your search string here"]	\
		] -side left
		set search_entry [ttk::entry $search_frame.entry			\
			-validate all							\
			-validatecommand {::configDialogues::shortcuts::search %P}	\
		]
		DynamicHelp::add $search_frame.entry	\
			-text [mc "Enter your search string here"]
		pack $search_entry -side left -fill x -expand 1
		set search_clear [ttk::button $search_frame.button	\
			-image ::ICONS::16::clear_left			\
			-style Flat.TButton				\
			-command "$search_entry delete 0 end"		\
			-state disabled					\
		]
		DynamicHelp::add $search_frame.button	\
			-text [mc "Clear"]
		pack $search_clear -side right -after $search_entry
		pack $search_frame -fill x -pady 5

		# Create frame for the tree widget and its scrollbar
		set tree_frame [frame $top_labelframe.tree_frame]
		pack $tree_frame -fill both -expand 1

		# Create tree widget showing available items
		set treeWidget [Tree $tree_frame.tree		\
			-selectfill 1				\
			-showlines 1				\
			-linesfill {#888888}			\
			-bg {#FFFFFF}				\
			-selectbackground {#CCCCFF}		\
			-selectforeground {#0000FF}		\
			-highlightthickness 0			\
			-padx 5					\
			-deltay 20				\
			-deltax 20				\
			-yscrollcommand "$tree_frame.scrollbar set"	\
			-crossopenimage ::ICONS::16::1downarrow		\
			-crosscloseimage ::ICONS::16::1rightarrow	\
			-selectcommand {::configDialogues::shortcuts::item_selected}	\
		]
		pack $treeWidget -fill both -expand 1 -side left
		bind $treeWidget <Button-5> {%W yview scroll +5 units; break}
		bind $treeWidget <Button-4> {%W yview scroll -5 units; break}

		# Create scrollbar for the tree widget
		pack [ttk::scrollbar $tree_frame.scrollbar	\
			-command "$treeWidget yview"		\
			-orient vertical			\
		] -fill y -side left -after $treeWidget

		# Fill in the tree
		foreach block ${::SHORTCUTS_LIST} {
			# Determinate category
			set cat_org [lindex $block 0]
			set cat "__$cat_org"

			# Adjus list of harcoded shotcuts
			set hardcoded {}
			foreach key [lindex $block 2] {
				lappend hardcoded [simplify_key_seq $key]
			}

			# Create category node
			$treeWidget insert end root $cat	\
				-selectable 1			\
				-data $hardcoded		\
				-text [mc [lindex $block 1]]	\
				-fill {#0000FF}			\
				-font $node_font_b

			## Create item node
			set block	[lreplace $block 0 2]	;# Item definitions
			set len		[llength $block]	;# Length of data block

			# Iterate over item definitions
			for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {

				# Local variables
				set item	[lindex $block $i]		;# Item ID
				set image	[lindex $block [list $j 2]]	;# Image ID or {}
				set text	[mc [lindex $block [list $j 3]]];# Item text
				set txt_len	[string length $text]		;# Item text length

				# Adjust text width
				append text [string repeat "\t" [expr {4 - ($txt_len / 8)}]]

				# Determinate text to show in the node
				set text_and_key $text
				append text_and_key [simplify_key_seq $local_DB($cat_org:$item)]

				# Determinate image ID
				if {$image != {}} {
					set image "::ICONS::16::$image"
				} else {
					set image $empty_image
				}

				# Adjust key combination
				set key_seq [regsub {Key(Press|Release)?\-} $local_DB($cat_org:$item) {}]

				# Create node in the tree widget
				$treeWidget insert end $cat $item		\
					-selectable 1				\
					-font $node_font			\
					-text $text_and_key			\
					-data [list				\
						$text				\
						[lindex $block [list $j 0]]	\
						$key_seq			\
					]	\
					-image $image -padx 25
			}
		}

		## Create widgets of bottom label frame
		 # Label and entry "Current"
		grid [label $bottom_labelframe.current_label	\
			-text [mc "Current shortcut:"]		\
		] -row 0 -column 0 -sticky w
		set current_entry [ttk::entry $bottom_labelframe.current_entry		\
			-validatecommand {::configDialogues::shortcuts::cur_entry_val %P}	\
		]
		grid $current_entry -row 0 -column 1
		bind $current_entry <KeyPress>			\
			{::configDialogues::shortcuts::current_entry_key %K;		break}
		bind $current_entry <Control-KeyPress>		\
			{::configDialogues::shortcuts::current_entry_key Ctrl+%K;		break}
		bind $current_entry <Alt-KeyPress>		\
			{::configDialogues::shortcuts::current_entry_key Alt+%K;		break}
		bind $current_entry <Control-Alt-KeyPress>	\
			{::configDialogues::shortcuts::current_entry_key Ctrl+Alt+%K;	break}
		set clear_button [ttk::button $bottom_labelframe.clear_button	\
			-image ::ICONS::16::clear_left				\
			-state disabled						\
			-style Flat.TButton					\
			-command {::configDialogues::shortcuts::clear_current}	\
		]
		DynamicHelp::add $bottom_labelframe.clear_button -text [mc "Clear"]
		grid $clear_button -row 0 -column 2 -sticky w

			# Label and entry "Default"
		grid [label $bottom_labelframe.default_label	\
			-text [mc "Default:"]			\
		] -row 1 -column 0 -sticky w
		set default_entry [ttk::label $bottom_labelframe.default_entry		\
			-style Shortcuts_Default.TLabel					\
		]
		grid $default_entry -row 1 -column 1 -sticky we
		set default_button [ttk::button $bottom_labelframe.default_button	\
			-image ::ICONS::16::up0						\
			-state disabled							\
			-command {::configDialogues::shortcuts::to_default}		\
			-style Flat.TButton						\
		]
		DynamicHelp::add $bottom_labelframe.default_button -text [mc "Restore default"]
		grid $default_button -row 1 -column 2 -sticky w

		# Button "Accept"
		set accept_button [ttk::button $bottom_labelframe.accept_button	\
			-command {::configDialogues::shortcuts::accept_current}	\
			-text [mc "Accept"]					\
			-compound left						\
			-image ::ICONS::16::ok					\
			-state disabled						\
		]
		DynamicHelp::add $bottom_labelframe.accept_button -text [mc "Accept new shortcut"]
		grid $accept_button -row 0 -column 4 -rowspan 2
		# Button "Original"
		set discard_button [ttk::button $bottom_labelframe.discard_button	\
			-command {::configDialogues::shortcuts::discard_current}	\
			-text [mc "Original"]					\
			-compound left						\
			-image ::ICONS::16::button_cancel			\
			-state disabled						\
		]
		DynamicHelp::add $bottom_labelframe.discard_button -text [mc "Discard new shortcut"]
		grid $discard_button -row 0 -column 5 -rowspan 2

		# Create status label
		set status_label [label $bottom_labelframe.status_label		\
			-fg {#DD0000} -anchor w -text {}			\
		]
		grid $status_label -row 2 -column 0 -columnspan 6 -sticky w

		# Create empty space on column 3
		grid columnconfigure $bottom_labelframe 3 -minsize 70


		## Button frame at the bottom
		set but_frame [frame $win.button_frame]
		 # Button "Reset"
		pack [ttk::button $but_frame.but_default		\
			-text [mc "Defaults"]				\
			-command {::configDialogues::shortcuts::DEFAULTS}	\
		] -side left
		DynamicHelp::add $but_frame.but_default -text [mc "Reset all settings to defaults"]
		 # Button "Ok"
		pack [ttk::button $but_frame.but_ok			\
			-text [mc "Ok"]					\
			-compound left					\
			-image ::ICONS::16::ok				\
			-command {::configDialogues::shortcuts::OK}	\
		] -side right -padx 2
		DynamicHelp::add $but_frame.but_ok -text [mc "Commit new settings"]
			# Button "Cancel"
		pack [ttk::button $but_frame.but_cancel			\
			-text [mc "Cancel"]				\
			-compound left					\
			-image ::ICONS::16::button_cancel		\
			-command {::configDialogues::shortcuts::CANCEL}	\
		] -side right -padx 2
		DynamicHelp::add $but_frame.but_cancel -text [mc "Take changes back and close dialog"]

		# Pack frames
		pack $win.header_label -side top -pady 6
		pack $top_labelframe -side top -fill both -expand 1 -padx 10
		pack $bottom_labelframe -side top -fill x -padx 10 -pady 10 -after $top_labelframe
		pack $but_frame -side bottom -fill x -padx 10 -pady 5

		# Set window attributes
		wm iconphoto $win ::ICONS::16::configure
		wm transient $win .
		wm title $win [mc "Configure shortcuts - %s" ${::APPNAME}]
		wm minsize $win 600 520
		raise $win
		catch {grab $win}
		wm protocol $win WM_DELETE_WINDOW {
			::configDialogues::shortcuts::CANCEL
		}
		tkwait window $win
	}

	## Argument of parameter '-selectcommand' for the tree widget
	 # @parm Widget widget	- Source tree widget
	 # @parm List nodes	- Selected nodes
	 # @return void
	proc item_selected {widget nodes} {
		variable current_entry_font	;# Font for entry "Current shortcut"
		variable node_font		;# Normal font for tree widget nodes
		variable search_entry		;# ID of entry widget on search panel
		variable search_in_P		;# Bool: search in progress
		variable discard_button		;# ID of button "Discard"
		variable accept_button		;# ID of button "Accept"
		variable default_entry		;# ID of label containging default key shortcut
		variable bottom_lf_label	;# ID of label for bottom label frame
		variable default_button		;# ID of button "Restore default" (bottom label frame)
		variable clear_button		;# ID of button "Clear"
		variable current_entry		;# ID of entry "Current shortcut"
		variable empty_image		;# Empty image
		variable status_label		;# ID of status label
		variable changed		;# Bool: Settings changed
		variable currentNode		;# ID of the currently selected tree node

		# Empty selection -> disable widgets on the bottom frame and return
		if {$nodes == {}} {
			# Save last changed item
			if {$changed} {
				current_item_changed
			}

			# Clear and disable componets of the bottom frame
			$current_entry	delete 0 end
			cur_entry_val {}
			$default_entry	configure -text {}
			$status_label	configure -text {}
			$current_entry	configure -state disabled
			$default_button	configure -state disabled
			$accept_button	configure -state disabled
			$discard_button	configure -state disabled
			$bottom_lf_label configure -text [mc "<Nothing selected>"] -image $empty_image
			return
		}

		# Only one node can be selected
		set node [lindex $nodes end]
		if {[llength $nodes] > 1} {
			foreach nd [lreplace $nodes end end] {
				$widget selection remove $nd
			}
			return
		}

		# Clear status label, search entry and ask for saving the last change
		$status_label configure -text {}
		if {!$search_in_P} {
			$search_entry delete 0 end
			if {$changed} {
				current_item_changed
			}
		}

		# If the selected node is a toplevel one -> open its node
		if {[regexp {^__} $node]} {
			$widget toggle $node
			$widget selection clear
			return
		}

		if {$currentNode != {}} {
			$widget itemconfigure $currentNode -font $node_font
		}
		$widget itemconfigure $node -font $current_entry_font

		# Set the current node
		set currentNode	$node

		# Adjust bottom frame
		set data	[$widget itemcget $node -data]
		$bottom_lf_label configure			\
			-image [$widget itemcget $node -image]	\
			-text [string trimright [lindex $data 0]]
		$current_entry configure -state normal
		$current_entry delete 0 end
		$current_entry insert end [simplify_key_seq [lindex $data 2]]
		cur_entry_val [simplify_key_seq [lindex $data 2]]
		$default_entry	configure -text [simplify_key_seq [lindex $data 1]]
		$default_button	configure -state normal
		ena_dis__accept_discard 0
	}

	## Binding for X-Key event for entry "Custom shortcut" (see proc. 'mkDialog')
	 # @parm String key_seq - human readable key combination string
	 # @return void
	proc current_entry_key {key_seq} {
		variable current_entry	;# ID of entry "Current shortcut"
		variable status_label	;# ID of status label
		variable changed	;# Bool: Settings changed
		variable treeWidget	;# ID of the tree widget
		variable currentNode	;# ID of the currently selected tree node
		variable root_hard_cd	;# List of hadrcoded shortcuts (main window only)

		if {$currentNode == {}} {
			return
		}

		# Clear entry "Custom shortcut"
		$current_entry delete 0 end
		cur_entry_val {}

		# Adjust key combination
		set lastchar [string index $key_seq end]
		if {[string index $key_seq end-1] == {+}} {
			if {[string is lower -strict $lastchar]} {
				set key_seq [string replace $key_seq	\
					end end [string toupper $lastchar]]
			} else {
				set key_seq [string replace $key_seq end end	\
					"Shift+[string toupper $lastchar]"]
			}
		}

		# Check for validity of the given shortcut and set flag "changed"
		set changed 0
		if {![regexp {^(Ctrl|Alt)\+} $key_seq] && ![regexp {^F\d\d?$} $key_seq]} {
			$status_label configure -text [mc "Modifier required (Control or Alt)"]
		} elseif {[lsearch $root_hard_cd $key_seq] != -1} {
			$status_label configure -text	\
				[mc "This combination is hard-coded in the main window, so it cannot be used"]
		} elseif {[lsearch [$treeWidget itemcget [$treeWidget parent $currentNode] -data] $key_seq] != -1} {
			$status_label configure -text	\
				[mc "This combination is hard-coded, so it cannot be used"]
		} else {
			set changed 1
		}
		if {!$changed} {
			$current_entry insert end $key_seq
			cur_entry_val $key_seq
			ena_dis__accept_discard 0
			return
		}

		# Change content of entry "Custom shortcut"
		$current_entry insert end $key_seq
		cur_entry_val $key_seq

		# Check if the given combination is not already assigned to something
		set name [lindex [key_seq_to_name	\
			[extend_key_seq $key_seq]	\
			[$treeWidget parent $currentNode]] 1]
		if {$name != {} && $name != [string trim [lindex [$treeWidget itemcget $currentNode -data] 0]]} {
			$status_label configure -text	\
				[mc "The '%s' key combination has already been assigned to \"%s\"." $key_seq $name]
		} else {
			$status_label configure -text {}
		}

		# Enable buttons "Accept" and "Original" (but only if user is not trying to redefine a shortcut with the same key combination)
		if {$name != [string trim [lindex [$treeWidget itemcget $currentNode -data] 0]]} {
			ena_dis__accept_discard 1
		}
	}

	## Clear entry "Custom shortcut"
	 # @return void
	proc clear_current {} {
		variable changed		;# Bool: Settings changed
		variable anything_modified	;# Bool: Settings changed (stay set to 1 even after APPLY)
		variable current_entry		;# ID of entry "Current shortcut"
		variable status_label		;# ID of status label

		# Adjust flag "Anything modified"
		if {[$current_entry get] != {}} {
			set anything_modified 1
		}
		# Clear the entry widget and status label
		$current_entry delete 0 end
		cur_entry_val {}
		$status_label configure -text {}
		# Enable buttons "Accept" and "Original"
		ena_dis__accept_discard 1
		# Set flag "Changed"
		set changed 1
	}

	## Validate content of entry "Current shortcut"
	 # @parm String content - content of entry "Current shortcut"
	 # @return Bool - always 1
	proc cur_entry_val {content} {
		variable clear_button	;# ID of button "Clear"

		# Enable/Disable button "Clear"
		if {$content == {}} {
			$clear_button configure -state disabled
		} else {
			$clear_button configure -state normal
		}

		return 1
	}

	## Set current shortcut to default
	 # @return void
	proc to_default {} {
		variable treeWidget		;# ID of the tree widget
		variable changed		;# Bool: Settings changed
		variable currentNode		;# ID of the currently selected tree node
		variable anything_modified	;# Bool: Settings changed (stay set to 1 even after APPLY)
		variable current_entry		;# ID of entry "Current shortcut"
		variable default_entry		;# ID of label containging default key shortcut
		variable status_label		;# ID of status label

		# Se flag "Anything modified"
		if {[$current_entry get] != [$default_entry cget -text]} {
			set anything_modified 1
		}

		# Adjust content of entry "Current shortcut"
		set key [$default_entry cget -text]
		$current_entry delete 0 end
		$current_entry insert 0 $key
		cur_entry_val $key

		# Check if the new setting is unique
		set name [lindex [key_seq_to_name	\
			[extend_key_seq $key ]		\
			[$treeWidget parent $currentNode]] 1]
		if {$name != {}} {
			$status_label configure -text	\
				[mc "The '%s' key combination has already been assigned to \"%s\"." $key $name]
		}

		# Enable buttons "Accept" and "Original"
		ena_dis__accept_discard 1
		set changed 1
	}

	## Accept new key combination fot the currently selected action
	 # @return void
	proc accept_current {} {
		variable changed		;# Bool: Settings changed
		variable treeWidget		;# ID of the tree widget
		variable current_entry		;# ID of entry "Current shortcut"
		variable currentNode		;# ID of the currently selected tree node
		variable anything_modified	;# Bool: Settings changed (stay set to 1 even after APPLY)
		variable local_DB		;# Local database of shortcuts
		variable status_label		;# ID of status label

		# Gain details about the current action
		set data	[$treeWidget itemcget $currentNode -data]
		set parent	[$treeWidget parent $currentNode]
		set category	[string replace $parent 0 1]
		set text_org	[lindex $data 0]
		set default	[lindex $data 1]
		set current	[extend_key_seq [$current_entry get]]
		set text	$text_org
		append text	[$current_entry get]

		## Redefine shortcut for action which have the same shortcut as the current one
		$treeWidget itemconfigure $currentNode -data {}
		set defined [key_seq_to_name $current $parent]
		 # Redefine
		if {$defined != {}} {
			$status_label configure -text	\
				[mc "Removing key combination for action \"%s\"" [lindex $defined 1]]
			set defined [lindex $defined 0]
			set cat [string replace [$treeWidget parent $defined] 0 1]
			set local_DB($cat:$defined) {}
			set dt [$treeWidget itemcget $defined -data]
			set txt [lindex $dt 0]
			set dt [lindex $dt 1]
			$treeWidget itemconfigure $defined	\
				-text $txt			\
				-data [list $txt $dt {}]
		 # Keep
		} else {
			$status_label configure -text {}
		}

		# Adjust local database and the tree widget
		set local_DB($category:$currentNode) $current
		$treeWidget itemconfigure $currentNode	\
			-text $text			\
			-data [list $text_org $default $current]

		# Adjust modifed flags and disable buttons "Accept" and "Original"
		set changed 0
		set anything_modified 1
		ena_dis__accept_discard 0
	}

	## Discard new key combination fot the currently selected action
	 # @return void
	proc discard_current {} {
		variable changed		;# Bool: Settings changed
		variable treeWidget		;# ID of the tree widget
		variable current_entry		;# ID of entry "Current shortcut"
		variable status_label		;# ID of status label
		variable currentNode		;# ID of the currently selected tree node
		variable anything_modified	;# Bool: Settings changed (stay set to 1 even after APPLY)

		# Restore previous content of entry "Current shortcut"
		$current_entry delete 0 end
		$current_entry insert end [simplify_key_seq	\
			[lindex [$treeWidget itemcget $currentNode -data] 2]]
		cur_entry_val [$current_entry get]

		# Clear status label
		$status_label configure -text {}

		# Disable buttons "Accept" and "Original"
		ena_dis__accept_discard 0
		set changed 0
	}

	## Ask user about saving the last change and conditionly save it
	 # @return void
	proc current_item_changed {} {
		variable changed	;# Bool: Settings changed
		variable currentNode	;# ID of the currently selected tree node
		variable win		;# ID of toplevel dialog window

		set changed 0
		if {[tk_messageBox		\
			-type yesno		\
			-parent $win		\
			-icon question		\
			-title [mc "Item changed"]	\
			-message [mc "The previous item was modified. Do you want to save it ?"] \
			] != {yes}
		} then {
			return
		}

		accept_current
	}

	## Translate key combination acceptable by Tk to "human readable" representation
	 # @parm String key_seq - Human readable representation of a key combination
	 # @return String - Key combination acceptable by Tk
	proc extend_key_seq {key_seq} {
		if {$key_seq == {}} {
			return {}
		}

		regsub -all {\+} $key_seq {-} key_seq
		regsub {Ctrl\-} $key_seq {Control-} key_seq
		set last_char [string index $key_seq end]
		if {![string compare {Shift-} [string range $key_seq {end-6} {end-1}]]} {
			set last_char [string toupper $last_char]
			set key_seq [string range $key_seq 0 {end-7}]
			append key_seq $last_char
		} elseif {[string index $key_seq {end-1}] == {-}} {
			set key_seq [string replace $key_seq end end [string tolower $last_char]]
		}

		return $key_seq
	}

	## Find name of action specified by the given key combination
	 # @parm String key_seq		- Key combination acceptable by Tk
	 # @parm String parent_node	- Parent node (category)
	 # @return String - Action name or {}
	proc key_seq_to_name {key_seq parent_node} {
		variable treeWidget		;# ID of the tree widget

		if {$key_seq == {}} {
			return {}
		}

		# Search the tree widget
		foreach node [$treeWidget nodes $parent_node] {
			if {![string compare $key_seq				\
				[lindex [$treeWidget itemcget $node -data] 2]]}	\
			{
				return	[list $node		\
					[string trimright	\
						[lindex [$treeWidget itemcget $node -data] 0]]]
			}
		}

		return {}
	}

	## Enable/Disable buttons "Discard" and "Accept"
	 # @parm Bool ena_dis - Enable/Disable (1 == enable; 0 == disable)
	 # @return void
	proc ena_dis__accept_discard {ena_dis} {
		variable discard_button	;# ID of button "Discard"
		variable accept_button	;# ID of button "Accept"

		if {$ena_dis} {
			$discard_button configure -state normal
			$accept_button configure -state normal
		} else {
			$discard_button configure -state disabled
			$accept_button configure -state disabled
		}
	}

	## Search the given string in the tree widget
	 # @parm String string - string to find
	 # @return Bool - always 1
	proc search {string} {
		variable search_entry	;# ID of entry widget on search panel
		variable search_clear	;# ID of button "Clear search entry"
		variable treeWidget	;# ID of the tree widget
		variable search_in_P	;# Bool: search in progress
		variable changed	;# Bool: Settings changed

		# Empty input string
		if {$string == {}} {
			$search_clear configure -state disabled
			$search_entry configure -style TEntry
			return 1
		}
		$search_clear configure -state normal

		# String to lowercase
		set string [string tolower $string]

		# Search all nodes
		foreach top [$treeWidget nodes root] {
			foreach node [$treeWidget nodes $top] {
				set text [$treeWidget itemcget $node -text]
				set text [string tolower $text]

				# String found
				if {[string first $string $text] != -1} {
					# Select the node
					set search_in_P 1
					$treeWidget opentree [$treeWidget parent $node]
					$treeWidget selection set $node
					$treeWidget see $node

					# Adjust entry widget and return
					set search_in_P 0
					$search_entry configure -style StringFound.TEntry
					return 1
				}
			}
		}

		# String not found
		$search_entry configure -style StringNotFound.TEntry
		return 1
	}

	## Retrieve settings related to this dialog from the program
	 # @return void
	proc getSettings {} {
		variable local_DB	;# Local database of shortcuts

		foreach key [array names ::SHORTCUTS_DB] {
			set local_DB($key) $::SHORTCUTS_DB($key)
		}
	}

	## Change content of configuration variables
	 # @return void
	proc use_settings {} {
		variable local_DB	;# Local database of shortcuts

		foreach key [array names local_DB] {
			set ::SHORTCUTS_DB($key) $local_DB($key)
		}
	}

	## Adjust application to fit new settings
	 # @return Bool - result
	proc apply_settings {} {
		# Adjust main window
		shortcuts_reevaluate
		mainmenu_redraw

		# Adjust projects
		foreach project ${::X::openedProjects} {

			# Adjust editors
			foreach editor [$project cget -editors] {
				$editor shortcuts_reevaluate
				$editor makePopupMenu
			}

			# Adjust right panel
			$project rightPanel_makePopupMenu
			$project rightPanel_watch_shortcuts_reevaluate
			# Adjust to do list
			$project TodoProc_makePopupMenu
			$project TodoProc_shortcuts_reevaluate
			# Adjust messages text
			$project messages_text_makePopupMenu
			$project messages_text_shortcuts_reevaluate
			# Adjust filelist
			$project filelist_makePopupMenu
			$project filelist_fsb_makePopupMenu
		}

		# Restore previous state of menu items (enabled / disabled)
		::X::disaena_menu_toolbar_for_current_project
	}

	## Save configuration to config file
	 # @return void
	proc save_config {} {
		variable local_DB	;# Local database of shortcuts

		foreach key [array names local_DB] {
			::settings setValue "Shortcuts/$key" $local_DB($key)
		}

		# Commit
		::settings saveConfig
	}

	## Load configuratin from config file
	 # @return void
	proc load_config {} {
		array unset ::SHORTCUTS_DB
		foreach block ${::SHORTCUTS_LIST} {
			set category	[lindex $block 0]	;# Shortcut category (eg. 'edit')
			set block	[lreplace $block 0 2]	;# Item definitions
			set len		[llength $block]	;# Length of data block

			# Iterate over data block and redefine local database
			for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
				set key [lindex $block $i]	;# Item name

				set ::SHORTCUTS_DB($category:$key)			\
					[::settings getValue "Shortcuts/$category:$key"	\
					[lindex $block [list $j 0]]]
			}
		}
	}

	## Destroy the dialog
	 # @return void
	proc CANCEL {} {
		variable win		;# ID of toplevel dialog window
		variable local_DB	;# Local database of shortcuts
		variable dialog_opened	;# Bool: True if this dialog is already opened
		variable root_hard_cd	;# List of hadrcoded shortcuts (main window only)

		# Discard local database of shortcuts
		array unset local_DB
		unset root_hard_cd

		# Destroy dialog window
		set dialog_opened 0
		grab release $win
		destroy $win
	}

	## Use settings and destroy the dialog
	 # @return void
	proc OK {} {
		variable win			;# ID of toplevel dialog window
		variable changed		;# Bool: Settings changed
		variable anything_modified	;# Bool: Settings changed (stay set to 1 even after APPLY)

		# Save last changed item
		if {$changed} {
			current_item_changed
		}

		# Use and save settings
		if {$anything_modified} {
			use_settings
			apply_settings
			save_config
		}

		# Destroy the dialog window
		CANCEL
	}

	## Restrore defaults
	 # @return void
	proc DEFAULTS {} {
		variable local_DB		;# Local database of shortcuts
		variable treeWidget		;# ID of the tree widget
		variable win			;# ID of toplevel dialog window
		variable changed		;# Bool: Settings changed
		variable anything_modified	;# Bool: Settings changed (stay set to 1 even after APPLY)

		# Ask user
		if {[tk_messageBox			\
			-parent $win			\
			-type yesno			\
			-title [mc "Confirmation required"]	\
			-icon question			\
			-message [mc "This will discard all shortcut settings and replace them with defaults. Are you sure by that ?"]\
			] != {yes}
		} then {
			return
		}

		# Adjust flags
		set changed 0		;# Last item modified --> NO
		set anything_modified 1	;# Any item modified --> YES

		# Reset local database of shortcuts
		array unset local_DB
		foreach block ${::SHORTCUTS_LIST} {
			set category	[lindex $block 0]	;# Shortcut category (eg. 'edit')
			set block	[lreplace $block 0 2]	;# Item definitions
			set len		[llength $block]	;# Length of data block

			# Redefine local database
			for {set i 0; set j 1} {$i < $len} {incr i 2; incr j 2} {
				set key [lindex $block $i]
				set local_DB($category:$key) [lindex $block [list $j 0]]
			}
		}

		## Refresh content of the tree widget
		$treeWidget selection clear
		# Iterate over toplevel items
		foreach top [$treeWidget nodes root] {
			set cat [string replace $top 0 1]	;# Shortcut category (eg. 'edit')

			# Iterate over lowlevel items
			foreach node [$treeWidget nodes $top] {
				# Long key sequence (for Tk)
				set key_seq [regsub {Key(Press|Release)?\-} $local_DB($cat:$node) {}]

				# Determinate new item data
				set data [$treeWidget itemcget $node -data]
				lset data 2 $key_seq

				# Determinate item text
				set text_and_key [lindex $data 0]
				append text_and_key [simplify_key_seq $key_seq]

				# Adjust item
				$treeWidget itemconfigure $node	\
					-data $data		\
					-text $text_and_key
			}
		}
	}
}

# >>> File inclusion guard
}
# <<< File inclusion guard