arcadia 0.12.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. data/README +25 -14
  2. data/conf/LC/en-UK.LANG +3 -1
  3. data/conf/arcadia.conf +10 -0
  4. data/conf/arcadia.res.rb +29 -1
  5. data/ext/ae-editor/ae-editor.rb +239 -48
  6. data/ext/ae-file-history/ae-file-history.conf +11 -1
  7. data/ext/ae-file-history/ae-file-history.rb +120 -2
  8. data/ext/ae-ruby-debug/ae-ruby-debug.rb +6 -5
  9. data/ext/ae-subprocess-inspector/ae-subprocess-inspector.rb +7 -3
  10. data/ext/ae-term/ae-term.rb +1 -1
  11. data/lib/a-commons.rb +72 -56
  12. data/lib/a-contracts.rb +23 -1
  13. data/lib/a-core.rb +136 -41
  14. data/lib/a-tkcommons.rb +127 -36
  15. data/tcl/fsdialog/fsdialog.tcl +2 -2
  16. data/tcl/ptwidgets-1.1.0/COPYRIGHT +10 -0
  17. data/tcl/ptwidgets-1.1.0/ChangeLog +194 -0
  18. data/tcl/ptwidgets-1.1.0/README +50 -0
  19. data/tcl/ptwidgets-1.1.0/common/stacktrace.tcl +29 -0
  20. data/tcl/ptwidgets-1.1.0/common/tokenframe.tcl +200 -0
  21. data/tcl/ptwidgets-1.1.0/doc/img/toggleswitch_off.png +0 -0
  22. data/tcl/ptwidgets-1.1.0/doc/img/toggleswitch_on.png +0 -0
  23. data/tcl/ptwidgets-1.1.0/doc/img/tokenentry.png +0 -0
  24. data/tcl/ptwidgets-1.1.0/doc/img/tokensearch_popup_example.png +0 -0
  25. data/tcl/ptwidgets-1.1.0/doc/img/tokensearch_popup_example2.png +0 -0
  26. data/tcl/ptwidgets-1.1.0/doc/img/wmarkentry.png +0 -0
  27. data/tcl/ptwidgets-1.1.0/doc/toggleswitch.html +402 -0
  28. data/tcl/ptwidgets-1.1.0/doc/tokenentry.html +1366 -0
  29. data/tcl/ptwidgets-1.1.0/doc/tokensearch.html +1549 -0
  30. data/tcl/ptwidgets-1.1.0/doc/wmarkentry.html +634 -0
  31. data/tcl/ptwidgets-1.1.0/library/toggleswitch.tcl +432 -0
  32. data/tcl/ptwidgets-1.1.0/library/tokenentry.tcl +2208 -0
  33. data/tcl/ptwidgets-1.1.0/library/tokensearch.tcl +2488 -0
  34. data/tcl/ptwidgets-1.1.0/library/wmarkentry.tcl +630 -0
  35. data/tcl/ptwidgets-1.1.0/pkgIndex.tcl +10 -0
  36. data/tcl/ptwidgets-1.1.0/test/Makefile +3 -0
  37. data/tcl/ptwidgets-1.1.0/test/run.tcl +3 -0
  38. data/tcl/ptwidgets-1.1.0/test/test.tcl +89 -0
  39. data/tcl/ptwidgets-1.1.0/test/toggleswitch.test +562 -0
  40. data/tcl/ptwidgets-1.1.0/test/tokenentry.test +1023 -0
  41. data/tcl/ptwidgets-1.1.0/test/tokensearch.test +1023 -0
  42. data/tcl/ptwidgets-1.1.0/test/wmarkentry.test +1325 -0
  43. data/tcl/themes/altTheme.tcl +101 -0
  44. data/tcl/themes/aquaTheme.tcl +59 -0
  45. data/tcl/themes/clamTheme.tcl +140 -0
  46. data/tcl/themes/classicTheme.tcl +108 -0
  47. data/tcl/themes/pkgIndex.tcl +3 -0
  48. data/tcl/themes/ttk.tcl +176 -0
  49. data/tcl/themes/vistaTheme.tcl +224 -0
  50. data/tcl/themes/winTheme.tcl +80 -0
  51. data/tcl/themes/xpTheme.tcl +65 -0
  52. data/tcl/tkfbox/folder.gif +0 -0
  53. data/tcl/tkfbox/textfile.gif +0 -0
  54. data/tcl/tkfbox/tkfbox.tcl +1 -0
  55. data/tcl/tkfbox/tkfbox.tcl~ +1 -0
  56. data/tcl/tkfbox/updir.xbm +1 -0
  57. metadata +43 -2
@@ -0,0 +1,2488 @@
1
+ #===============================================================
2
+ # Main tokensearch package module
3
+ #
4
+ # Copyright (c) 2011-2012 Trevor Williams (phase1geo@gmail.com)
5
+ #===============================================================
6
+
7
+ package provide tokensearch 1.0
8
+
9
+ source [file join [tokensearch::DIR] common tokenframe.tcl]
10
+
11
+ namespace eval tokensearch {
12
+
13
+ array set token_index {}
14
+ array set active_token {}
15
+ array set options {}
16
+ array set dont_tokenize {}
17
+ array set old_focus {}
18
+ array set old_grab {}
19
+ array set dropdown_token {}
20
+ array set images {}
21
+ array set pressed_token {}
22
+ array set token_count {}
23
+ array set token_shapes {}
24
+ array set categoryopt_vars {}
25
+ array set edit_info {}
26
+ array set dont_deselect {}
27
+ array set state {}
28
+
29
+ array set text_options {
30
+ -background 1
31
+ -bg 1
32
+ -borderwidth 1
33
+ -bd 1
34
+ -exportselection 1
35
+ -font 1
36
+ -foreground 1
37
+ -fg 1
38
+ -highlightbackground 1
39
+ -highlightcolor 1
40
+ -highlightthickness 1
41
+ -insertbackground 1
42
+ -insertborderwidth 1
43
+ -insertofftime 1
44
+ -insertontime 1
45
+ -insertwidth 1
46
+ -padx 1
47
+ -pady 1
48
+ -relief 1
49
+ -selectbackground 1
50
+ -selectborderwidth 1
51
+ -selectforeground 1
52
+ -setgrid 1
53
+ -state 1
54
+ -takefocus 1
55
+ -xscrollcommand 1
56
+ -yscrollcommand 1
57
+ -autoseparators 1
58
+ }
59
+
60
+ array set widget_options {
61
+ -autoseparators {autoSeparators AutoSeparators}
62
+ -background {background Background}
63
+ -bg -background
64
+ -borderwidth {borderWidth BorderWidth}
65
+ -bd -borderwidth
66
+ -categories {categories Categories}
67
+ -categorybd {categoryBorderWidth CategoryBorderWidth}
68
+ -categorybg {categoryBackground CategoryBackground}
69
+ -categorycursor {categoryCursor Cursor}
70
+ -categoryfont {categoryFont CategoryFont}
71
+ -categoryopts {categoryOpts CategoryOpts}
72
+ -categoryrelief {categoryRelief CategoryRelief}
73
+ -dropdownheight {dropDownHeight DropDownHeight}
74
+ -dropdownmaxheight {dropDownMaxHeight DropDownMaxHeight}
75
+ -exportselection {exportSelection ExportSelection}
76
+ -font {font Font}
77
+ -foreground {foreground Foreground}
78
+ -fg -foreground
79
+ -height {height Height}
80
+ -highlightbackground {highlightBackground HighlightBackground}
81
+ -highlightcolor {highlightColor HighlightColor}
82
+ -highlightthickness {highlightThickness HighlightThickness}
83
+ -historyvar {historyVar HistoryVar}
84
+ -insertbackground {insertBackground InsertBackground}
85
+ -insertborderwidth {insertBorderWidth InsertBorderWidth}
86
+ -insertofftime {insertOffTime InsertOffTime}
87
+ -insertontime {insertOnTime InsertOnTime}
88
+ -insertwidth {insertWidth InsertWidth}
89
+ -matchcase {matchCase MatchCase}
90
+ -matchmode {matchMode MatchMode}
91
+ -padx {padX Pad}
92
+ -pady {padY Pad}
93
+ -relief {relief Relief}
94
+ -selectbackground {selectBackground Background}
95
+ -selectborderwidth {selectBorderWidth BorderWidth}
96
+ -selectforeground {selectForeground Foreground}
97
+ -setgrid {setGrid SetGrid}
98
+ -state {state State}
99
+ -takefocus {takeFocus TakeFocus}
100
+ -tokenbg {tokenBackground TokenBackground}
101
+ -tokenbordercolor {tokenBorderColor TokenBorderColor}
102
+ -tokenfg {tokenForeground TokenForeground}
103
+ -tokenselectbg {tokenSelectBackground TokenSelectBackground}
104
+ -tokenselectbordercolor {tokenSelectBorderColor TokenSelectBorderColor}
105
+ -tokenselectfg {tokenSelectForeground TokenSelectForeground}
106
+ -tokenshape {tokenShape TokenShape}
107
+ -tokenvar {tokenVar TokenVar}
108
+ -watermark {watermark Watermark}
109
+ -watermarkforeground {watermarkForeground Foreground}
110
+ -width {width Width}
111
+ -wrap {wrap Wrap}
112
+ -xscrollcommand {xScrollCommand ScrollCommand}
113
+ -yscrollcommand {yScrollCommand ScrollCommand}
114
+ }
115
+
116
+ variable img_arrow
117
+ variable img_blank
118
+
119
+ set img_arrow [image create photo -data "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"]
120
+ set img_blank [image create photo -data "R0lGODlhBwAHAIAAAP///wAAACH5BAkKAAEAIf8 LSUNDUkdCRzEwMTL/AAAYHGFwcGwCEAAAbW50clJHQiBYWVogB9sACAAQABUAOgAzYWNzcEFQUEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1hcHBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARZGVzYwAAAVAAAABiZHNjbQAAAbQAAAEgY3BydAAAAtQAAAAjd3RwdAAAAvgAAAAUclhZWgAAAwwAAAAUZ1hZWgAAAyAAAAAUYlhZWgAAAzQAAAAUclRSQwAAA0gAAAgMYWFyZwAAC1QAAAAgdmNndAAAC3QAAAYSbmRp/24AABGIAAAGPmNoYWQAABfIAAAALG1tb2QAABf0AAAAKGJUUkMAAANIAAAIDGdUUkMAAANIAAAIDGFhYmcAAAtUAAAAIGFhZ2cAAAtUAAAAIGRlc2MAAAAAAAAACERpc3BsYXkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtbHVjAAAAAAAAABYAAAAMcHRCUgAAAAgAAAEYaXRJVAAAAAgAAAEYaHVIVQAAAAgAAAEYemhUVwAAAAgAAAEYbmJOTwAAAAgAAP8BGGNzQ1oAAAAIAAABGGtvS1IAAAAIAAABGGRlREUAAAAIAAABGHN2U0UAAAAIAAABGHpoQ04AAAAIAAABGGphSlAAAAAIAAABGGFyAAAAAAAIAAABGHB0UFQAAAAIAAABGG5sTkwAAAAIAAABGGZyRlIAAAAIAAABGGVzRVMAAAAIAAABGHRyVFIAAAAIAAABGGZpRkkAAAAIAAABGHBsUEwAAAAIAAABGHJ1UlUAAAAIAAABGGVuVVMAAAAIAAABGGRhREsAAAAIAAABGABpAE0AYQBjdGV4dAAAAABDb3B5cmlnaHQgQXBwbGUsIEluYy4sIDIwMTEAWFlaIAD/AAAAAADzUgABAAAAARbPWFlaIAAAAAAAAHgYAAA/7gAAAixYWVogAAAAAAAAWl4AAKwHAAAUMVhZWiAAAAAAAAAkYAAAFAsAALzPY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAoAC0AMgA2ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAKMAqACtALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEyATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHh/wHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCP/7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEKJwo9ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwqDEMMXAx1DI4MpwzADNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg+WD7MPzw/sEAkQJhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMjE0MTYxODE6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxayFtb/FvoXHRdBF2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR+UH78f6iAVIEEgbCCYIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQklOCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2K2krnSvRLAUsOSxuLKIs/9ctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmv9L4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJUj1TbVShVdVXCVg9WXFapVvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc1l0nXXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1mkmboZz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw4HE6cZVx8HJLcqZzAXNdc7h0FHT/cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2hfgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuHn4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLjk02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd0p5Anq6fHZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adu/6fgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5v8N5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c/23//3BhcmEAAAAAAAMAAAACZmYAAPKnAAANWQAAE9AAAAoOdmNndAAAAAAAAAAAAAMBAAACAAAAVgEUAWUB3gJHArcDOwPSBIEFQQYHBuMHygjGCcIKywvfDQIOHw9KEHgRqRLdFBMVQBZ5F68Y3BoJGzAcSx1eHlUfRyA3ISoiHSMYJBslFiYXJxkoISkpKjArNiw/LUcuTy9VMFUxWDJaM1f/NFQ1UjZFN0U4SzlYOmQ7azx2PXs+fz+CQIJBgEJ+Q3lEcUVoRltHTUg/STBKH0sPS/xM603eTtxP5VDtUfNS+lQBVQZWClcOWBFZFFoYWxxcI10rXjNfPWBLYVliZ2N6ZIlliWaFZ4FofGl6anxrfGx8bYBuhW+McJVxoHKwc8J01XXtdwh4Ink9elJ7W3xefWR+a397gIeBmIKrg76E0YXjhvKIA4kSih6LKYwwjTSONo87kFKRaZKEk5uUspXDltOX45jtmfebAJwGnQqeC58OoA6hC6ILow6kHaU4plSncKiJqaOquqvPrOat/a8UsCyxRLJds3i0lLWzttS3//C497nquti7yry5vaq+m7+PwIXBfcJ4w3XEdcV2xnvHgciLyZnKnsuWzInNf855z3XQc9Fy0nXTeNR71X3Wftd92HrZdtpv22PcW91e3mnfcuB74YHig+OD5ILlfeZ252zoYOlS6kTrNuwm7RfuC+8W8CPxLvI480L0SPVN9lD3UvhS+VL6U/tU/FX9Wf5d/0X//wAAACsAxAEtAYIB9QJaAtEDXQQBBLAFbwY/ByIIDwkFCg4LHQwzDVgOgQ+tENwSDRNAFHQVphbWGAEZJRpBG1McXB1NHjcfHyAKIPkh7CLkI9kk0CXKJsgnxyjGKcQqwivCLMEtvS62L7Ewqv8xnjKSM4Y0dzVsNmg3aThqOWc6aDtkPF09WD5NP0NAN0EpQhlDBkPyRN1Fx0axR5xIhUlsSlZLQEw8TT9OQE9AUEJRQlJAUz5UOlU3VjNXL1gtWSpaKVsoXCtdMF42XztgRWFJYj1jLGQbZQtl/WbwZ+No2GnPashrw2y/bb5uwW/GcMtx1nLkc/J0/3YIdwZ4AHj8eft6/3wFfQ1+GH8lgDKBPoJJg1aEYIVnhm6HcYhziXGKcIuIjJqNso7Gj9qQ6ZH2kwKUC5USlhiXHpggmSCaIpsinB+dH54inzGgTKFmooKjmqSypcmm3afyqQiqHaszrEmtYK54r5KwrrH/yrLjs+u04LXRtsa3uriuuaS6nLuYvJa9l76bv6LAqcG5wsXD18TtxfvG/cf5yPbJ/MsCzArNFc4izzHQQdFQ0l3TatR11X/WhteJ2I3Zp9rG2+jdAt4f3zfgTOFh4nPjgeSN5Znmoues6LbpvurH69btAO4u71rwhPGv8tbz+/Ue9kD3YPiA+aH6wPvi/Qf+Kv81//8AAAAOAEEAoAEbAY4CGQKhA0QEAQS8BYYGYgdNCDsJOwpBC04MYA13DpIPsRDNEekTCRQiFS8WQBdRGFIZThpGGzccKx0XHgIe8h/mINoh0iLII70ksiWpJp8nlSiKKX4qbitdLEktMi4Y/y77L94wvjGcMnozWTQ7NR82BDbnN8k4qzmLOmo7RjwjPPs91D6rP4BAVEElQfhCy0OfRHJFQ0YZRu5Hy0iwSZRKeUteTENNJ04LTu9P01C2UZtSgVNnVFBVOVYlVxRYAljyWeJazVuwXItdZ15CXyFgA2DmYcxis2OfZIxlfWZxZ2hoYmlfal9rYmxmbWlubW9tcGxxbXJxc3t0hnWVdqZ3uXjNed5673wAfRB+HX8ogC+BNII2gziEQ4VNhlmHYohpiW2KbottjGqNZI5bj1GQQ5E0kiWTE5QAlO+V4Zbbl9yY4JnjmuWb5pzmneSe45/ioOOh5KLmo+mk7qX1pv/+qAipD6oMqwCr76zjrdWuya+/sLixtrK2s7u0wrXNttm37Lj+uhS7Lrw+vT++O783wDfBOcI9w0LESMVPxlbHW8heyV7KXctZzFPNSs5Fz0/QY9F50o3TodSx1b7WzdfY2ODZ5trs2+/c8t323vjf++ED4ibjSeRl5X7mmOe26NnqCOtK7KHuEu+h8W7zevXk+OP8w///AABuZGluAAAAAAAABjYAAKNnAABYMQAATJEAAJ0OAAAk6gAAEoIAAFANAABUOQACLhQAAgzMAAHMzAADAQAAAgAAAAEACAAVACMAMQBBAFEAYgBzAIYAmQCtAMEA1wDtAQQBHAE1AU//AWoBhwGkAcIB4gIEAicCTAJ0Ap0CzgMCAzkDcQOrA+UEHwRdBJsE2wUbBV0FoQXnBi4GdwbCBw8HYAeyCAYIXgi4CRMJdQnUCjMKkQrxC1ULuQwhDIwM+Q1pDd0OUg7LD0gPxxBLENIRWxHnEncTCBOfFDQUyxVYFeYWeBcMF6EYORjVGXIaEhq1G1kb/xynHU8d+R6lH1Ef/SCrIVsiCiK8I3skQSUIJdMmnidoKDYpBinVKqUrdixILRst6y68L48wYTExMgMy1zOtNIo1dDZkN1M4RDkuOh87DTv8POw93j7TP81AyUHDQshDzETXRehG/EgWSSxKLks5TEFN/09OX092UJJRrlLTU/tVJ1ZWV4tYx1oEW0Nci13VXxxgYmGOYsBj8WUkZl1nl2jWahlrXWyibepvMnB9cclzFXRida92+3hHeZd6/3yOfi1/x4FogwqErYZOh+2JjYsqjMWOX4/7kZCTKZS8lk2X8Zmwm3adOZ71oLOibKQrpeKnnqlcqyCs6a64sIuyZrRJtjm4Grniu6u9fr9RwS3DFcUBxvHI7crxzP7PENEq00PVZteK2bHbpN2W343hiuOI5Y7nnemw68ft5fAL8i30U/Z++KL6yvz0//8AAAACAAwAGwAqADoASwBcAG4AgQCUAKgAvQDSAOgA/wEXATABSv8BZQGBAZ4BvQHdAf8CIwJJAnICnQLPAwUDPgN4A7MD7wQsBGwErQTvBTIFdwW+BgcGUgaeBu0HPweUB+kIQwigCP4JYQnECicKiQrtC1ULvQwpDJkNCg2ADfgOcw7xD3MP+RCCEQ4RnRIuEsITWxP0FJAVIhWzFkcW3hd2GBEYsBlRGfUamxtEG+8cmx1KHfkeqx9cIA4gwiF4Ii0i6SO0JIUlWSYuJwMn2ii0KY4qaCtDLB8s/C3XLrIvkDBsMUYyIjMBM+I0zDXENr03tTisOaE6mDuOPIM9ej5zP3BAcEFvQnRDfkSKRZ1GtEfQSO9J80sBTAtNHE4uT0ZQZVH/g1KrU9RVA1Y0V2lYplnlWyNca121XvtgRGFxYqNj1mUJZkNnfmi9agFrR2yNbddvIXBucb1zDHRcdax2/HhNeaF7C3yYfjF/xYFfgvuEloYvh8WJW4rujH+ODo+gkSaStpQ+lcKXUJj3mqucY54Nn7mhZKMOpLamXagGqa+rX60SrsmwhLJGtA214LeuuVK6/byjvljACcHFw4nFTccXyOvKw8ykzoXQb9JY1ETWOdgq2hLb0N2L30rhEOLV5J/mcOhG6h/r/e3e78jxrvOV9YT3b/lW+0P9MP//AAAABgAQAB0AKgA5AEkAWQBrAH0AkACkALkAzwDmAP4BFwEy/wFOAWsBigGsAc8B8wIbAkYCcwKkAtYDDANEA30DtwPzBDAEcASyBPYFOwWDBc0GGQZpBrsHEQdqB8cIJwiKCPIJXAnJCjcKpgsXC4wMBAx/DP4NgQ4HDpIPIA+zEEoQ5hGEEiQSyBNxFBkUxRVoFg4WthdhGA4YvxlyGika4hueHFsdGx3bHp0fXyAiIOghriJ4I0wkLyUUJfwm4yfKKLIpmyqCK2osUS03Lh0vAi/nMMwxsDKWM340aTVZNkw3QDgzOSM6FTsFO/U85T3XPsw/xUDAQbtCvUPBRMtF3EbvSApJJEo1S01MZE2BTqJPylD2UihTX1SbVd9XJlh2Wf/KWyBcf13gXz9gl2HmYzJkgWXUZytohWnla0Zsqm4Pb3Vw3XJEc651FnZ9d+V5UHrIfFR98X+HgSSCv4RahfOHhokZiqeMM429j0eQypJRk9WVU5bWmHWaKZvinZafSaD8oq2kYaYUp8qpg6tBrQiu1LCmsoC0YbZNuCG53buVvVG/EMDUwqDEcsZEyB/KAcvpzdTPx9G907TVsNeu2a3bd91A3xTg9uLa5LvmmOhw6jjr7u2P7xzwlvH/81b0h/Wp9rr3tPil+Xn6Rvr++6f8UPzb/WL96f6I/0T//wAAc2YzMgAAAAAAAQxCAAAF3v//8yYAAAeSAAD9kf//+6I0///9owAAA9wAAMBsbW1vZAAAAAAAAAYQAACcbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAAAAcABwAAAgaMj6nLjQUAOw=="]
121
+
122
+ ###########################################################################
123
+ # Main procedure which creates the given window and initializes it.
124
+ proc tokensearch {w args} {
125
+
126
+ variable token_index
127
+ variable options
128
+ variable dont_tokenize
129
+ variable dont_deselect
130
+ variable active_token
131
+ variable pressed_token
132
+ variable token_count
133
+ variable widget_options
134
+ variable dropdown_token
135
+ variable state
136
+
137
+ # Create the widget frame
138
+ frame $w -class TokenSearch -takefocus 0
139
+
140
+ # Initially, we pack the frame with an entry widget
141
+ text $w.txt -highlightthickness 0 -relief flat -bg white -spacing1 2 -spacing2 2 -spacing3 2 -takefocus 1
142
+
143
+ # Pack the text widget
144
+ pack $w.txt -side left -fill both -expand yes
145
+
146
+ # Create the category menu
147
+ menu $w.mnu -tearoff 0
148
+
149
+ # Create the popup window that might be used by this widget
150
+ toplevel $w.top
151
+ listbox $w.top.list -selectmode browse -background white -yscrollcommand "$w.top.vsb set" -exportselection 0 -borderwidth 0 -cursor top_left_arrow
152
+ ttk::scrollbar $w.top.vsb -command "$w.top.list yview"
153
+
154
+ pack $w.top.list -side left -fill both -expand y
155
+
156
+ # Handle the popup
157
+ wm overrideredirect $w.top 1
158
+ wm transient $w.top [winfo toplevel $w]
159
+ wm group $w.top [winfo parent $w]
160
+ wm withdraw $w.top
161
+
162
+ # Initialize default options
163
+ if {[array size token_index] == 0} {
164
+ foreach opt [array names widget_options] {
165
+ if {![catch "$w.txt configure $opt" rc]} {
166
+ if {[llength $widget_options($opt)] != 1} {
167
+ if {$opt eq "-wrap"} {
168
+ set default_value 0
169
+ } elseif {$opt eq "-height"} {
170
+ set default_value 1
171
+ } elseif {$opt eq "-background"} {
172
+ set default_value "white"
173
+ } elseif {$opt eq "-relief"} {
174
+ set default_value "ridge"
175
+ } else {
176
+ set default_value [lindex $rc 4]
177
+ }
178
+ option add *TokenSearch.[lindex $rc 1] $default_value widgetDefault
179
+ }
180
+ }
181
+ }
182
+ option add *TokenSearch.tokenForeground [list "white" "black"] widgetDefault
183
+ option add *TokenSearch.tokenBackground [list "dark blue" "light blue"] widgetDefault
184
+ option add *TokenSearch.tokenBorderColor [list "dark blue" "light blue"] widgetDefault
185
+ option add *TokenSearch.tokenSelectForeground "white" widgetDefault
186
+ option add *TokenSearch.tokenSelectBackground "blue" widgetDefault
187
+ option add *TokenSearch.tokenSelectBorderColor "blue" widgetDefault
188
+ option add *TokenSearch.dropDownHeight 0 widgetDefault
189
+ option add *TokenSearch.dropDownMaxHeight 5 widgetDefault
190
+ option add *TokenSearch.matchMode glob widgetDefault
191
+ option add *TokenSearch.matchCase 0 widgetDefault
192
+ option add *TokenSearch.historyVar "" widgetDefault
193
+ option add *TokenSearch.tokenVar "" widgetDefault
194
+ option add *TokenSearch.tokenShape pill widgetDefault
195
+ option add *TokenSearch.dropDownFormatString "%s" widgetDefault
196
+ option add *TokenSearch.categories [list {Categories Name}] widgetDefault
197
+ option add *TokenSearch.categoryBackground white widgetDefault
198
+ option add *TokenSearch.categoryRelief groove widgetDefault
199
+ option add *TokenSearch.categoryBorderWidth 1 widgetDefault
200
+ option add *TokenSearch.categoryFont [font create -size 8] widgetDefault
201
+ option add *TokenSearch.categoryCursor "" widgetDefault
202
+ option add *TokenSearch.watermark "" widgetDefault
203
+ option add *TokenSearch.watermarkForeground "light gray" widgetDefault
204
+ }
205
+
206
+ # Initialize variables
207
+ set token_index($w) 0
208
+ set active_token($w) ""
209
+ set dont_tokenize($w) 0
210
+ set dropdown_token($w) ""
211
+ set pressed_token($w) ""
212
+ set token_count($w) 0
213
+ set dont_deselect($w) 0
214
+ set state($w) "unknown"
215
+
216
+ # Initialize the options array
217
+ foreach opt [array names widget_options] {
218
+ set options($w,$opt) [option get $w [lindex $widget_options($opt) 0] [lindex $widget_options($opt) 1]]
219
+ }
220
+
221
+ # Setup bindings
222
+ bind $w.txt <FocusOut> "set tokensearch::dont_tokenize($w) 0; tokensearch::tokenize $w"
223
+ bind $w.txt <Return> "tokensearch::key_return $w; break"
224
+ bind $w.txt <Tab> "tokensearch::focus_next $w; break"
225
+ bind $w.txt <Left> {
226
+ tokensearch::key_left_right [winfo parent %W] left
227
+ if {[tokensearch::handle_text_movement [winfo parent %W]]} {
228
+ break
229
+ }
230
+ }
231
+ bind $w.txt <Right> {
232
+ tokensearch::key_left_right [winfo parent %W] right
233
+ if {[tokensearch::handle_text_movement [winfo parent %W]]} {
234
+ break
235
+ }
236
+ }
237
+ bind $w.txt <Down> {
238
+ tokensearch::key_down [winfo parent %W]
239
+ if {[tokensearch::handle_text_movement [winfo parent %W]]} {
240
+ break
241
+ }
242
+ }
243
+ bind $w.txt <Up> {
244
+ tokensearch::key_up [winfo parent %W]
245
+ if {[tokensearch::handle_text_movement [winfo parent %W]]} {
246
+ break
247
+ }
248
+ }
249
+ bind $w.txt <Escape> "tokensearch::close_dropdown $w"
250
+ bind $w.txt <Button-1> {
251
+ tokensearch::close_dropdown [winfo parent %W]
252
+ if {[tokensearch::handle_text_movement [winfo parent %W]]} {
253
+ break
254
+ }
255
+ }
256
+ bind $w.txt <B1-Motion> {
257
+ if {[tokensearch::handle_text_movement [winfo parent %W]]} {
258
+ break
259
+ }
260
+ }
261
+ bind $w.txt <B1-Leave> {
262
+ if {[tokensearch::handle_text_movement [winfo parent %W]]} {
263
+ break
264
+ }
265
+ }
266
+ bind $w.txt <Any-KeyPress> "tokensearch::keypress $w"
267
+ bind $w.top.list <Motion> "tokensearch::motion_dropdown $w %x %y"
268
+ bind $w.top.list <Button-1> "tokensearch::key_return $w; focus $w.txt"
269
+ bind $w.txt <<Modified>> "tokensearch::modified $w"
270
+ bind $w.txt <<Selection>> "tokensearch::handle_selection_change $w"
271
+ bind $w.txt <Destroy> "tokensearch::handle_destroy $w"
272
+ if {[tk windowingsystem] eq "aqua"} {
273
+ bind $w.txt <Command-x> "tokensearch::handle_cut $w"
274
+ bind $w.txt <Command-c> "tokensearch::handle_copy $w"
275
+ bind $w.txt <Command-v> "tokensearch::handle_paste $w"
276
+ } else {
277
+ bind $w.txt <Control-x> "tokensearch::handle_cut $w"
278
+ bind $w.txt <Control-c> "tokensearch::handle_copy $w"
279
+ bind $w.txt <Control-v> "tokensearch::handle_paste $w"
280
+ }
281
+
282
+ # Configure the widget
283
+ eval "configure 1 $w $args"
284
+
285
+ # Rename and alias the tokensearch window
286
+ rename ::$w $w
287
+ interp alias {} ::$w {} tokensearch::widget_cmd $w
288
+
289
+ return $w
290
+
291
+ }
292
+
293
+ ###########################################################################
294
+ # This procedure is called when the widget is destroyed.
295
+ proc handle_destroy {w} {
296
+
297
+ variable images
298
+
299
+ # Delete the images
300
+ foreach {key value} [array get images $w,*] {
301
+ image delete $value
302
+ }
303
+
304
+ # Delete the image array
305
+ array unset images $w,*
306
+
307
+ }
308
+
309
+ ###########################################################################
310
+ # Changes focus to the next window after w.
311
+ proc focus_next {w} {
312
+
313
+ # Change the focus
314
+ focus [tk_focusNext $w.txt]
315
+
316
+ }
317
+
318
+ ###########################################################################
319
+ # This procedure is called when the text widget is modified.
320
+ proc modified {w} {
321
+
322
+ variable token_count
323
+ variable options
324
+ variable state
325
+
326
+ if {[$w.txt edit modified]} {
327
+
328
+ set last_value [$w.txt get {insert - 1 chars} insert]
329
+
330
+ if {($last_value eq "\n") || ($last_value eq "\t")} {
331
+ $w.txt delete {insert - 1 chars} insert
332
+ handle_state $w 1
333
+ }
334
+
335
+ # Reset the modified flag
336
+ $w.txt edit modified false
337
+
338
+ # Generate the TokenSearchModified event if our token count has changed
339
+ set tokens [llength [$w.txt window names]]
340
+ if {$token_count($w) != $tokens} {
341
+ set token_count($w) $tokens
342
+ if {$options($w,-tokenvar) ne ""} {
343
+ upvar #0 $options($w,-tokenvar) var
344
+ set var [get_tokens $w]
345
+ }
346
+ event generate $w <<TokenSearchModified>>
347
+ }
348
+
349
+ }
350
+
351
+ }
352
+
353
+ ###########################################################################
354
+ # If the selection of the text box changes, make sure that any selected
355
+ # tokens are updated appropriately.
356
+ proc handle_selection_change {w} {
357
+
358
+ # Don't allow the selection to contain tokens
359
+ foreach token [$w.txt window names] {
360
+ if {[lsearch [$w.txt tag names $token] sel] != -1} {
361
+ $w.txt tag remove sel $token
362
+ }
363
+ }
364
+
365
+ }
366
+
367
+ ###########################################################################
368
+ # Validation command.
369
+ proc validate {w str} {
370
+
371
+ variable options
372
+
373
+ if {$str eq ","} {
374
+ return 0
375
+ } elseif {$options($w,-validatecommand) ne ""} {
376
+ return [eval $options($w,-validatecommand) $str]
377
+ } else {
378
+ return 1
379
+ }
380
+
381
+ }
382
+
383
+ ###########################################################################
384
+ # Handles a left or right arrow key event.
385
+ proc key_left_right {w dir {token ""}} {
386
+
387
+ variable options
388
+ variable active_token
389
+
390
+ if {$token eq ""} {
391
+
392
+ # Don't do anything if the current insertion cursor is the beginning or end
393
+ if {(([$w.txt index insert] ne "1.0") || ($dir eq "right")) && \
394
+ (([$w.txt index insert] ne [$w.txt index end]) || ($dir eq "left"))} {
395
+
396
+ # Get the current insertion index
397
+ if {$dir eq "left"} {
398
+ set index [$w.txt index "insert - 1 chars"]
399
+ } else {
400
+ set index [$w.txt index insert]
401
+ }
402
+
403
+ # If a token exists at the given index, select it.
404
+ foreach token [$w.txt window names] {
405
+ if {[$w.txt index $token] eq $index} {
406
+ reverse_token $w $token
407
+ set active_token($w) $index
408
+ focus $token
409
+ return
410
+ }
411
+ }
412
+
413
+ }
414
+
415
+ } else {
416
+
417
+ # Clear the active token
418
+ set active_token($w) ""
419
+
420
+ # Deselect the token
421
+ reverse_token $w $token
422
+
423
+ # Close the dropdown listbox if it is opened
424
+ close_dropdown $w
425
+
426
+ # If the direction was a positive direction, increase the insertion cursor by one character
427
+ if {($dir eq "right") && ([$w.txt index $token] eq [$w.txt index insert])} {
428
+ $w.txt mark set insert "insert + 1 chars"
429
+ }
430
+
431
+ # Get the text entry field the focus
432
+ focus $w.txt
433
+
434
+ }
435
+
436
+ }
437
+
438
+ ###########################################################################
439
+ # This procedure is invoked when the user hits the down key when the text
440
+ # has the focus.
441
+ proc key_down {w {token ""}} {
442
+
443
+ if {[winfo ismapped $w.top]} {
444
+ tk::ListboxUpDown $w.top.list 1
445
+ return -code break
446
+ } elseif {$token ne ""} {
447
+ display_category_menu $w $token
448
+ }
449
+
450
+ }
451
+
452
+ ###########################################################################
453
+ # This procedure is invoked when the user hits the shift-down key combination
454
+ # when the token has the focus. This invokes the history drop-down.
455
+ proc key_shift_down {w token} {
456
+
457
+ # Dislay the dropdown item list
458
+ display_dropdown_items $w $token
459
+
460
+ }
461
+
462
+ ###########################################################################
463
+ # This procedure is invoked when the user hits the up key when the text
464
+ # has the focus.
465
+ proc key_up {w {token ""}} {
466
+
467
+ if {[winfo ismapped $w.top]} {
468
+ tk::ListboxUpDown $w.top.list -1
469
+ return -code break
470
+ } elseif {$token ne ""} {
471
+ close_dropdown $w
472
+ }
473
+
474
+ }
475
+
476
+ ###########################################################################
477
+ # This procedure is invoked when the user hits the return key when the
478
+ # text has the focus.
479
+ proc key_return {w {token ""}} {
480
+
481
+ variable dropdown_token
482
+ variable options
483
+ variable dont_tokenize
484
+
485
+ # Allow the tokenization to occur
486
+ set dont_tokenize($w) 0
487
+
488
+ # If the dropdown window is shown, get the currently selected text and insert it into the textbox.
489
+ if {[winfo ismapped $w.top]} {
490
+
491
+ # Get the currently selected value
492
+ set value [$w.top.list get [$w.top.list curselection]]
493
+
494
+ # Figure out the position of the first character of text
495
+ set curr_index 1.0
496
+ set end_index [$w.txt index end]
497
+ while {($curr_index != $end_index) && ([$w.txt get $curr_index] eq "")} {
498
+ set curr_index [$w.txt index "$curr_index + 1 chars"]
499
+ }
500
+
501
+ # If the result is associated with a token, change the token text
502
+ if {$dropdown_token($w) ne ""} {
503
+ $dropdown_token($w).val.l1 configure -text $value
504
+ redraw_token $w $dropdown_token($w) 1
505
+ if {$options($w,-tokenvar) ne ""} {
506
+ upvar #0 $options($w,-tokenvar) var
507
+ set var [get_tokens $w]
508
+ }
509
+ event generate $w <<TokenSearchModified>>
510
+
511
+ # Otherwise, remove the current text and replace it with the given value
512
+ } else {
513
+ $w.txt delete $curr_index "$curr_index + [expr [string length $value] + 1] chars"
514
+ $w.txt insert $curr_index $value
515
+ tokenize $w
516
+ }
517
+
518
+ # Close the dropbox
519
+ close_dropdown $w
520
+
521
+ # If this return was hit for a token, detokenize the current token to make it editable
522
+ } elseif {$token ne ""} {
523
+
524
+ detokenize $w $token
525
+
526
+ } else {
527
+
528
+ # Tokenize the text
529
+ tokenize $w
530
+
531
+ }
532
+
533
+ }
534
+
535
+ ###########################################################################
536
+ # This procedure is called whenever the escape key is pressed when a token
537
+ # has the focus. This will cause the dropdown listbox to be closed if
538
+ # it is currently opened.
539
+ proc key_escape {w token} {
540
+
541
+ # Just close the dropdown listbox
542
+ close_dropdown $w
543
+
544
+ }
545
+
546
+ ###########################################################################
547
+ # This procedure is called whenever the user presses a key in the text box.
548
+ proc keypress {w} {
549
+
550
+ # Update the current state
551
+ handle_state $w 1
552
+
553
+ after idle [list tokensearch::handle_entry_key $w]
554
+
555
+ # Clear the listbox selection so that it's obvious what will happen if the user
556
+ # presses return.
557
+ $w.top.list see 0
558
+ $w.top.list selection clear 0 end
559
+ $w.top.list selection anchor 0
560
+ $w.top.list activate 0
561
+
562
+ }
563
+
564
+ ###########################################################################
565
+ # Populates and shows the listbox with the matching values. If there are no
566
+ # matching values, the listbox is closed.
567
+ proc handle_entry_key {w} {
568
+
569
+ variable options
570
+ variable dont_tokenize
571
+
572
+ # Handle the current state
573
+ handle_state $w 1
574
+
575
+ # Make sure that we don't tokenize
576
+ set dont_tokenize($w) 1
577
+
578
+ # Get rid of any whitespace from around the value
579
+ set value [string trim [$w.txt get 1.0 end]]
580
+
581
+ # Clear the listbox
582
+ $w.top.list delete 0 end
583
+
584
+ # Populate the listbox with matching values
585
+ if {$value ne ""} {
586
+ if {$options($w,-historyvar) ne ""} {
587
+ upvar #0 $options($w,-historyvar) history
588
+ set cmdargs [list]
589
+ switch $options($w,-matchmode) {
590
+ glob {
591
+ lappend cmdargs "-glob"
592
+ set matchval "*$value*"
593
+ }
594
+ regexp {
595
+ lappend cmdargs "-regexp"
596
+ set matchval ".*$value.*"
597
+ }
598
+ default {
599
+ lappend cmdargs "-glob"
600
+ set matchval "*$value*"
601
+ }
602
+ }
603
+ if {!$options($w,-matchcase)} {
604
+ lappend cmdargs "-nocase"
605
+ }
606
+ lappend cmdargs "-all" "-inline"
607
+ foreach value [eval "lsearch $cmdargs {$history} {$matchval}"] {
608
+ $w.top.list insert end $value
609
+ }
610
+ }
611
+ }
612
+
613
+ # If the listbox is not empty, show it
614
+ if {[$w.top.list size] > 0} {
615
+ open_dropdown $w
616
+ $w.top.list activate 0
617
+ $w.top.list selection set 0
618
+
619
+ } else {
620
+ close_dropdown $w
621
+ }
622
+
623
+ }
624
+
625
+ ###########################################################################
626
+ # Handles any sort of movement of the insertion cursor or selection within
627
+ # the text widget.
628
+ proc handle_text_movement {w} {
629
+
630
+ variable state
631
+
632
+ # If we are empty, always set the insertion cursor to 1.0
633
+ if {$state($w) eq "empty"} {
634
+ $w.txt mark set insert 1.0
635
+ $w.txt tag remove sel 1.0 end
636
+ focus $w.txt
637
+ return 1
638
+ }
639
+
640
+ return 0
641
+
642
+ }
643
+
644
+ ###########################################################################
645
+ # Handles a Control-x binding on the given widget.
646
+ proc handle_cut {w} {
647
+
648
+ if {[focus] eq $w} {
649
+ set select [$w.txt tag ranges sel]
650
+ if {[llength $select] == 0} {
651
+ clipboard clear
652
+ clipboard append [$w.txt get 1.0 end]
653
+ # TBD - Need to delete only text
654
+ eval "$w.txt delete 1.0 end"
655
+ handle_state $w 1
656
+ } else {
657
+ clipboard clear
658
+ clipboard append [eval "$w.txt get $select"]
659
+ eval "$w.txt delete $select"
660
+ handle_state $w 1
661
+ }
662
+ } else {
663
+ clipboard clear
664
+ clipboard append [[focus].l1 cget -text]
665
+ eval "tokendelete $w $select"
666
+ }
667
+
668
+ }
669
+
670
+ ###########################################################################
671
+ # Handles a Control-c binding on the given widget.
672
+ proc handle_copy {w} {
673
+
674
+ if {[focus] eq $w} {
675
+ set select [$w.txt tag ranges sel]
676
+ if {[llength $select] == 0} {
677
+ clipboard clear
678
+ clipboard append [$w.txt get 1.0 end]
679
+ } else {
680
+ clipboard clear
681
+ clipboard append [eval "$w.txt get $select"]
682
+ }
683
+ } else {
684
+ clipboard clear
685
+ clipboard append [[focus].l1 cget -text]
686
+ }
687
+
688
+ }
689
+
690
+ ###########################################################################
691
+ # Handles a Control-v binding on the given widget.
692
+ proc handle_paste {w} {
693
+
694
+ # Handle the current state
695
+ handle_state $w 1
696
+
697
+ # Insert the clipboard text
698
+ $w.txt insert insert [clipboard get]
699
+
700
+ # Close the drop-down listbox
701
+ close_dropdown $w
702
+
703
+ }
704
+
705
+ ###########################################################################
706
+ # Redraws the given token.
707
+ proc redraw_token {w token resize} {
708
+
709
+ variable options
710
+ variable images
711
+ variable token_shapes
712
+
713
+ # Get the border color from the token
714
+ set cat_usebc [$token.cat.l2.top cget -bg]
715
+ set val_usebc [$token.val.l2.top cget -bg]
716
+ set txt_bg [$w.txt cget -background]
717
+
718
+ # Figure out the width and height of the token text label
719
+ if {$resize} {
720
+ update idletasks
721
+ }
722
+ set l1_cat_width [winfo reqwidth $token.cat.l1]
723
+ set l1_val_width [winfo reqwidth $token.val.l1]
724
+ set l1_height [winfo reqheight $token.cat.l1]
725
+
726
+ # Get the needed shapes
727
+ set shape_left [lindex $token_shapes($token) 0]
728
+ set shape_right [lindex $token_shapes($token) end]
729
+
730
+ # Create the token images, if necessary
731
+ if {![info exists images($w,left,$l1_height,$cat_usebc,$txt_bg,$shape_left)]} {
732
+ set images($w,left,$l1_height,$cat_usebc,$txt_bg,$shape_left) [image create bitmap -data [eval "tokenframe::create_left $shape_left $l1_height"] -maskdata [eval "tokenframe::create_left_mask $shape_left $l1_height"] -foreground $cat_usebc -background $txt_bg]
733
+ }
734
+ if {![info exists images($w,cat_edge,$cat_usebc)]} {
735
+ set images($w,cat_edge,$cat_usebc) [image create bitmap -data "#define edge_width 7\n#define edge_height 2\nstatic char edge_bits\[\] = {\n0x7f, 0x7f};" -foreground $cat_usebc]
736
+ }
737
+ if {![info exists images($w,val_edge,$val_usebc)]} {
738
+ set images($w,val_edge,$val_usebc) [image create bitmap -data "#define edge_width 7\n#define edge_height 2\nstatic char edge_bits\[\] = {\n0x7f, 0x7f};" -foreground $val_usebc]
739
+ }
740
+ if {![info exists images($w,cat_middle,$l1_cat_width,$l1_height,$cat_usebc)]} {
741
+ set images($w,cat_middle,$l1_cat_width,$l1_height,$cat_usebc) [image create bitmap -data [tokenframe::create_middle $l1_cat_width $l1_height] -foreground $cat_usebc]
742
+ }
743
+ if {![info exists images($w,val_middle,$l1_val_width,$l1_height,$val_usebc)]} {
744
+ set images($w,val_middle,$l1_val_width,$l1_height,$val_usebc) [image create bitmap -data [tokenframe::create_middle $l1_val_width $l1_height] -foreground $val_usebc]
745
+ }
746
+ if {![info exists images($w,$l1_height,$val_usebc,$txt_bg,$shape_right)]} {
747
+ set images($w,right,$l1_height,$val_usebc,$txt_bg,$shape_right) [image create bitmap -data [eval "tokenframe::create_right $shape_right $l1_height"] -maskdata [eval "tokenframe::create_right_mask $shape_right $l1_height"] -foreground $val_usebc -background $txt_bg]
748
+ }
749
+
750
+ # Configure the label images
751
+ $token.ll configure -padx 0 -pady 0 -compound center -image $images($w,left,$l1_height,$cat_usebc,$txt_bg,$shape_left)
752
+ $token.cat.l1 configure -padx 0 -pady 0 -compound center -image $images($w,cat_middle,$l1_cat_width,$l1_height,$cat_usebc)
753
+ $token.cat.l2.top configure -padx 0 -pady 0 -compound center -image $images($w,cat_edge,$cat_usebc)
754
+ $token.cat.l2.bot configure -padx 0 -pady 0 -compound center -image $images($w,cat_edge,$cat_usebc)
755
+ $token.val.l1 configure -padx 0 -pady 0 -compound center -image $images($w,val_middle,$l1_val_width,$l1_height,$val_usebc)
756
+ $token.val.l2.top configure -padx 0 -pady 0 -compound center -image $images($w,val_edge,$val_usebc)
757
+ $token.val.l2.bot configure -padx 0 -pady 0 -compound center -image $images($w,val_edge,$val_usebc)
758
+ $token.lr configure -padx 0 -pady 0 -compound center -image $images($w,right,$l1_height,$val_usebc,$txt_bg,$shape_right)
759
+
760
+ }
761
+
762
+ ###########################################################################
763
+ # Reverses the color scheme of the given token.
764
+ proc reverse_token {w token} {
765
+
766
+ # Get the current colors
767
+ set a_cat_bg [$token.cat.l1 cget -bg]
768
+ set a_cat_fg [$token.cat.l1 cget -fg]
769
+ set a_cat_bc [$token.cat.l2.top cget -bg]
770
+ set b_cat_bg [$token.cat.l2.top cget -fg]
771
+ set b_cat_fg [$token.cat.l2.mid cget -fg]
772
+ set b_cat_bc [$token.cat.l2.bot cget -fg]
773
+
774
+ set a_val_bg [$token.val.l1 cget -bg]
775
+ set a_val_fg [$token.val.l1 cget -fg]
776
+ set a_val_bc [$token.val.l2.top cget -bg]
777
+ set b_val_bg [$token.val.l2.top cget -fg]
778
+ set b_val_fg [$token.val.l2.mid cget -fg]
779
+ set b_val_bc [$token.val.l2.bot cget -fg]
780
+
781
+ # Reverse the color schemes
782
+ $token.ll configure -bg $b_cat_bg
783
+ $token.cat configure -bg $b_cat_bg
784
+ $token.cat.l1 configure -bg $b_cat_bg -fg $b_cat_fg
785
+ $token.cat.l2.top configure -bg $b_cat_bc -fg $a_cat_bg
786
+ $token.cat.l2.mid configure -bg $b_cat_bg -fg $a_cat_fg
787
+ $token.cat.l2.bot configure -bg $b_cat_bc -fg $a_cat_bc
788
+ $token.val configure -bg $b_val_bg
789
+ $token.val.l1 configure -bg $b_val_bg -fg $b_val_fg
790
+ $token.val.l2.top configure -bg $b_val_bc -fg $a_val_bg
791
+ $token.val.l2.mid configure -bg $b_val_bg -fg $a_val_fg
792
+ $token.val.l2.bot configure -bg $b_val_bc -fg $a_val_bc
793
+ $token.lr configure -bg $b_val_bg
794
+
795
+ # Redraw the token
796
+ redraw_token $w $token 0
797
+
798
+ }
799
+
800
+ ###########################################################################
801
+ # Creates a token and inserts it into the textbox.
802
+ proc create_token {w index fg bg bordercolor selectfg selectbg selectbordercolor value} {
803
+
804
+ variable options
805
+ variable token_index
806
+ variable img_blank
807
+ variable token_shapes
808
+
809
+ # Get the first category in the categories list
810
+ set category [lindex $options($w,-categories) 0 1 0]
811
+
812
+ # Add the token (store the "store" colors and the select background color in unused slots)
813
+ set token [frame $w.txt.f$token_index($w) -relief flat]
814
+ set catf [frame $token.cat -bg [lindex $bg 0]]
815
+ set valf [frame $token.val -bg [lindex $bg end]]
816
+
817
+ label $token.ll -bd 0 -bg [lindex $bg 0] -fg [lindex $selectbg 0]
818
+ label $catf.l1 -bd 0 -text $category -fg [lindex $fg 0] -bg [lindex $bg 0] -font [$w.txt cget -font]
819
+ frame $catf.l2 -bg [lindex $bg 0]
820
+ label $catf.l2.top -bd 0 -bg [lindex $bordercolor 0] -fg [lindex $selectbg 0]
821
+ label $catf.l2.mid -bd 0 -bg [lindex $bg 0] -fg [lindex $selectfg 0] -image $img_blank
822
+ label $catf.l2.bot -bd 0 -bg [lindex $bordercolor 0] -fg [lindex $selectbordercolor 0]
823
+ label $valf.l1 -bd 0 -text $value -fg [lindex $fg end] -bg [lindex $bg end] -font [$w.txt cget -font]
824
+ frame $valf.l2 -bg [lindex $bg end]
825
+ label $valf.l2.top -bd 0 -bg [lindex $bordercolor end] -fg [lindex $selectbg end]
826
+ label $valf.l2.mid -bd 0 -bg [lindex $bg end] -fg [lindex $selectfg end] -image $img_blank
827
+ label $valf.l2.bot -bd 0 -bg [lindex $bordercolor end] -fg [lindex $selectbordercolor end]
828
+ label $token.lr -bd 0 -bg [lindex $bg end] -fg [lindex $selectbg end]
829
+
830
+ set token_shapes($token) $options($w,-tokenshape)
831
+
832
+ # Create the token frames
833
+ redraw_token $w $token 1
834
+
835
+ # Pack the labels
836
+ pack $catf.l2.top -anchor n
837
+ pack $catf.l2.mid -fill y -expand yes
838
+ pack $catf.l2.bot -anchor s
839
+
840
+ pack $catf.l1 -side left -padx 2
841
+ pack $catf.l2 -side left -padx 2
842
+
843
+ pack $valf.l2.top -anchor n
844
+ pack $valf.l2.mid -fill y -expand yes
845
+ pack $valf.l2.bot -anchor s
846
+
847
+ pack $valf.l1 -side left -padx 2
848
+ pack $valf.l2 -side left -padx 2
849
+
850
+ pack $token.ll -side left
851
+ pack $catf -side left
852
+ pack $valf -side left -fill both
853
+ pack $token.lr -side left
854
+
855
+ $w.txt window create $index -window $token -padx 2
856
+
857
+ # Add bindings to the new token
858
+ bind $token <FocusOut> "tokensearch::deselect_token $w $token"
859
+ bind $catf.l1 <ButtonPress-1> "tokensearch::handle_token_press $w $token %x %y"
860
+ bind $catf.l1 <Motion> "tokensearch::handle_token_drag $w %x %y"
861
+ bind $catf.l1 <ButtonRelease-1> "tokensearch::handle_token_release $w $token %x %y"
862
+ bind $catf.l2.mid <Button-1> "tokensearch::handle_cat_arrow_click $w $token %x %y"
863
+ bind $valf.l1 <ButtonPress-1> "tokensearch::handle_token_press $w $token %x %y"
864
+ bind $valf.l1 <Motion> "tokensearch::handle_token_drag $w %x %y"
865
+ bind $valf.l1 <ButtonRelease-1> "tokensearch::handle_token_release $w $token %x %y"
866
+ bind $valf.l2.mid <Button-1> "tokensearch::handle_val_arrow_click $w $token %x %y"
867
+ bind $catf <Enter> "tokensearch::handle_category_enter $w $token"
868
+ bind $valf <Enter> "tokensearch::handle_value_enter $w $token"
869
+ bind $token <Enter> "tokensearch::handle_token_enter $w $token"
870
+ bind $catf <Leave> "tokensearch::handle_category_leave $w $token"
871
+ bind $valf <Leave> "tokensearch::handle_value_leave $w $token"
872
+ bind $token <BackSpace> "tokensearch::delete_token $w $token"
873
+ bind $token <Left> "tokensearch::key_left_right $w left $token"
874
+ bind $token <Right> "tokensearch::key_left_right $w right $token"
875
+ bind $token <Down> "tokensearch::key_down $w $token"
876
+ bind $token <Shift-Down> "tokensearch::key_shift_down $w $token"
877
+ bind $token <Up> "tokensearch::key_up $w $token"
878
+ bind $token <Return> "tokensearch::key_return $w $token"
879
+ bind $token <Escape> "tokensearch::key_escape $w $token"
880
+ if {[tk windowingsystem] eq "aqua"} {
881
+ bind $token <Command-x> "tokensearch::handle_cut $w"
882
+ bind $token <Command-c> "tokensearch::handle_copy $w"
883
+ } else {
884
+ bind $token <Control-x> "tokensearch::handle_cut $w"
885
+ bind $token <Control-c> "tokensearch::handle_copy $w"
886
+ }
887
+
888
+ incr token_index($w)
889
+
890
+ return $token
891
+
892
+ }
893
+
894
+ ###########################################################################
895
+ # Returns the text window position given an index.
896
+ proc index_to_position {w index} {
897
+
898
+ set indices [list]
899
+ foreach token [$w.txt window names] {
900
+ lappend indices [$w.txt index $token]
901
+ }
902
+
903
+ return [lindex [lsort -real $indices] $index]
904
+
905
+ }
906
+
907
+ ###########################################################################
908
+ # Returns the name of the token at the given index.
909
+ proc index_to_token {w index} {
910
+
911
+ set indices [list]
912
+ foreach token [$w.txt window names] {
913
+ lappend indices [list [$w.txt index $token] $token]
914
+ }
915
+
916
+ return [lindex [lsort -real -index 0 $indices] $index 1]
917
+
918
+ }
919
+
920
+ ###########################################################################
921
+ # Returns true if the given token is currently selected; otherwise, returns
922
+ # false.
923
+ proc is_selected {token} {
924
+
925
+ if {([$token.ll cget -fg] eq [$token.cat.l1 cget -bg]) && ([$token.lr cget -fg] eq [$token.val.l1 cget -bg])} {
926
+ return 1
927
+ } else {
928
+ return 0
929
+ }
930
+
931
+ }
932
+
933
+ ###########################################################################
934
+ # Creates a token out of the given text, deletes the text.
935
+ proc tokenize {w} {
936
+
937
+ variable token_index
938
+ variable options
939
+ variable dont_tokenize
940
+ variable img_blank
941
+ variable edit_info
942
+ variable categoryopt_vars
943
+ variable state
944
+
945
+ if {$dont_tokenize($w)} {
946
+ set dont_tokenize($w) 0
947
+ return
948
+ }
949
+
950
+ # If our current state is empty, be done
951
+ if {$state($w) eq "empty"} {
952
+ return
953
+ }
954
+
955
+ # Get the current string in the entry field
956
+ set token_str [string trim [$w.txt get 1.0 end]]
957
+
958
+ # Figure out the position of the first character of text
959
+ set curr_index 1.0
960
+ set end_index [$w.txt index end]
961
+ while {($curr_index != $end_index) && ([$w.txt get $curr_index] eq "")} {
962
+ set curr_index [$w.txt index "$curr_index + 1 chars"]
963
+ }
964
+
965
+ # Create and add the token and add the token string to the history variable
966
+ if {$token_str ne ""} {
967
+ set token [create_token $w $curr_index $options($w,-tokenfg) $options($w,-tokenbg) $options($w,-tokenbordercolor) \
968
+ $options($w,-tokenselectfg) $options($w,-tokenselectbg) $options($w,-tokenselectbordercolor) $token_str]
969
+ if {$options($w,-historyvar) ne ""} {
970
+ upvar #0 $options($w,-historyvar) historyvar
971
+ if {[lsearch $historyvar $token_str] == -1} {
972
+ lappend historyvar $token_str
973
+ }
974
+ }
975
+ } else {
976
+ set token ""
977
+ }
978
+
979
+ # If we have edited this token, clear our recent buffer and populate the new
980
+ # token with the previous information.
981
+ if {[info exists edit_info($w)]} {
982
+
983
+ if {$token ne ""} {
984
+
985
+ # Set the category
986
+ $token.cat.l1 configure -text [lindex $edit_info($w) 0]
987
+
988
+ # Set the category options
989
+ set optnum 0
990
+ foreach opt [lrange $edit_info($w) 1 end] {
991
+ set categoryopt_vars($w,$token,$optnum) $opt
992
+ incr optnum
993
+ }
994
+
995
+ }
996
+
997
+ # Clear the edit information
998
+ unset edit_info($w)
999
+
1000
+ } else {
1001
+
1002
+ if {$token ne ""} {
1003
+
1004
+ # Create the categoryopt_vars for the given token
1005
+ set optnum 0
1006
+ foreach categoryopt $options($w,-categoryopts) {
1007
+ set categoryopt_vars($w,$token,$optnum) [lindex $categoryopt 2]
1008
+ incr optnum
1009
+ }
1010
+
1011
+ }
1012
+
1013
+ }
1014
+
1015
+ # Clear the text field
1016
+ $w.txt delete "$curr_index + 1 chars" "$curr_index + [expr [string length $token_str] + 1] chars"
1017
+
1018
+ # Make sure that the insertion cursor is visible
1019
+ $w.txt see 1.0
1020
+ update
1021
+ $w.txt see insert
1022
+
1023
+ # Finally, close the dropdown window if it is currently opened
1024
+ close_dropdown $w
1025
+
1026
+ return $token
1027
+
1028
+ }
1029
+
1030
+ ###########################################################################
1031
+ # Deletes the token and replaces it with the original text.
1032
+ proc detokenize {w token} {
1033
+
1034
+ variable dont_tokenize
1035
+ variable active_token
1036
+ variable edit_info
1037
+ variable categoryopt_vars
1038
+
1039
+ # Save the category and category options information to the edit_info array
1040
+ set edit_info($w) [list [$token.cat.l1 cget -text]]
1041
+ set optnum 0
1042
+ while {[info exists categoryopt_vars($w,$token,$optnum)]} {
1043
+ lappend edit_info($w) $categoryopt_vars($w,$token,$optnum)
1044
+ array unset categoryopt_vars($w,$token,$optnum)
1045
+ incr optnum
1046
+ }
1047
+
1048
+ # Change the focus to the textbox prior to deleting the token to avoid
1049
+ # having the token be tokenized immediately
1050
+ focus $w.txt
1051
+
1052
+ # Get some information from the token (position and text)
1053
+ set token_pos [$w.txt index $token]
1054
+ set token_text [$token.val.l1 cget -text]
1055
+
1056
+ # Delete the token
1057
+ $w.txt delete $token
1058
+
1059
+ # Insert the label text
1060
+ $w.txt insert $token_pos $token_text
1061
+
1062
+ # Set the selection to the inserted text
1063
+ $w.txt tag add sel $token_pos "$token_pos + [string length $token_text] chars"
1064
+
1065
+ # Set the insertion cursor to the end of the text
1066
+ $w.txt mark set insert "$token_pos + [string length $token_text] chars"
1067
+
1068
+ # Make sure that we don't tokenize this string
1069
+ set dont_tokenize($w) 1
1070
+
1071
+ # Clear the active token
1072
+ set active_token($w) ""
1073
+
1074
+ }
1075
+
1076
+ ###########################################################################
1077
+ # Removes a token from the entry field.
1078
+ proc delete_token {w token} {
1079
+
1080
+ variable options
1081
+ variable active_token
1082
+
1083
+ set last_pos ""
1084
+
1085
+ foreach token [$w.txt window names] {
1086
+ if {[$token.cat.l1 cget -bg] eq $options($w,-tokenselectbg)} {
1087
+ set last_pos [$w.txt index $token]
1088
+ $w.txt delete $token
1089
+ handle_state $w 1
1090
+ }
1091
+ }
1092
+
1093
+ # Set the insertion cursor to the end
1094
+ if {$last_pos ne ""} {
1095
+ $w.txt mark set insert $last_pos
1096
+ }
1097
+
1098
+ # Clear the active token
1099
+ set active_token($w) ""
1100
+
1101
+ # Set the focus back to the entry
1102
+ focus $w.txt
1103
+
1104
+ }
1105
+
1106
+ ###########################################################################
1107
+ # This procedure is called when the text token receives the focus. It
1108
+ # deselects any currently selected tokens.
1109
+ proc deselect_token {w token} {
1110
+
1111
+ variable options
1112
+ variable img_blank
1113
+ variable active_token
1114
+ variable dont_deselect
1115
+
1116
+ # If we are disabled, do nothing
1117
+ if {$options($w,-state) eq "disabled"} {
1118
+ return
1119
+ }
1120
+
1121
+ if {$dont_deselect($w) == 0} {
1122
+
1123
+ # If we are selected, reverse the token
1124
+ if {[is_selected $token]} {
1125
+ reverse_token $w $token
1126
+ }
1127
+
1128
+ # Clear the active token
1129
+ set active_token($w) ""
1130
+
1131
+ } else {
1132
+
1133
+ set dont_deselect($w) 0
1134
+
1135
+ }
1136
+
1137
+ # Clear the arrow image
1138
+ $token.cat.l2.mid configure -image $img_blank
1139
+ $token.val.l2.mid configure -image $img_blank
1140
+
1141
+ }
1142
+
1143
+ ###########################################################################
1144
+ # This procedure is called whenever a token is left-pressed. It allows a
1145
+ # drag and drop option to move the token.
1146
+ proc handle_token_press {w token x y} {
1147
+
1148
+ variable pressed_token
1149
+ variable options
1150
+ variable dont_tokenize
1151
+
1152
+ # If we are disabled, do nothing
1153
+ if {$options($w,-state) eq "disabled"} {
1154
+ return
1155
+ }
1156
+
1157
+ # Save the pressed token
1158
+ set pressed_token($w) [list $token $x]
1159
+
1160
+ # Close the dropdown list if it is opened
1161
+ close_dropdown $w
1162
+
1163
+ # If there is anything that needs to be tokenized, do it now
1164
+ set dont_tokenize($w) 0
1165
+ tokenize $w
1166
+
1167
+ }
1168
+
1169
+ ###########################################################################
1170
+ # This procedure is called whenever a token is moved.
1171
+ proc handle_token_drag {w x y} {
1172
+
1173
+ variable pressed_token
1174
+
1175
+ if {$pressed_token($w) ne ""} {
1176
+
1177
+ # Make sure that the text widget has the focus
1178
+ focus $w.txt
1179
+
1180
+ # Change the cursor to a hand
1181
+ [lindex $pressed_token($w) 0] configure -cursor left_side
1182
+
1183
+ set index [$w.txt index @[expr [winfo x [lindex $pressed_token($w) 0]] + $x + 8],$y]
1184
+
1185
+ # Get the current location and set the insertion cursor
1186
+ if {$x < [lindex $pressed_token($w) 1]} {
1187
+ $w.txt mark set insert $index
1188
+ } else {
1189
+ $w.txt mark set insert "$index + 1 chars"
1190
+ }
1191
+
1192
+ }
1193
+
1194
+ }
1195
+
1196
+ ###########################################################################
1197
+ # This procedure is called whenever a token is left-clicked. It changes
1198
+ # the state of the token.
1199
+ proc handle_token_release {w token x y} {
1200
+
1201
+ variable options
1202
+ variable pressed_token
1203
+ variable active_token
1204
+
1205
+ # If we are disabled, stop now.
1206
+ if {$options($w,-state) eq "disabled"} {
1207
+ return
1208
+ }
1209
+
1210
+ set start_index [$w.txt index $token]
1211
+ set end_index [$w.txt index @[expr [winfo x [lindex $pressed_token($w) 0]] + $x + 8],$y]
1212
+
1213
+ # If the token was not moved, treat the click as a selection/detokenization
1214
+ if {$start_index == $end_index} {
1215
+
1216
+ # If the token is currently selected, detokenize the selection
1217
+ if {$active_token($w) == [$w.txt index $token]} {
1218
+
1219
+ detokenize $w $token
1220
+
1221
+ # Clear the pressed token
1222
+ set pressed_token($w) ""
1223
+
1224
+ return
1225
+
1226
+ } else {
1227
+
1228
+ # Reverse the color scheme
1229
+ reverse_token $w $token
1230
+
1231
+ # Set the active token
1232
+ set active_token($w) [$w.txt index $token]
1233
+
1234
+ # Make sure that the current token keeps the focus
1235
+ focus $token
1236
+
1237
+ # Generate the TokenSearchSelected event
1238
+ event generate $w <<TokenSearchSelected>>
1239
+
1240
+ }
1241
+
1242
+ # Otherwise, the token has been dragged to a new position -- delete it and recreate it in the new position
1243
+ } else {
1244
+
1245
+ # Move the window to the new position
1246
+ if {$x < [lindex $pressed_token($w) 1]} {
1247
+ $w.txt window create $end_index -window $token -padx 2
1248
+ } else {
1249
+ $w.txt window create "$end_index + 1 chars" -window $token -padx 2
1250
+ }
1251
+
1252
+ # Delete the previous position if the starting position is less than the ending position
1253
+ if {$start_index < $end_index} {
1254
+ $w.txt delete $start_index
1255
+ }
1256
+
1257
+ # Update the tokenvar variable, if it has been set
1258
+ if {$options($w,-tokenvar) ne ""} {
1259
+ upvar #0 $options($w,-tokenvar) var
1260
+ set var [get_tokens $w]
1261
+ }
1262
+
1263
+ # Generate a TokenSearchModified event
1264
+ event generate $w <<TokenSearchModified>>
1265
+
1266
+ }
1267
+
1268
+ # Change cursor on pressed token to arrow
1269
+ [lindex $pressed_token($w) 0] configure -cursor top_left_arrow
1270
+
1271
+ # Clear the pressed token
1272
+ set pressed_token($w) ""
1273
+
1274
+ }
1275
+
1276
+ ###########################################################################
1277
+ # Displays the popup menu for the given token.
1278
+ proc display_category_menu {w token} {
1279
+
1280
+ variable options
1281
+ variable dont_deselect
1282
+
1283
+ # Clear the menu
1284
+ $w.mnu delete 0 end
1285
+
1286
+ # Populate the menu with the given categories
1287
+ foreach category $options($w,-categories) {
1288
+ $w.mnu insert end command -label [lindex $category 0] -state disabled
1289
+ foreach value [lindex $category 1] {
1290
+ $w.mnu insert end command -label " $value" -command "$token.cat.l1 configure -text [list $value]; focus -force $token; event generate $w <<TokenSearchModified>>"
1291
+ }
1292
+ }
1293
+
1294
+ # Add the category options
1295
+ if {[llength $options($w,-categoryopts)] > 0} {
1296
+ $w.mnu insert end command -label "Category Options" -state disabled
1297
+ set optnum 0
1298
+ set last_type ""
1299
+ foreach categoryopt $options($w,-categoryopts) {
1300
+ if {[llength $categoryopt] != 3} {
1301
+ return -code error "Incorrect number of values specified in -categoryopt ($category). Must be {type {value(s)} default_value}"
1302
+ }
1303
+ if {[lindex $categoryopt 0] eq "checkbutton"} {
1304
+ if {$last_type eq "radiobutton"} {
1305
+ $w.mnu insert end separator
1306
+ }
1307
+ $w.mnu insert end checkbutton -label " [lindex $categoryopt 1]" -variable tokensearch::categoryopt_vars($w,$token,$optnum) -command "focus -force $token; event generate $w <<TokenSearchModified>>"
1308
+ } elseif {[lindex $categoryopt 0] eq "radiobutton"} {
1309
+ $w.mnu insert end separator
1310
+ foreach item [lindex $categoryopt 1] {
1311
+ $w.mnu insert end radiobutton -label " $item" -variable tokensearch::categoryopt_vars($w,$token,$optnum) -value $item -command "focus -force $token; event generate $w <<TokenSearchModified>>"
1312
+ }
1313
+ } else {
1314
+ return -code error "Illegal -categoryopts option type ([lindex $categoryopt 0])"
1315
+ }
1316
+ set last_type [lindex $categoryopt 0]
1317
+ incr optnum
1318
+ }
1319
+ }
1320
+
1321
+ # Specify that we should not perform a focusout deselection
1322
+ set dont_deselect($w) 1
1323
+
1324
+ # Display the popup menu
1325
+ tk_popup $w.mnu [winfo rootx $token.cat.l1] [expr [winfo rooty $token.cat.l1] + [winfo reqheight $token.cat.l1]]
1326
+
1327
+ }
1328
+
1329
+ ###########################################################################
1330
+ # This procedure is called whenever an arrow token is left-clicked. It changes
1331
+ # the state of the token.
1332
+ proc handle_cat_arrow_click {w token x y} {
1333
+
1334
+ variable active_token
1335
+ variable options
1336
+ variable img_blank
1337
+
1338
+ # If we are disabled, stop now.
1339
+ if {$options($w,-state) eq "disabled"} {
1340
+ return
1341
+ }
1342
+
1343
+ if {[$token.cat.l2.mid cget -image] eq $img_blank} {
1344
+ handle_token_press $w $token $x $y
1345
+ handle_token_release $w $token $x $y
1346
+ } else {
1347
+ display_category_menu $w $token
1348
+ }
1349
+
1350
+ }
1351
+
1352
+ ###########################################################################
1353
+ # Populates the dropdown listbox with the items from the -historyvar list
1354
+ # and displays the listbox.
1355
+ proc display_dropdown_items {w token} {
1356
+
1357
+ variable options
1358
+
1359
+ if {[info exists options($w,-historyvar)] && ($options($w,-historyvar) ne "")} {
1360
+
1361
+ upvar #0 $options($w,-historyvar) history
1362
+
1363
+ # Remove all of the items from the dropdown list
1364
+ $w.top.list delete 0 end
1365
+
1366
+ # Populate the dropdown list with the list of items from historyvar
1367
+ eval "$w.top.list insert end $history"
1368
+
1369
+ # Activate and select the first item in the list
1370
+ $w.top.list activate 0
1371
+ $w.top.list selection set 0
1372
+
1373
+ # Show the dropdown list
1374
+ open_dropdown $w $token
1375
+
1376
+ }
1377
+
1378
+ }
1379
+
1380
+ ###########################################################################
1381
+ # This procedure is called whenever an arrow token in the value portion of
1382
+ # the token is left-clicked. It pops down a search history drop-down listbox.
1383
+ proc handle_val_arrow_click {w token x y} {
1384
+
1385
+ variable active_token
1386
+ variable options
1387
+ variable img_blank
1388
+
1389
+ # If we are disabled, stop now.
1390
+ if {$options($w,-state) eq "disabled"} {
1391
+ return
1392
+ }
1393
+
1394
+ if {[$token.val.l2.mid cget -image] eq $img_blank} {
1395
+ handle_token_press $w $token $x $y
1396
+ handle_token_release $w $token $x $y
1397
+ } else {
1398
+ display_dropdown_items $w $token
1399
+ }
1400
+
1401
+ }
1402
+
1403
+ ###########################################################################
1404
+ # This procedirue is called when the cursor enters a token area.
1405
+ proc handle_token_enter {w token} {
1406
+
1407
+ variable options
1408
+ variable img_arrow
1409
+
1410
+ # If we are disabled, do nothing
1411
+ if {$options($w,-state) eq "disabled"} {
1412
+ return
1413
+ }
1414
+
1415
+ # Change the cursor
1416
+ $token configure -cursor top_left_arrow
1417
+
1418
+ }
1419
+
1420
+ ###########################################################################
1421
+ # This procedure is called when the cursor enters the category portion of
1422
+ # a token area.
1423
+ proc handle_category_enter {w token} {
1424
+
1425
+ variable options
1426
+ variable img_arrow
1427
+
1428
+ # If we are disabled, do nothing
1429
+ if {$options($w,-state) eq "disabled"} {
1430
+ return
1431
+ }
1432
+
1433
+ # Draw an arrow if we have categories
1434
+ if {[llength $options($w,-categories)] > 0} {
1435
+ $token.cat.l2.mid configure -image $img_arrow
1436
+ }
1437
+
1438
+ }
1439
+
1440
+ ###########################################################################
1441
+ # This procedure is called when the cursor enters the value portion of a
1442
+ # token area.
1443
+ proc handle_value_enter {w token} {
1444
+
1445
+ variable options
1446
+ variable img_arrow
1447
+
1448
+ # If we are disabled, do nothing
1449
+ if {$options($w,-state) eq "disabled"} {
1450
+ return
1451
+ }
1452
+
1453
+ # Draw an arrow if we have history
1454
+ if {$options($w,-historyvar) ne ""} {
1455
+ upvar #0 $options($w,-historyvar) history
1456
+ if {[llength $history] > 0} {
1457
+ $token.val.l2.mid configure -image $img_arrow
1458
+ }
1459
+ }
1460
+
1461
+ }
1462
+
1463
+ ###########################################################################
1464
+ # This procedure is called when the cursor leaves the category portion of
1465
+ # a token.
1466
+ proc handle_category_leave {w token} {
1467
+
1468
+ variable options
1469
+ variable img_arrow
1470
+ variable img_blank
1471
+
1472
+ # If we are disabled, do nothing
1473
+ if {$options($w,-state) eq "disabled"} {
1474
+ return
1475
+ }
1476
+
1477
+ if {([$token.cat.l2.mid cget -image] eq $img_arrow) && ([$token.cat.l2.mid cget -bg] eq [lindex $options($w,-tokenbg) 0])} {
1478
+ $token.cat.l2.mid configure -image $img_blank
1479
+ }
1480
+
1481
+ }
1482
+
1483
+ ###########################################################################
1484
+ # This procedure is called when the cursor leaves the value portion of a
1485
+ # token.
1486
+ proc handle_value_leave {w token} {
1487
+
1488
+ variable options
1489
+ variable img_arrow
1490
+ variable img_blank
1491
+
1492
+ # If we are disabled, do nothing
1493
+ if {$options($w,-state) eq "disabled"} {
1494
+ return
1495
+ }
1496
+
1497
+ if {([$token.val.l2.mid cget -image] eq $img_arrow) && ([$token.val.l2.mid cget -bg] eq [lindex $options($w,-tokenbg) end])} {
1498
+ $token.val.l2.mid configure -image $img_blank
1499
+ }
1500
+
1501
+ }
1502
+
1503
+ ###########################################################################
1504
+ # Calculates the geometry of the given window.
1505
+ proc compute_geometry {w} {
1506
+
1507
+ variable options
1508
+
1509
+ if {($options($w,-dropdownheight) == 0) && ($options($w,-dropdownmaxheight) != 0)} {
1510
+ set nitems [$w.top.list size]
1511
+ if {$nitems > $options($w,-dropdownmaxheight)} {
1512
+ $w.top.list configure -height $options($w,-dropdownmaxheight)
1513
+ } else {
1514
+ $w.top.list configure -height 0
1515
+ }
1516
+ update idletasks
1517
+ }
1518
+
1519
+ # Compute the height and width of the dropdown list
1520
+ set bd [$w.top cget -borderwidth]
1521
+ set height [expr [winfo reqheight $w.top] + $bd + $bd]
1522
+ set width [winfo width $w]
1523
+
1524
+ # Figure out where to place it on the screen
1525
+ set screen_width [winfo screenwidth $w]
1526
+ set screen_height [winfo screenheight $w]
1527
+ set rootx [winfo rootx $w]
1528
+ set rooty [winfo rooty $w]
1529
+ set vrootx [winfo vrootx $w]
1530
+ set vrooty [winfo vrooty $w]
1531
+
1532
+ set x [expr $rootx + $vrootx]
1533
+ set y [expr $rooty + $vrooty + [winfo reqheight $w] + 1]
1534
+ set bottom_edge [expr $y + $height]
1535
+
1536
+ # If it extends beyond our screen, trim the list and add a scrollbar
1537
+ if {$bottom_edge >= $screen_height} {
1538
+ set y [expr ($rooty - $height - 1) + $vrooty]
1539
+ if {$y < 0} {
1540
+ if {$rooty > [expr $screen_height / 2]} {
1541
+ set y 1
1542
+ set height [expr $rooty - 1 - $y]
1543
+ } else {
1544
+ set y [expr $rooty + $vrooty + [winfo reqheight $w] + 1]
1545
+ set height [expr $screen_height - $y]
1546
+ }
1547
+ handle_scrollbar $w crop
1548
+ }
1549
+ }
1550
+
1551
+ if {$y < 0} {
1552
+ set y 0
1553
+ set height $screen_height
1554
+ }
1555
+
1556
+ set geometry [format "=%dx%d+%d+%d" $width $height $x $y]
1557
+
1558
+ return $geometry
1559
+
1560
+ }
1561
+
1562
+ ###########################################################################
1563
+ # Hides/Displays the scrollbar in the dropdown listbox.
1564
+ proc handle_scrollbar {w {action "unknown"}} {
1565
+
1566
+ variable options
1567
+
1568
+ if {$options($w,-dropdownheight) == 0} {
1569
+ set hlimit $options($w,-dropdownmaxheight)
1570
+ } else {
1571
+ set hlimit $options($w,-dropdownheight)
1572
+ }
1573
+
1574
+ switch $action {
1575
+ "grow" {
1576
+ if {($hlimit > 0) && ([$w.top.list size] > $hlimit)} {
1577
+ pack forget $w.top.list
1578
+ pack $w.top.vsb -side right -fill y -expand n
1579
+ pack $w.top.list -side left -fill both -expand y
1580
+ }
1581
+ }
1582
+ "shrink" {
1583
+ if {($hlimit > 0) && ([$w.top.list size] <= $hlimit)} {
1584
+ pack forget $w.top.vsb
1585
+ }
1586
+ }
1587
+ "crop" {
1588
+ pack forget $w.top.list
1589
+ pack $w.top.vsb -side right -fill y -expand n
1590
+ pack $w.top.list -side left -fill both -expand y
1591
+ }
1592
+ default {
1593
+ if {($hlimit > 0) && ([$w.top.list size] > $hlimit)} {
1594
+ pack forget $w.top.list
1595
+ pack $w.top.vsb -side right -fill y -expand n
1596
+ pack $w.top.list -side left -fill both -expand y
1597
+ } else {
1598
+ pack forget $w.top.vsb
1599
+ }
1600
+ }
1601
+ }
1602
+
1603
+ return ""
1604
+
1605
+ }
1606
+
1607
+ ###########################################################################
1608
+ # This procedure is invoked by various events and displays the dropdown
1609
+ # listbox containing a list of selectable values.
1610
+ proc open_dropdown {w {token ""}} {
1611
+
1612
+ variable options
1613
+ variable old_focus
1614
+ variable old_grab
1615
+ variable dropdown_token
1616
+
1617
+ # If the user has not provided any values to display, skip opening the window
1618
+ if {$options($w,-historyvar) ne ""} {
1619
+ upvar #0 $options($w,-historyvar) historyvar
1620
+ if {[llength $historyvar] == 0} {
1621
+ return 0
1622
+ }
1623
+ }
1624
+
1625
+ # Update the scrollbar appropriately
1626
+ handle_scrollbar $w
1627
+
1628
+ # Compute the geometry of the window to pop up, set it, and force the window manager to
1629
+ # take notice
1630
+ set geometry [compute_geometry $w]
1631
+ wm geometry $w.top $geometry
1632
+ update idletasks
1633
+
1634
+ # If we are already open, stop
1635
+ if {[winfo ismapped $w.top]} {
1636
+ return 0
1637
+ }
1638
+
1639
+ # Set the reason
1640
+ set dropdown_token($w) $token
1641
+
1642
+ # Save the current focus
1643
+ set old_focus($w) [focus]
1644
+
1645
+ # Make the list pop up
1646
+ wm deiconify $w.top
1647
+ update idletasks
1648
+ raise $w.top
1649
+
1650
+ # Force the focus so we can handle keypress events for traversal
1651
+ if {$token eq ""} {
1652
+ focus -force $w.txt
1653
+ } else {
1654
+ focus -force $token
1655
+ }
1656
+
1657
+ # Save the current grab state
1658
+ set status "none"
1659
+ set grab [grab current $w]
1660
+ if {$grab != ""} {
1661
+ set status [grab status $grab]
1662
+ }
1663
+ set old_grab($w) [list $grab $status]
1664
+ unset grab status
1665
+
1666
+ grab -global $w
1667
+
1668
+ # Fake the listbox into thinking it has focus.
1669
+ event generate $w.top.list <B1-Enter>
1670
+
1671
+ return 1
1672
+
1673
+ }
1674
+
1675
+ ###########################################################################
1676
+ # This procedure is invoked when the user hits the Escape key or makes a
1677
+ # a listbox selection. It removes the dropdown listbox and returns the focus
1678
+ # to the text box.
1679
+ proc close_dropdown {w} {
1680
+
1681
+ variable old_focus
1682
+ variable old_grab
1683
+ variable dropdown_token
1684
+
1685
+ # If the window is already unmapped, stop
1686
+ if {![winfo ismapped $w.top]} {
1687
+ return 0
1688
+ }
1689
+
1690
+ catch { focus $old_focus($w) } result
1691
+ catch { grab release $w }
1692
+ catch {
1693
+ set status [lindex $old_grab($w) 1]
1694
+ if {$status eq "global"} {
1695
+ grab -global [lindex $old_grab($w) 0]
1696
+ } elseif {$status eq "local"} {
1697
+ grab [lindex $old_grab($w) 0]
1698
+ }
1699
+ unset status
1700
+ }
1701
+
1702
+ # Clear the reason
1703
+ set dropdown_token($w) ""
1704
+
1705
+ # Hide the listbox
1706
+ wm withdraw $w.top
1707
+
1708
+ # Magic Tcl stuff (see tk.tcl in the distribution lib directory)
1709
+ tk::CancelRepeat
1710
+
1711
+ return 1
1712
+
1713
+ }
1714
+
1715
+ ###########################################################################
1716
+ # This is called whenever the cursor moves over the listbox.
1717
+ proc motion_dropdown {w x y} {
1718
+
1719
+ # Set the cursor
1720
+ $w.top.list configure -cursor ""
1721
+
1722
+ # Clear the selections
1723
+ $w.top.list selection clear 0 end
1724
+
1725
+ # Set the selection to the current index
1726
+ $w.top.list selection set @$x,$y
1727
+
1728
+ }
1729
+
1730
+ ###########################################################################
1731
+ # Returns a sorted list of all of the token values.
1732
+ proc get_tokens {w} {
1733
+
1734
+ variable categoryopt_vars
1735
+
1736
+ set tokens [list]
1737
+ set indices [list]
1738
+
1739
+ foreach token [$w.txt window names] {
1740
+ lappend indices [list [$w.txt index $token] $token]
1741
+ }
1742
+
1743
+ foreach index [lsort -real -index 0 $indices] {
1744
+ set values [list [[lindex $index 1].cat.l1 cget -text] [[lindex $index 1].val.l1 cget -text]]
1745
+ set optnum 0
1746
+ while {[info exists categoryopt_vars($w,[lindex $index 1],$optnum)]} {
1747
+ lappend values $categoryopt_vars($w,[lindex $index 1],$optnum)
1748
+ incr optnum
1749
+ }
1750
+ lappend tokens $values
1751
+ }
1752
+
1753
+ return $tokens
1754
+
1755
+ }
1756
+
1757
+ ###########################################################################
1758
+ # Handles the current state of the widget (empty/non-empty) and handles
1759
+ # any watermark display (or removal of the display).
1760
+ proc handle_state {w keyed} {
1761
+
1762
+ variable state
1763
+ variable options
1764
+
1765
+ # If we are in the empty state
1766
+ if {$state($w) eq "empty"} {
1767
+
1768
+ $w.txt delete 1.0 end
1769
+
1770
+ if {$keyed} {
1771
+ set state($w) "non-empty"
1772
+ $w.txt configure -foreground $options($w,-foreground)
1773
+ } else {
1774
+ $w.txt configure -foreground $options($w,-watermarkforeground)
1775
+ $w.txt insert end $options($w,-watermark)
1776
+ $w.txt mark set insert 1.0
1777
+ }
1778
+
1779
+ # Otherwise, we are in the not-empty state
1780
+ } elseif {$state($w) eq "non-empty"} {
1781
+
1782
+ # If the widget is empty, set the state to empty and fill it with the
1783
+ # empty string.
1784
+ if {([string trim [$w.txt get 1.0 end]] eq "") && ([llength [$w.txt window names]] == 0)} {
1785
+ set state($w) "empty"
1786
+ $w.txt configure -foreground $options($w,-watermarkforeground)
1787
+ $w.txt insert end $options($w,-watermark)
1788
+ $w.txt mark set insert 1.0
1789
+ }
1790
+
1791
+ }
1792
+
1793
+ }
1794
+
1795
+ ###########################################################################
1796
+ # Converts an entry index to a text index.
1797
+ proc entry_to_text_index {w index} {
1798
+
1799
+ set offset ""
1800
+ if {[regexp {(.+)\s*\-\s*(\d+)$} $index -> index offset]} {
1801
+ set offset " - $offset chars"
1802
+ }
1803
+
1804
+ if {[string is integer $index]} {
1805
+ return "1.$index$offset"
1806
+ } elseif {$index eq "anchor"} {
1807
+ return -code error "Illegal tokensearch index ($index)"
1808
+ } elseif {$index eq "end"} {
1809
+ return "1.end$offset"
1810
+ } elseif {$index eq "insert"} {
1811
+ return "[$w.txt index insert]$offset"
1812
+ } elseif {$index eq "sel.first"} {
1813
+ return "[lindex [$w.txt tag ranges sel] 0]$offset"
1814
+ } elseif {$index eq "sel.last"} {
1815
+ return "[lindex [$w.txt tag ranges sel] 1]$offset"
1816
+ } else {
1817
+ return -code error "Illegal tokensearch index ($index)"
1818
+ }
1819
+
1820
+ }
1821
+
1822
+ ###########################################################################
1823
+ # Handles all commands.
1824
+ proc widget_cmd {w args} {
1825
+
1826
+ if {[llength $args] == 0} {
1827
+ return -code error "tokensearch widget called without a command"
1828
+ }
1829
+
1830
+ set cmd [lindex $args 0]
1831
+ set opts [lrange $args 1 end]
1832
+
1833
+ switch $cmd {
1834
+ configure { eval "tokensearch::configure 0 $w $opts" }
1835
+ cget { return [eval "tokensearch::cget $w $opts"] }
1836
+ tokenindex { return [eval "tokensearch::tokenindex $w $opts"] }
1837
+ tokenselection { eval "tokensearch::tokenselection $w $opts" }
1838
+ tokenget { return [eval "tokensearch::get_tokens $w"] }
1839
+ tokenconfigure { eval "tokensearch::tokenconfigure $w $opts" }
1840
+ tokencget { return [eval "tokensearch::tokencget $w $opts" }
1841
+ tokeninsert { eval "tokensearch::tokeninsert $w $opts" }
1842
+ tokendelete { eval "tokensearch::tokendelete $w $opts" }
1843
+ tokenedit { eval "tokensearch::tokenedit $w $opts" }
1844
+ entryget { return [$w.txt get 1.0 end] }
1845
+ insert { eval "tokensearch::insert $w $opts" }
1846
+ delete { eval "tokensearch::delete $w $opts" }
1847
+ get { return [eval "tokensearch::get $w $opts"] }
1848
+ icursor { eval "tokensearch::icursor $w $opts" }
1849
+ index { return [eval "tokensearch::index $w $opts"] }
1850
+ default { eval "$w.txt $cmd $opts" }
1851
+ }
1852
+
1853
+ }
1854
+
1855
+ ###########################################################################
1856
+ # USER COMMANDS
1857
+ ###########################################################################
1858
+
1859
+ ###########################################################################
1860
+ # Main configuration routine.
1861
+ proc configure {initialize w args} {
1862
+
1863
+ variable options
1864
+ variable text_options
1865
+ variable widget_options
1866
+ variable state
1867
+
1868
+ if {([llength $args] == 0) && !$initialize} {
1869
+
1870
+ set results [list]
1871
+
1872
+ foreach opt [lsort [array names widget_options]] {
1873
+ if {[llength $widget_options($opt)] == 2} {
1874
+ set opt_name [lindex $widget_options($opt) 0]
1875
+ set opt_class [lindex $widget_options($opt) 1]
1876
+ set opt_default [option get $w $opt_name $opt_class]
1877
+ if {[info exists text_options($opt)]} {
1878
+ lappend results [list $opt $opt_name $opt_class $opt_default [$w.txt cget $opt]]
1879
+ } elseif {[info exists options($w,$opt)]} {
1880
+ lappend results [list $opt $opt_name $opt_class $opt_default $options($w,$opt)]
1881
+ } else {
1882
+ lappend results [list $opt $opt_name $opt_class $opt_default ""]
1883
+ }
1884
+ }
1885
+ }
1886
+
1887
+ return $results
1888
+
1889
+ } elseif {([llength $args] == 1) && !$initialize} {
1890
+
1891
+ set opt [lindex $args 0]
1892
+
1893
+ if {[info exists widget_options($opt)]} {
1894
+ if {[llength $widget_options($opt)] == 1} {
1895
+ set opt [lindex $widget_options($opt) 0]
1896
+ }
1897
+ set opt_name [lindex $widget_options($opt) 0]
1898
+ set opt_class [lindex $widget_options($opt) 1]
1899
+ set opt_default [option get $w $opt_name $opt_class]
1900
+ if {[info exists text_options($opt)]} {
1901
+ return [list $opt $opt_name $opt_class $opt_default [$w.txt cget $opt]]
1902
+ } elseif {[info exists options($w,$opt)]} {
1903
+ return [list $opt $opt_name $opt_class $opt_default $options($w,$opt)]
1904
+ } else {
1905
+ return [list $opt $opt_name $opt_class $opt_default ""]
1906
+ }
1907
+ }
1908
+
1909
+ return -code error "TokenSearch configuration option [lindex $args 0] does not exist"
1910
+
1911
+ } else {
1912
+
1913
+ # Save the original contents
1914
+ array set orig_options [array get options]
1915
+
1916
+ # Parse the arguments
1917
+ foreach {name value} $args {
1918
+ if {[info exists text_options($name)]} {
1919
+ $w.txt configure $name $value
1920
+ } elseif {[info exists options($w,$name)]} {
1921
+ set options($w,$name) $value
1922
+ } else {
1923
+ return -code error "Illegal option given to the tokensearch configure command ($name)"
1924
+ }
1925
+ }
1926
+
1927
+ # Update the GUI widgets
1928
+ # $w.txt configure -fg $options($w,-foreground) -bg $options($w,-background) -relief $options($w,-relief) -state $options($w,-state)
1929
+ if {$options($w,-width) ne ""} {
1930
+ $w.txt configure -width $options($w,-width)
1931
+ }
1932
+ if {$options($w,-height) ne ""} {
1933
+ $w.txt configure -height $options($w,-height)
1934
+ }
1935
+ $w.mnu configure -bg $options($w,-categorybg) -bd $options($w,-categorybd) -relief $options($w,-categoryrelief) -font $options($w,-categoryfont) -cursor $options($w,-categorycursor)
1936
+
1937
+ if {[string is boolean $options($w,-wrap)]} {
1938
+ if {$options($w,-wrap)} {
1939
+ $w.txt configure -wrap word
1940
+ } else {
1941
+ $w.txt configure -wrap none
1942
+ }
1943
+ } else {
1944
+ set options($w,-wrap) $orig_options($w,-wrap)
1945
+ return -code error "Value for -wrap option is not a boolean value ($options($w,-wrap))"
1946
+ }
1947
+
1948
+ # If the textbox is empty, configure it for the watermark
1949
+ if {$options($w,-watermark) ne ""} {
1950
+ set state($w) "empty"
1951
+ }
1952
+ handle_state $w 0
1953
+
1954
+ if {($orig_options($w,-dropdownheight) ne $options($w,-dropdownheight)) || \
1955
+ ($orig_options($w,-dropdownmaxheight) ne $options($w,-dropdownmaxheight))} {
1956
+ handle_scrollbar $w
1957
+ }
1958
+
1959
+ # Update the tokens, if necessary
1960
+ if {($orig_options($w,-tokenbg) ne $options($w,-tokenbg)) || ($orig_options($w,-tokenfg) ne $options($w,-tokenfg)) || \
1961
+ ($orig_options($w,-tokenselectbg) ne $options($w,-tokenselectbg)) || ($orig_options($w,-tokenselectfg) ne $options($w,-tokenselectfg)) || \
1962
+ ($orig_options($w,-tokenshape) ne $options($w,-tokenshape))} {
1963
+ set token_num [llength [$w.txt window names]]
1964
+ for {set i 0} {$i < $token_num} {incr i} {
1965
+ tokenconfigure $w $i -bg $options($w,-tokenbg) -fg $options($w,-tokenfg) \
1966
+ -selectbg $options($w,-tokenselectbg) -selectfg $options($w,-tokenselectfg) \
1967
+ -shape $options($w,-tokenshape)
1968
+ }
1969
+ }
1970
+
1971
+ }
1972
+
1973
+ }
1974
+
1975
+ ###########################################################################
1976
+ # Gets configuration option value(s).
1977
+ proc cget {w args} {
1978
+
1979
+ variable options
1980
+ variable text_options
1981
+
1982
+ if {[llength $args] != 1} {
1983
+ return -code error "Incorrect number of parameters given to the tokensearch cget command"
1984
+ }
1985
+
1986
+ if {[info exists text_options([lindex $args 0])]} {
1987
+ return [$w.txt cget [lindex $args 0]]
1988
+ } elseif {[info exists options($w,[lindex $args 0])]} {
1989
+ return $options($w,[lindex $args 0])
1990
+ } else {
1991
+ return -code error "Illegal option given to the tokensearch cget command ([lindex $args 0])"
1992
+ }
1993
+
1994
+ }
1995
+
1996
+ ###########################################################################
1997
+ # Configures the token located at the given index.
1998
+ proc tokenconfigure {w args} {
1999
+
2000
+ variable token_shapes
2001
+
2002
+ if {[expr [llength $args] % 2] == 0} {
2003
+ return -code error "Incorrect number of parameters given to the tokenconfigure command"
2004
+ }
2005
+
2006
+ set index [index_to_position $w [lindex $args 0]]
2007
+
2008
+ # Retrieve the current token pathname
2009
+ set token [$w.txt window cget $index -window]
2010
+
2011
+ # Figure out if the current token is selected or not
2012
+ set selected [is_selected $token]
2013
+
2014
+ set redraw 0
2015
+ set resize 0
2016
+
2017
+ foreach {option value} [lrange $args 1 end] {
2018
+ switch $option {
2019
+ -bg -
2020
+ -background {
2021
+ if {$selected} {
2022
+ $token.cat.l2.top configure -fg [lindex $value 0]
2023
+ $token.val.l2.top configure -fg [lindex $value end]
2024
+ } else {
2025
+ $token.ll configure -bg [lindex $value 0]
2026
+ $token.cat.l1 configure -bg [lindex $value 0]
2027
+ $token.cat.l2 configure -bg [lindex $value 0]
2028
+ $token.cat.l2.mid configure -bg [lindex $value 0]
2029
+ $token.val.l1 configure -bg [lindex $value end]
2030
+ $token.val.l2 configure -bg [lindex $value end]
2031
+ $token.val.l2.mid configure -bg [lindex $value end]
2032
+ $token.lr configure -bg [lindex $value end]
2033
+ set redraw 1
2034
+ }
2035
+ }
2036
+ -fg -
2037
+ -foreground {
2038
+ if {$selected} {
2039
+ $token.cat.l2.mid configure -fg [lindex $value 0]
2040
+ $token.val.l2.mid configure -fg [lindex $value end]
2041
+ } else {
2042
+ $token.cat.l1 configure -fg [lindex $value 0]
2043
+ $token.val.l1 configure -fg [lindex $value end]
2044
+ set redraw 1
2045
+ }
2046
+ }
2047
+ -bordercolor {
2048
+ if {$selected} {
2049
+ $token.cat.l2.bot configure -fg [lindex $value 0]
2050
+ $token.val.l2.bot configure -fg [lindex $value end]
2051
+ } else {
2052
+ $token.cat.l2.top configure -bg [lindex $value 0]
2053
+ $token.cat.l2.bot configure -bg [lindex $value 0]
2054
+ $token.val.l2.top configure -bg [lindex $value end]
2055
+ $token.val.l2.bot configure -bg [lindex $value end]
2056
+ set redraw 1
2057
+ }
2058
+ }
2059
+ -shape {
2060
+ if {([llength $value] < 0) || ([llength $value] > 2)} {
2061
+ return -code error "ERROR: Token -shape list must be contain either 1 or 2 values"
2062
+ }
2063
+ foreach val $value {
2064
+ switch $value {
2065
+ pill -
2066
+ tag -
2067
+ square -
2068
+ eased -
2069
+ ticket {}
2070
+ default {
2071
+ return -code error "ERROR: Token -shape is an unsupported value (pill, tag, square, eased, ticket)"
2072
+ }
2073
+ }
2074
+ set token_shapes($token) $value
2075
+ set redraw 1
2076
+ }
2077
+ }
2078
+ -selectbg -
2079
+ -selectbackground {
2080
+ if {$selected} {
2081
+ $token.ll configure -bg [lindex $value 0]
2082
+ $token.cat.l1 configure -bg [lindex $value 0]
2083
+ $token.cat.l2 configure -bg [lindex $value 0]
2084
+ $token.cat.l2.mid configure -bg [lindex $value 0]
2085
+ $token.val.l1 configure -bg [lindex $value end]
2086
+ $token.val.l2 configure -bg [lindex $value end]
2087
+ $token.val.l2.mid configure -bg [lindex $value end]
2088
+ $token.lr configure -bg [lindex $value end]
2089
+ set redraw 1
2090
+ } else {
2091
+ $token.cat.l2.top configure -fg [lindex $value 0]
2092
+ $token.val.l2.top configure -fg [lindex $value end]
2093
+ }
2094
+ }
2095
+ -selectfg -
2096
+ -selectforeground {
2097
+ if {$selected} {
2098
+ $token.cat.l1 configure -fg [lindex $value 0]
2099
+ $token.val.l1 configure -fg [lindex $value end]
2100
+ set redraw 1
2101
+ } else {
2102
+ $token.cat.l2.mid configure -fg [lindex $value 0]
2103
+ $token.val.l2.mid configure -fg [lindex $value end]
2104
+ }
2105
+ }
2106
+ -selectbordercolor {
2107
+ if {$selected} {
2108
+ $token.cat.l2.top configure -bg [lindex $value 0]
2109
+ $token.cat.l2.bot configure -bg [lindex $value 0]
2110
+ $token.val.l2.top configure -bg [lindex $value end]
2111
+ $token.val.l2.bot configure -bg [lindex $value end]
2112
+ set redraw 1
2113
+ } else {
2114
+ $token.cat.l2.bot configure -fg [lindex $value 0]
2115
+ $token.val.l2.bot configure -fg [lindex $value end]
2116
+ }
2117
+ }
2118
+ -categoryindex {
2119
+ $token.cat.l1 configure -text [lindex $options($w,-categories) $value]
2120
+ set redraw 1
2121
+ set resize 1
2122
+ }
2123
+ -value {
2124
+ $token.val.l1 configure -text $value
2125
+ set redraw 1
2126
+ set resize 1
2127
+ }
2128
+ default {
2129
+ return -code error "Illegal option to the tokenconfigure option ($option)"
2130
+ }
2131
+ }
2132
+ }
2133
+
2134
+ # If we need to redraw the token, do it now
2135
+ if {$redraw} {
2136
+ redraw_token $w $token $resize
2137
+ }
2138
+
2139
+ }
2140
+
2141
+ ###########################################################################
2142
+ # Gets the configuration information located at the given index.
2143
+ proc tokencget {w args} {
2144
+
2145
+ variable token_shapes
2146
+
2147
+ if {[llength $args] != 2} {
2148
+ return -code error "Incorrect number of options given to the tokencget command"
2149
+ }
2150
+
2151
+ # Get the token index
2152
+ set index [index_to_position $w [lindex $args 0]]
2153
+
2154
+ # Get the token
2155
+ set token [$w.txt window cget $index -window]
2156
+
2157
+ # Figure out if the token is currently selected
2158
+ set selected [is_selected $token]
2159
+
2160
+ # Do an option lookup
2161
+ switch [lindex $args 1] {
2162
+ -bg -
2163
+ -background {
2164
+ if {$selected} {
2165
+ return [list [$token.cat.l2.top cget -fg] [$token.val.l2.top cget -fg]]
2166
+ } else {
2167
+ return [list [$token.cat.l1 cget -bg] [$token.val.l1 cget -bg]]
2168
+ }
2169
+ }
2170
+ -fg -
2171
+ -foreground {
2172
+ if {$selected} {
2173
+ return [list [$token.cat.l2.mid cget -fg] [$token.val.l2.mid cget -fg]]
2174
+ } else {
2175
+ return [list [$token.cat.l1 cget -fg] [$token.val.l1 cget -fg]]
2176
+ }
2177
+ }
2178
+ -bordercolor {
2179
+ if {$selected} {
2180
+ return [list [$token.cat.l2.bot cget -fg] [$token.val.l2.bot cget -fg]]
2181
+ } else {
2182
+ return [list [$token.cat.l2.top cget -bg] [$token.val.l2.top cget -bg]]
2183
+ }
2184
+ }
2185
+ -shape {
2186
+ return $token_shapes($token)
2187
+ }
2188
+ -selectbg -
2189
+ -selectbackground {
2190
+ if {$selected} {
2191
+ return [list [$token.cat.l1 cget -bg] [$token.val.l1 cget -bg]]
2192
+ } else {
2193
+ return [list [$token.cat.l2.top cget -fg] [$token.val.l2.top cget -fg]]
2194
+ }
2195
+ }
2196
+ -selectfg -
2197
+ -selectforeground {
2198
+ if {$selected} {
2199
+ return [list [$token.cat.l1 cget -fg] [$token.val.l1 cget -fg]]
2200
+ } else {
2201
+ return [list [$token.cat.l2.mid cget -fg] [$token.val.l2.mid cget -fg]]
2202
+ }
2203
+ }
2204
+ -selectbordercolor {
2205
+ if {$selected} {
2206
+ return [list [$token.cat.l2.top cget -bg] [$token.val.l2.top cget -bg]]
2207
+ } else {
2208
+ return [list [$token.cat.l2.bot cget -fg] [$token.val.l2.bot cget -fg]]
2209
+ }
2210
+ }
2211
+ -categoryindex {
2212
+ return [lsearch $options($w,-categories) [$token.cat.l1 cget -text]]
2213
+ }
2214
+ -value {
2215
+ return [$token.val.l1 cget -text]
2216
+ }
2217
+ default {
2218
+ return -code error "Illegal option to the tokencget option ([lindex $args 1])"
2219
+ }
2220
+
2221
+ }
2222
+
2223
+ }
2224
+
2225
+ ###########################################################################
2226
+ # Returns the numerical index of the specified index.
2227
+ proc tokenindex {w args} {
2228
+
2229
+ variable active_token
2230
+
2231
+ if {[llength $args] != 1} {
2232
+ return -code error "Illegal options to the tokenindex command"
2233
+ } else {
2234
+ set index [lindex $args 0]
2235
+ if {$index eq "active"} {
2236
+ if {$active_token($w) eq ""} {
2237
+ return -1
2238
+ } else {
2239
+ return $active_token($w)
2240
+ }
2241
+ } else {
2242
+ return [lindex [$w.txt window names] $index]
2243
+ }
2244
+ }
2245
+
2246
+ }
2247
+
2248
+ ###########################################################################
2249
+ # Handles the tokenselection command.
2250
+ proc tokenselection {w args} {
2251
+
2252
+ variable active_token
2253
+ variable options
2254
+
2255
+ if {[llength $args] == 0} {
2256
+
2257
+ return -code error "Incorrect number of options to the tokenselection command"
2258
+
2259
+ } else {
2260
+
2261
+ switch [lindex $args 0] {
2262
+ get {
2263
+ }
2264
+ clear {
2265
+ set start_index [index_to_position $w [lindex $args 1]]
2266
+ set end_index [index_to_position $w [lindex $args 2]]
2267
+ set index $start_index
2268
+ foreach token [lrange [$w.txt window names] $start_index $end_index] {
2269
+ $token configure -fg $options($w,-tokenfg) -bg $options($w,-tokenbg)
2270
+ incr start_index
2271
+ }
2272
+ set active_token($w) ""
2273
+ }
2274
+ set {
2275
+ set start_index [index_to_position $w [lindex $args 1]]
2276
+ set end_index [index_to_position $w [lindex $args 2]]
2277
+ set index $start_index
2278
+ foreach token [lrange [$w.txt window names] $start_index $end_index] {
2279
+ $token configure -fg $options($w,-tokenselectfg) -bg $options($w,-tokenselectbg)
2280
+ incr index
2281
+ }
2282
+ set active_token($w) $start_index
2283
+ }
2284
+ default {
2285
+ return -code error "Illegal token selection command ([lindex $args 0])"
2286
+ }
2287
+ }
2288
+
2289
+ }
2290
+
2291
+ }
2292
+
2293
+ ###########################################################################
2294
+ # Handles the token insertion command.
2295
+ proc tokeninsert {w args} {
2296
+
2297
+ variable options
2298
+ variable dont_tokenize
2299
+ variable categoryopt_vars
2300
+
2301
+ if {[llength $args] != 2} {
2302
+ return -code error "Incorrect number of options to the tokeninsert command"
2303
+ }
2304
+
2305
+ set index [index_to_position $w [lindex $args 0]]
2306
+
2307
+ if {$index eq ""} {
2308
+ set index [$w.txt index "1.[lindex $args 0]"]
2309
+ }
2310
+
2311
+ # Make sure that all inserted text is tokenized
2312
+ set dont_tokenize($w) 0
2313
+
2314
+ # Create the tokens (we do this for performance purposes)
2315
+ foreach value [lreverse [lindex $args 1]] {
2316
+
2317
+ # Handle the current state
2318
+ handle_state $w 1
2319
+
2320
+ # Insert the text into the widget
2321
+ $w.txt insert $index [lindex $value 1]
2322
+
2323
+ # Turn the text into a token
2324
+ if {[set token [tokenize $w]] ne ""} {
2325
+
2326
+ # Set the category
2327
+ $token.cat.l1 configure -text [lindex $value 0]
2328
+
2329
+ # Set the category options
2330
+ set optnum 0
2331
+ foreach opt [lrange $value 2 end] {
2332
+ set categoryopt_vars($w,$token,$optnum) $opt
2333
+ incr optnum
2334
+ }
2335
+
2336
+ }
2337
+
2338
+ }
2339
+
2340
+ }
2341
+
2342
+ ###########################################################################
2343
+ # Deletes one or more tokens from the text widget.
2344
+ proc tokendelete {w args} {
2345
+
2346
+ if {([llength $args] == 0) || ([llength $args] > 2)} {
2347
+ return -code error "Incorrect number of options to the tokendelete command"
2348
+ }
2349
+
2350
+ # If the user wants to delete a single item, do so
2351
+ if {[llength $args] == 1} {
2352
+ set index [index_to_position $w [lindex $args 0]]
2353
+ if {$index ne ""} {
2354
+ $w.txt delete $index
2355
+ handle_state $w 1
2356
+ }
2357
+
2358
+ # Otherwise, delete a range of items
2359
+ } else {
2360
+ set sindex [index_to_position $w [lindex $args 0]]
2361
+ set eindex [index_to_position $w [lindex $args 1]]
2362
+ if {$sindex ne ""} {
2363
+ if {$eindex eq ""} {
2364
+ $w.txt delete $sindex
2365
+ } else {
2366
+ $w.txt delete $sindex "$eindex + 1 chars"
2367
+ }
2368
+ handle_state $w 1
2369
+ }
2370
+ }
2371
+
2372
+ }
2373
+
2374
+ ###########################################################################
2375
+ # Detokenizes the given token to make it editable.
2376
+ proc tokenedit {w args} {
2377
+
2378
+ if {[llength $args] != 1} {
2379
+ return -code error "Incorrect number of options to the tokenedit command"
2380
+ }
2381
+
2382
+ # Detokenize the given index
2383
+ if {[set token [index_to_token $w [lindex $args 0]]] ne ""} {
2384
+ detokenize $w $token
2385
+ }
2386
+
2387
+ }
2388
+
2389
+ ###########################################################################
2390
+ # Overrides the text insert command to handle watermarks.
2391
+ proc insert {w args} {
2392
+
2393
+ if {([llength $args] != 1) && ([llength $args] != 2)} {
2394
+ return -code error "tokensearch::insert called with wrong arguments"
2395
+ }
2396
+
2397
+ # If the user has inserted a non-empty string of data, make sure the state
2398
+ # is handled properly.
2399
+ if {[lindex $args 1] ne ""} {
2400
+ handle_state $w 1
2401
+ } else {
2402
+ handle_state $w 0
2403
+ }
2404
+
2405
+ return [eval "$w.txt insert [entry_to_text_index $w [lindex $args 0]] [lindex $args 1]"]
2406
+
2407
+ }
2408
+
2409
+ ###########################################################################
2410
+ # Converts tokenentry delete command to a text delete command.
2411
+ proc delete {w args} {
2412
+
2413
+ variable state
2414
+
2415
+ if {[llength $args] == 1} {
2416
+ if {$state($w) ne "empty"} {
2417
+ $w.txt delete [entry_to_text_index $w [lindex $args 0]]
2418
+ handle_state $w 0
2419
+ }
2420
+ } elseif {[llength $args] == 2} {
2421
+ if {$state($w) ne "empty"} {
2422
+ $w.txt delete [entry_to_text_index $w [lindex $args 0]] \
2423
+ [entry_to_text_index $w [lindex $args 1]]
2424
+ handle_state $w 0
2425
+ }
2426
+ } else {
2427
+ return -code error "tokensearch::delete called with wrong arguments"
2428
+ }
2429
+
2430
+ }
2431
+
2432
+ ###########################################################################
2433
+ # Converts tokensearch get command to a text get command.
2434
+ proc get {w args} {
2435
+
2436
+ variable state
2437
+
2438
+ if {[llength $args] != 0} {
2439
+ return -code error "tokensearch::get called with wrong arguments"
2440
+ }
2441
+
2442
+ if {$state($w) eq "empty"} {
2443
+ return ""
2444
+ } else {
2445
+ return [$w.txt get 1.0 1.end]
2446
+ }
2447
+
2448
+ }
2449
+
2450
+ ###########################################################################
2451
+ # Converts tokensearch icursor command to a text insertion cursor call.
2452
+ proc icursor {w args} {
2453
+
2454
+ variable state
2455
+
2456
+ if {[llength $args] != 1} {
2457
+ return -code error "tokensearch::icursor called with wrong arguments"
2458
+ }
2459
+
2460
+ if {$state($w) eq "empty"} {
2461
+ return [$w.txt mark set insert 1.0]
2462
+ } else {
2463
+ return [eval "$w.txt mark set insert [entry_to_text_index $w [lindex $args 0]]"]
2464
+ }
2465
+
2466
+ }
2467
+
2468
+ ###########################################################################
2469
+ # Converts tokensearch index command to a text index command call.
2470
+ proc index {w args} {
2471
+
2472
+ variable state
2473
+
2474
+ if {[llength $args] != 1} {
2475
+ return -code error "tokensearch::index called with wrong arguments"
2476
+ }
2477
+
2478
+ if {$state($w) eq "empty"} {
2479
+ return 0
2480
+ } else {
2481
+ return [lindex [split [$w.txt index [entry_to_text_index $w [lindex $args 0]]] .] 1]
2482
+ }
2483
+
2484
+ }
2485
+
2486
+ namespace export *
2487
+
2488
+ }