Pratt 1.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (283) hide show
  1. data/.exrc +61 -0
  2. data/.gitignore +4 -0
  3. data/History.txt +6 -0
  4. data/Manifest.txt +46 -0
  5. data/Pratt.gemspec +351 -0
  6. data/README.txt +66 -0
  7. data/Rakefile +85 -0
  8. data/TODO +54 -0
  9. data/VERSION +1 -0
  10. data/bin/pratt.rb +13 -0
  11. data/config.rb +34 -0
  12. data/lib/pratt.rb +527 -0
  13. data/lib/pratt/array.rb +11 -0
  14. data/lib/pratt/string.rb +18 -0
  15. data/models/app.rb +40 -0
  16. data/models/customer.rb +24 -0
  17. data/models/payment.rb +22 -0
  18. data/models/pratt.rb +19 -0
  19. data/models/project.rb +82 -0
  20. data/models/whence.rb +70 -0
  21. data/pkgs/tile-0.8.2.tar.gz +0 -0
  22. data/pkgs/tile-0.8.2/ANNOUNCE.txt +95 -0
  23. data/pkgs/tile-0.8.2/ChangeLog +4651 -0
  24. data/pkgs/tile-0.8.2/Makefile +250 -0
  25. data/pkgs/tile-0.8.2/Makefile.in +250 -0
  26. data/pkgs/tile-0.8.2/README.txt +86 -0
  27. data/pkgs/tile-0.8.2/aclocal.m4 +2 -0
  28. data/pkgs/tile-0.8.2/altTheme.o +0 -0
  29. data/pkgs/tile-0.8.2/blink.o +0 -0
  30. data/pkgs/tile-0.8.2/button.o +0 -0
  31. data/pkgs/tile-0.8.2/cache.o +0 -0
  32. data/pkgs/tile-0.8.2/clamTheme.o +0 -0
  33. data/pkgs/tile-0.8.2/classicTheme.o +0 -0
  34. data/pkgs/tile-0.8.2/config.log +1330 -0
  35. data/pkgs/tile-0.8.2/config.status +795 -0
  36. data/pkgs/tile-0.8.2/configure +15248 -0
  37. data/pkgs/tile-0.8.2/configure.in +89 -0
  38. data/pkgs/tile-0.8.2/demos/autocomplete.tcl +59 -0
  39. data/pkgs/tile-0.8.2/demos/demo.tcl +870 -0
  40. data/pkgs/tile-0.8.2/demos/dirbrowser.tcl +167 -0
  41. data/pkgs/tile-0.8.2/demos/dlgtest.tcl +97 -0
  42. data/pkgs/tile-0.8.2/demos/iconlib.tcl +110 -0
  43. data/pkgs/tile-0.8.2/demos/repeater.tcl +117 -0
  44. data/pkgs/tile-0.8.2/demos/toolbutton.tcl +101 -0
  45. data/pkgs/tile-0.8.2/doc/Geometry.3 +230 -0
  46. data/pkgs/tile-0.8.2/doc/INDEX.MAP +153 -0
  47. data/pkgs/tile-0.8.2/doc/Makefile +36 -0
  48. data/pkgs/tile-0.8.2/doc/TILE.XML +45 -0
  49. data/pkgs/tile-0.8.2/doc/Theme.3 +34 -0
  50. data/pkgs/tile-0.8.2/doc/button.n +75 -0
  51. data/pkgs/tile-0.8.2/doc/checkbutton.n +61 -0
  52. data/pkgs/tile-0.8.2/doc/combobox.n +98 -0
  53. data/pkgs/tile-0.8.2/doc/converting.txt +97 -0
  54. data/pkgs/tile-0.8.2/doc/dialog.n +122 -0
  55. data/pkgs/tile-0.8.2/doc/entry.n +438 -0
  56. data/pkgs/tile-0.8.2/doc/frame.n +43 -0
  57. data/pkgs/tile-0.8.2/doc/html/Geometry.html +304 -0
  58. data/pkgs/tile-0.8.2/doc/html/Theme.html +48 -0
  59. data/pkgs/tile-0.8.2/doc/html/button.html +120 -0
  60. data/pkgs/tile-0.8.2/doc/html/category-index.html +18 -0
  61. data/pkgs/tile-0.8.2/doc/html/checkbutton.html +94 -0
  62. data/pkgs/tile-0.8.2/doc/html/combobox.html +164 -0
  63. data/pkgs/tile-0.8.2/doc/html/converting.txt +97 -0
  64. data/pkgs/tile-0.8.2/doc/html/dialog.html +159 -0
  65. data/pkgs/tile-0.8.2/doc/html/entry.html +613 -0
  66. data/pkgs/tile-0.8.2/doc/html/frame.html +76 -0
  67. data/pkgs/tile-0.8.2/doc/html/image.html +100 -0
  68. data/pkgs/tile-0.8.2/doc/html/index.html +25 -0
  69. data/pkgs/tile-0.8.2/doc/html/keyword-index.html +228 -0
  70. data/pkgs/tile-0.8.2/doc/html/label.html +133 -0
  71. data/pkgs/tile-0.8.2/doc/html/labelframe.html +91 -0
  72. data/pkgs/tile-0.8.2/doc/html/manpage.css +212 -0
  73. data/pkgs/tile-0.8.2/doc/html/menubutton.html +63 -0
  74. data/pkgs/tile-0.8.2/doc/html/notebook.html +280 -0
  75. data/pkgs/tile-0.8.2/doc/html/paned.html +149 -0
  76. data/pkgs/tile-0.8.2/doc/html/progressbar.html +138 -0
  77. data/pkgs/tile-0.8.2/doc/html/radiobutton.html +89 -0
  78. data/pkgs/tile-0.8.2/doc/html/scrollbar.html +221 -0
  79. data/pkgs/tile-0.8.2/doc/html/separator.html +48 -0
  80. data/pkgs/tile-0.8.2/doc/html/sizegrip.html +62 -0
  81. data/pkgs/tile-0.8.2/doc/html/style.html +172 -0
  82. data/pkgs/tile-0.8.2/doc/html/tile-intro.html +164 -0
  83. data/pkgs/tile-0.8.2/doc/html/treeview.html +634 -0
  84. data/pkgs/tile-0.8.2/doc/html/widget.html +342 -0
  85. data/pkgs/tile-0.8.2/doc/image.n +81 -0
  86. data/pkgs/tile-0.8.2/doc/internals.txt +409 -0
  87. data/pkgs/tile-0.8.2/doc/label.n +75 -0
  88. data/pkgs/tile-0.8.2/doc/labelframe.n +64 -0
  89. data/pkgs/tile-0.8.2/doc/man.macros +239 -0
  90. data/pkgs/tile-0.8.2/doc/menubutton.n +41 -0
  91. data/pkgs/tile-0.8.2/doc/notebook.n +188 -0
  92. data/pkgs/tile-0.8.2/doc/paned.n +95 -0
  93. data/pkgs/tile-0.8.2/doc/progressbar.n +79 -0
  94. data/pkgs/tile-0.8.2/doc/radiobutton.n +57 -0
  95. data/pkgs/tile-0.8.2/doc/scrollbar.n +160 -0
  96. data/pkgs/tile-0.8.2/doc/separator.n +30 -0
  97. data/pkgs/tile-0.8.2/doc/sizegrip.n +53 -0
  98. data/pkgs/tile-0.8.2/doc/style.n +119 -0
  99. data/pkgs/tile-0.8.2/doc/tile-intro.n +165 -0
  100. data/pkgs/tile-0.8.2/doc/tmml.options +4 -0
  101. data/pkgs/tile-0.8.2/doc/treeview.n +415 -0
  102. data/pkgs/tile-0.8.2/doc/widget.n +227 -0
  103. data/pkgs/tile-0.8.2/doc/xml/Geometry.tmml +379 -0
  104. data/pkgs/tile-0.8.2/doc/xml/INDEX.MAP +153 -0
  105. data/pkgs/tile-0.8.2/doc/xml/Theme.tmml +63 -0
  106. data/pkgs/tile-0.8.2/doc/xml/button.tmml +134 -0
  107. data/pkgs/tile-0.8.2/doc/xml/checkbutton.tmml +119 -0
  108. data/pkgs/tile-0.8.2/doc/xml/combobox.tmml +184 -0
  109. data/pkgs/tile-0.8.2/doc/xml/dialog.tmml +195 -0
  110. data/pkgs/tile-0.8.2/doc/xml/entry.tmml +630 -0
  111. data/pkgs/tile-0.8.2/doc/xml/frame.tmml +98 -0
  112. data/pkgs/tile-0.8.2/doc/xml/image.tmml +101 -0
  113. data/pkgs/tile-0.8.2/doc/xml/label.tmml +154 -0
  114. data/pkgs/tile-0.8.2/doc/xml/labelframe.tmml +116 -0
  115. data/pkgs/tile-0.8.2/doc/xml/menubutton.tmml +80 -0
  116. data/pkgs/tile-0.8.2/doc/xml/notebook.tmml +306 -0
  117. data/pkgs/tile-0.8.2/doc/xml/paned.tmml +154 -0
  118. data/pkgs/tile-0.8.2/doc/xml/progressbar.tmml +151 -0
  119. data/pkgs/tile-0.8.2/doc/xml/radiobutton.tmml +109 -0
  120. data/pkgs/tile-0.8.2/doc/xml/scrollbar.tmml +233 -0
  121. data/pkgs/tile-0.8.2/doc/xml/separator.tmml +59 -0
  122. data/pkgs/tile-0.8.2/doc/xml/sizegrip.tmml +82 -0
  123. data/pkgs/tile-0.8.2/doc/xml/style.tmml +171 -0
  124. data/pkgs/tile-0.8.2/doc/xml/tile-intro.tmml +192 -0
  125. data/pkgs/tile-0.8.2/doc/xml/treeview.tmml +604 -0
  126. data/pkgs/tile-0.8.2/doc/xml/widget.tmml +372 -0
  127. data/pkgs/tile-0.8.2/entry.o +0 -0
  128. data/pkgs/tile-0.8.2/frame.o +0 -0
  129. data/pkgs/tile-0.8.2/generic/Makefile.in +221 -0
  130. data/pkgs/tile-0.8.2/generic/TODO +493 -0
  131. data/pkgs/tile-0.8.2/generic/altTheme.c +1172 -0
  132. data/pkgs/tile-0.8.2/generic/blink.c +168 -0
  133. data/pkgs/tile-0.8.2/generic/button.c +858 -0
  134. data/pkgs/tile-0.8.2/generic/cache.c +354 -0
  135. data/pkgs/tile-0.8.2/generic/clamTheme.c +974 -0
  136. data/pkgs/tile-0.8.2/generic/classicTheme.c +518 -0
  137. data/pkgs/tile-0.8.2/generic/configure +10334 -0
  138. data/pkgs/tile-0.8.2/generic/configure.in +100 -0
  139. data/pkgs/tile-0.8.2/generic/entry.c +1922 -0
  140. data/pkgs/tile-0.8.2/generic/frame.c +648 -0
  141. data/pkgs/tile-0.8.2/generic/gunk.h +44 -0
  142. data/pkgs/tile-0.8.2/generic/image.c +416 -0
  143. data/pkgs/tile-0.8.2/generic/label.c +663 -0
  144. data/pkgs/tile-0.8.2/generic/layout.c +1215 -0
  145. data/pkgs/tile-0.8.2/generic/manager.c +554 -0
  146. data/pkgs/tile-0.8.2/generic/manager.h +91 -0
  147. data/pkgs/tile-0.8.2/generic/notebook.c +1380 -0
  148. data/pkgs/tile-0.8.2/generic/paned.c +958 -0
  149. data/pkgs/tile-0.8.2/generic/pkgIndex.tcl.in +7 -0
  150. data/pkgs/tile-0.8.2/generic/progress.c +549 -0
  151. data/pkgs/tile-0.8.2/generic/scale.c +526 -0
  152. data/pkgs/tile-0.8.2/generic/scroll.c +253 -0
  153. data/pkgs/tile-0.8.2/generic/scrollbar.c +346 -0
  154. data/pkgs/tile-0.8.2/generic/separator.c +132 -0
  155. data/pkgs/tile-0.8.2/generic/square.c +306 -0
  156. data/pkgs/tile-0.8.2/generic/tagset.c +147 -0
  157. data/pkgs/tile-0.8.2/generic/tile.c +296 -0
  158. data/pkgs/tile-0.8.2/generic/tkElements.c +1280 -0
  159. data/pkgs/tile-0.8.2/generic/tkTheme.c +1708 -0
  160. data/pkgs/tile-0.8.2/generic/tkTheme.h +419 -0
  161. data/pkgs/tile-0.8.2/generic/tkThemeInt.h +45 -0
  162. data/pkgs/tile-0.8.2/generic/tkstate.c +268 -0
  163. data/pkgs/tile-0.8.2/generic/trace.c +145 -0
  164. data/pkgs/tile-0.8.2/generic/track.c +174 -0
  165. data/pkgs/tile-0.8.2/generic/treeview.c +3211 -0
  166. data/pkgs/tile-0.8.2/generic/ttk.decls +154 -0
  167. data/pkgs/tile-0.8.2/generic/ttkDecls.h +340 -0
  168. data/pkgs/tile-0.8.2/generic/ttkStubInit.c +61 -0
  169. data/pkgs/tile-0.8.2/generic/ttkStubLib.c +70 -0
  170. data/pkgs/tile-0.8.2/generic/widget.c +785 -0
  171. data/pkgs/tile-0.8.2/generic/widget.h +263 -0
  172. data/pkgs/tile-0.8.2/image.o +0 -0
  173. data/pkgs/tile-0.8.2/label.o +0 -0
  174. data/pkgs/tile-0.8.2/layout.o +0 -0
  175. data/pkgs/tile-0.8.2/library/altTheme.tcl +101 -0
  176. data/pkgs/tile-0.8.2/library/aquaTheme.tcl +62 -0
  177. data/pkgs/tile-0.8.2/library/button.tcl +85 -0
  178. data/pkgs/tile-0.8.2/library/clamTheme.tcl +139 -0
  179. data/pkgs/tile-0.8.2/library/classicTheme.tcl +108 -0
  180. data/pkgs/tile-0.8.2/library/combobox.tcl +439 -0
  181. data/pkgs/tile-0.8.2/library/cursors.tcl +36 -0
  182. data/pkgs/tile-0.8.2/library/defaults.tcl +118 -0
  183. data/pkgs/tile-0.8.2/library/dialog.tcl +274 -0
  184. data/pkgs/tile-0.8.2/library/entry.tcl +580 -0
  185. data/pkgs/tile-0.8.2/library/fonts.tcl +153 -0
  186. data/pkgs/tile-0.8.2/library/icons.tcl +105 -0
  187. data/pkgs/tile-0.8.2/library/keynav.tcl +192 -0
  188. data/pkgs/tile-0.8.2/library/menubutton.tcl +171 -0
  189. data/pkgs/tile-0.8.2/library/notebook.tcl +193 -0
  190. data/pkgs/tile-0.8.2/library/paned.tcl +87 -0
  191. data/pkgs/tile-0.8.2/library/progress.tcl +51 -0
  192. data/pkgs/tile-0.8.2/library/scale.tcl +54 -0
  193. data/pkgs/tile-0.8.2/library/scrollbar.tcl +125 -0
  194. data/pkgs/tile-0.8.2/library/sizegrip.tcl +77 -0
  195. data/pkgs/tile-0.8.2/library/tile.tcl +211 -0
  196. data/pkgs/tile-0.8.2/library/treeview.tcl +382 -0
  197. data/pkgs/tile-0.8.2/library/utils.tcl +254 -0
  198. data/pkgs/tile-0.8.2/library/winTheme.tcl +77 -0
  199. data/pkgs/tile-0.8.2/library/xpTheme.tcl +63 -0
  200. data/pkgs/tile-0.8.2/libtile0.8.2.so +0 -0
  201. data/pkgs/tile-0.8.2/libttkstub.a +0 -0
  202. data/pkgs/tile-0.8.2/license.terms +24 -0
  203. data/pkgs/tile-0.8.2/macosx/aquaTheme.c +1076 -0
  204. data/pkgs/tile-0.8.2/manager.o +0 -0
  205. data/pkgs/tile-0.8.2/notebook.o +0 -0
  206. data/pkgs/tile-0.8.2/paned.o +0 -0
  207. data/pkgs/tile-0.8.2/pkgIndex.tcl +3 -0
  208. data/pkgs/tile-0.8.2/progress.o +0 -0
  209. data/pkgs/tile-0.8.2/scale.o +0 -0
  210. data/pkgs/tile-0.8.2/scroll.o +0 -0
  211. data/pkgs/tile-0.8.2/scrollbar.o +0 -0
  212. data/pkgs/tile-0.8.2/separator.o +0 -0
  213. data/pkgs/tile-0.8.2/tagset.o +0 -0
  214. data/pkgs/tile-0.8.2/tclconfig/install-sh +119 -0
  215. data/pkgs/tile-0.8.2/tclconfig/tcl.m4 +4069 -0
  216. data/pkgs/tile-0.8.2/tclconfig/teax.m4 +109 -0
  217. data/pkgs/tile-0.8.2/tests/all.tcl +18 -0
  218. data/pkgs/tile-0.8.2/tests/bwidget.test +103 -0
  219. data/pkgs/tile-0.8.2/tests/cbtest.tcl +125 -0
  220. data/pkgs/tile-0.8.2/tests/combobox.test +51 -0
  221. data/pkgs/tile-0.8.2/tests/compound.tcl +92 -0
  222. data/pkgs/tile-0.8.2/tests/entry.test +285 -0
  223. data/pkgs/tile-0.8.2/tests/entrytest.tcl +78 -0
  224. data/pkgs/tile-0.8.2/tests/image.test +94 -0
  225. data/pkgs/tile-0.8.2/tests/labelframe.tcl +41 -0
  226. data/pkgs/tile-0.8.2/tests/labelframe.test +137 -0
  227. data/pkgs/tile-0.8.2/tests/layout.test +33 -0
  228. data/pkgs/tile-0.8.2/tests/misc.test +35 -0
  229. data/pkgs/tile-0.8.2/tests/nbtest.tcl +66 -0
  230. data/pkgs/tile-0.8.2/tests/notebook.test +500 -0
  231. data/pkgs/tile-0.8.2/tests/paned.test +298 -0
  232. data/pkgs/tile-0.8.2/tests/progress.test +92 -0
  233. data/pkgs/tile-0.8.2/tests/pwtest.tcl +90 -0
  234. data/pkgs/tile-0.8.2/tests/sbtest.tcl +79 -0
  235. data/pkgs/tile-0.8.2/tests/scrollbar.test +77 -0
  236. data/pkgs/tile-0.8.2/tests/sgtest.tcl +52 -0
  237. data/pkgs/tile-0.8.2/tests/testutils.tcl +20 -0
  238. data/pkgs/tile-0.8.2/tests/tile.test +674 -0
  239. data/pkgs/tile-0.8.2/tests/treetags.test +78 -0
  240. data/pkgs/tile-0.8.2/tests/treeview.test +563 -0
  241. data/pkgs/tile-0.8.2/tests/tvtest.tcl +332 -0
  242. data/pkgs/tile-0.8.2/tests/validate.test +278 -0
  243. data/pkgs/tile-0.8.2/tile.o +0 -0
  244. data/pkgs/tile-0.8.2/tkElements.o +0 -0
  245. data/pkgs/tile-0.8.2/tkTheme.o +0 -0
  246. data/pkgs/tile-0.8.2/tkstate.o +0 -0
  247. data/pkgs/tile-0.8.2/tools/genStubs.tcl +861 -0
  248. data/pkgs/tile-0.8.2/trace.o +0 -0
  249. data/pkgs/tile-0.8.2/track.o +0 -0
  250. data/pkgs/tile-0.8.2/treeview.o +0 -0
  251. data/pkgs/tile-0.8.2/ttkStubInit.o +0 -0
  252. data/pkgs/tile-0.8.2/ttkStubLib.o +0 -0
  253. data/pkgs/tile-0.8.2/widget.o +0 -0
  254. data/pkgs/tile-0.8.2/win/Tile.dsp +261 -0
  255. data/pkgs/tile-0.8.2/win/makefile.vc +527 -0
  256. data/pkgs/tile-0.8.2/win/monitor.c +164 -0
  257. data/pkgs/tile-0.8.2/win/nmakehlp.c +483 -0
  258. data/pkgs/tile-0.8.2/win/rules.vc +512 -0
  259. data/pkgs/tile-0.8.2/win/tile.rc +40 -0
  260. data/pkgs/tile-0.8.2/win/winTheme.c +734 -0
  261. data/pkgs/tile-0.8.2/win/xpTheme.c +1029 -0
  262. data/spec/app_spec.rb +48 -0
  263. data/spec/customer_spec.rb +31 -0
  264. data/spec/fixtures/graph.expectation +18 -0
  265. data/spec/payment_spec.rb +19 -0
  266. data/spec/pratt_spec.rb +148 -0
  267. data/spec/project_spec.rb +163 -0
  268. data/spec/rcov.opts +0 -0
  269. data/spec/spec.opts +1 -0
  270. data/spec/spec_helper.rb +21 -0
  271. data/spec/whence_spec.rb +54 -0
  272. data/tasks/pratt.rb +84 -0
  273. data/templates/model.eruby +12 -0
  274. data/templates/spec.eruby +8 -0
  275. data/views/env.rb +22 -0
  276. data/views/graph.eruby +20 -0
  277. data/views/invoice.eruby +148 -0
  278. data/views/main.rb +92 -0
  279. data/views/pid.eruby +3 -0
  280. data/views/pop.rb +94 -0
  281. data/views/pop2.rb +75 -0
  282. data/views/raw.eruby +11 -0
  283. metadata +390 -0
@@ -0,0 +1,100 @@
1
+ #
2
+ # configure.in,v 1.51 2007/12/16 18:20:55 jenglish Exp
3
+ #
4
+ builtin(include, ../tclconfig/tcl.m4)
5
+ builtin(include, ../tclconfig/teax.m4)
6
+
7
+ AC_INIT([tile],[0.8.2])
8
+ AC_CONFIG_AUX_DIR(../tclconfig)
9
+ AC_REVISION(1.51)
10
+
11
+ # Usual Tcl stuff:
12
+ #
13
+ TEA_INIT([3.6])
14
+ TEA_PATH_TCLCONFIG
15
+ TEA_LOAD_TCLCONFIG
16
+ TEA_PATH_TKCONFIG
17
+ TEA_LOAD_TKCONFIG
18
+ TEA_PREFIX
19
+
20
+ dnl
21
+ dnl Alternative to TEA_SETUP_COMPILER:
22
+ dnl (TEA_SETUP_COMPILER is for building Tcl itself)
23
+ dnl
24
+ AC_PROG_CC
25
+ AC_PROG_INSTALL
26
+ AC_PROG_RANLIB
27
+ AC_OBJEXT
28
+
29
+ AC_ARG_ENABLE([private-headers],
30
+ AC_HELP_STRING(
31
+ [--disable-private-headers],
32
+ [Disable if private headers are unavailable]),
33
+ [have_private_headers=$enableval], [have_private_headers=yes])
34
+
35
+ AC_MSG_CHECKING([Did you ask for private headers?])
36
+ AC_MSG_RESULT(${have_private_headers})
37
+
38
+ if test ${have_private_headers} = "yes" ; then
39
+ TEA_MISSING_POSIX_HEADERS
40
+ TEA_PRIVATE_TCL_HEADERS
41
+ TEA_PRIVATE_TK_HEADERS
42
+ else
43
+ TEA_PUBLIC_TCL_HEADERS
44
+ TEA_PUBLIC_TK_HEADERS
45
+ AC_DEFINE(NO_PRIVATE_HEADERS)
46
+ fi
47
+
48
+ TEA_PROG_TCLSH
49
+ TEA_PROG_WISH
50
+
51
+ # Build stuff:
52
+ #
53
+ TEA_CONFIG_CFLAGS
54
+ TEA_PATH_X
55
+ dnl TEA_ENABLE_THREADS
56
+ TEA_ENABLE_SHARED
57
+ TEA_ENABLE_SYMBOLS
58
+
59
+ AC_DEFINE(USE_TCL_STUBS,1,[Use Tcl stub library])
60
+ AC_DEFINE(USE_TK_STUBS,1,[Use Tk stub library])
61
+ AC_DEFINE(BUILD_tile,1,[Source for tile package])
62
+
63
+ TEAX_CONFIG_LDFLAGS
64
+ TEAX_FIX_LIB_SPECS
65
+ TEAX_EXPAND_CFLAGS
66
+
67
+ # Platform-specific stuff:
68
+ # NB: With -DNO_PRIVATE_HEADERS, we need to link against libtk
69
+ # in addition to libtkstub, at least on Windows. We can get away
70
+ # without doing this on Unix.
71
+ #
72
+ case "${TEA_WINDOWINGSYSTEM}" in
73
+ win32)
74
+ PLATFORM_OBJS='$(WIN_OBJS)'
75
+ PKG_LIBS="${PKG_LIBS}"
76
+ if test ${have_private_headers} = "no" ; then
77
+ TEA_ADD_LIBS($TK_LIB_SPEC)
78
+ fi
79
+ TEA_ADD_LIBS([user32.lib gdi32.lib])
80
+ AC_CHECK_HEADER([uxtheme.h],
81
+ [AC_DEFINE(HAVE_UXTHEME_H,1,[XP uxtheme.h available])],
82
+ [AC_MSG_NOTICE([xpnative theme will be unavailable])],
83
+ [#include <windows.h>])
84
+ ;;
85
+ aqua)
86
+ PLATFORM_OBJS='$(MAC_OBJS)' ; # Ignore autoconf warning, it's bogus
87
+ PKG_LIBS="${PKG_LIBS} -framework Carbon"
88
+ ;;
89
+ x11)
90
+ PLATFORM_OBJS='$(X11_OBJS)'
91
+ ;;
92
+ esac;
93
+ AC_SUBST(PLATFORM_OBJS)
94
+
95
+ #--------------------------------------------------------------------
96
+
97
+ AC_CONFIG_FILES([Makefile pkgIndex.tcl])
98
+ AC_OUTPUT
99
+
100
+ #*EOF*
@@ -0,0 +1,1922 @@
1
+ /*
2
+ * entry.c,v 1.46 2007/05/18 21:50:49 jenglish Exp
3
+ *
4
+ * DERIVED FROM: tk/generic/tkEntry.c r1.35.
5
+ *
6
+ * Copyright (c) 1990-1994 The Regents of the University of California.
7
+ * Copyright (c) 1994-1997 Sun Microsystems, Inc.
8
+ * Copyright (c) 2000 Ajuba Solutions.
9
+ * Copyright (c) 2002 ActiveState Corporation.
10
+ * Copyright (c) 2004 Joe English
11
+ */
12
+
13
+ #include <string.h>
14
+ #include <tk.h>
15
+ #include <X11/Xatom.h>
16
+
17
+ #include "tkTheme.h"
18
+ #include "widget.h"
19
+
20
+ /*
21
+ * Extra bits for core.flags:
22
+ */
23
+ #define GOT_SELECTION (WIDGET_USER_FLAG<<1)
24
+ #define SYNCING_VARIABLE (WIDGET_USER_FLAG<<2)
25
+ #define VALIDATING (WIDGET_USER_FLAG<<3)
26
+ #define VALIDATION_SET_VALUE (WIDGET_USER_FLAG<<4)
27
+
28
+ /*
29
+ * Definitions for -validate option values:
30
+ */
31
+ typedef enum validateMode {
32
+ VMODE_ALL, VMODE_KEY, VMODE_FOCUS, VMODE_FOCUSIN, VMODE_FOCUSOUT, VMODE_NONE
33
+ } VMODE;
34
+
35
+ static const char *validateStrings[] = {
36
+ "all", "key", "focus", "focusin", "focusout", "none", NULL
37
+ };
38
+
39
+ /*
40
+ * Validation reasons:
41
+ */
42
+ typedef enum validateReason {
43
+ VALIDATE_INSERT, VALIDATE_DELETE,
44
+ VALIDATE_FOCUSIN, VALIDATE_FOCUSOUT,
45
+ VALIDATE_FORCED
46
+ } VREASON;
47
+
48
+ static const char *validateReasonStrings[] = {
49
+ "key", "key", "focusin", "focusout", "forced", NULL
50
+ };
51
+
52
+ /*------------------------------------------------------------------------
53
+ * +++ Entry widget record.
54
+ *
55
+ * Dependencies:
56
+ *
57
+ * textVariableTrace : textVariableObj
58
+ *
59
+ * numBytes,numChars : string
60
+ * displayString : numChars, showChar
61
+ * layoutHeight,
62
+ * layoutWidth,
63
+ * textLayout : fontObj, displayString
64
+ * layoutX, layoutY : textLayout, justify, xscroll.first
65
+ *
66
+ * Invariants:
67
+ *
68
+ * 0 <= insertPos <= numChars
69
+ * 0 <= selectFirst < selectLast <= numChars || selectFirst == selectLast == -1
70
+ * displayString points to string if showChar == NULL,
71
+ * or to malloc'ed storage if showChar != NULL.
72
+ */
73
+
74
+ /* Style parameters:
75
+ */
76
+ typedef struct
77
+ {
78
+ Tcl_Obj *foregroundObj; /* Foreground color for normal text */
79
+ Tcl_Obj *backgroundObj; /* Entry widget background color */
80
+ Tcl_Obj *selBorderObj; /* Border and background for selection */
81
+ Tcl_Obj *selBorderWidthObj; /* Width of selection border */
82
+ Tcl_Obj *selForegroundObj; /* Foreground color for selected text */
83
+ Tcl_Obj *insertColorObj; /* Color of insertion cursor */
84
+ Tcl_Obj *insertWidthObj; /* Insert cursor width */
85
+ } EntryStyleData;
86
+
87
+ typedef struct
88
+ {
89
+ /*
90
+ * Internal state:
91
+ */
92
+ char *string; /* Storage for string (malloced) */
93
+ int numBytes; /* Length of string in bytes. */
94
+ int numChars; /* Length of string in characters. */
95
+
96
+ int insertPos; /* Insert index */
97
+ int selectFirst; /* Index of start of selection, or -1 */
98
+ int selectLast; /* Index of end of selection, or -1 */
99
+
100
+ Scrollable xscroll; /* Current scroll position */
101
+ ScrollHandle xscrollHandle;
102
+
103
+ /*
104
+ * Options managed by Tk_SetOptions:
105
+ */
106
+ Tcl_Obj *textVariableObj; /* Name of linked variable */
107
+ int exportSelection; /* Tie internal selection to X selection? */
108
+
109
+ VMODE validate; /* Validation mode */
110
+ char *validateCmd; /* Validation script template */
111
+ char *invalidCmd; /* Invalid callback script template */
112
+
113
+ char *showChar; /* Used to derive displayString */
114
+
115
+ Tcl_Obj *fontObj; /* Text font to use */
116
+ Tcl_Obj *widthObj; /* Desired width of window (in avgchars) */
117
+ Tk_Justify justify; /* Text justification */
118
+
119
+ EntryStyleData styleData; /* Display style data (widget options) */
120
+ EntryStyleData styleDefaults;/* Style defaults (fallback values) */
121
+
122
+ Tcl_Obj *stateObj; /* Compatibility option -- see CheckStateObj */
123
+
124
+ /*
125
+ * Derived resources:
126
+ */
127
+ Ttk_TraceHandle *textVariableTrace;
128
+
129
+ char *displayString; /* String to use when displaying */
130
+ Tk_TextLayout textLayout; /* Cached text layout information. */
131
+ int layoutWidth; /* textLayout width */
132
+ int layoutHeight; /* textLayout height */
133
+
134
+ int layoutX, layoutY; /* Origin for text layout. */
135
+
136
+ } EntryPart;
137
+
138
+ typedef struct
139
+ {
140
+ WidgetCore core;
141
+ EntryPart entry;
142
+ } Entry;
143
+
144
+ /*
145
+ * Extra mask bits for Tk_SetOptions()
146
+ */
147
+ #define STATE_CHANGED (0x100) /* -state option changed */
148
+ #define TEXTVAR_CHANGED (0x200) /* -textvariable option changed */
149
+ #define SCROLLCMD_CHANGED (0x400) /* -xscrollcommand option changed */
150
+
151
+ /*
152
+ * Default option values:
153
+ */
154
+ #define DEF_SELECT_BG "#000000"
155
+ #define DEF_SELECT_FG "#ffffff"
156
+ #define DEF_INSERT_BG "black"
157
+ #define DEF_ENTRY_WIDTH "20"
158
+ #define DEF_ENTRY_FONT "TkTextFont"
159
+ #define DEF_LIST_HEIGHT "10"
160
+
161
+ static Tk_OptionSpec EntryOptionSpecs[] =
162
+ {
163
+ WIDGET_TAKES_FOCUS,
164
+
165
+ {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection",
166
+ "ExportSelection", "1", -1, Tk_Offset(Entry, entry.exportSelection),
167
+ 0,0,0 },
168
+ {TK_OPTION_FONT, "-font", "font", "Font",
169
+ DEF_ENTRY_FONT, Tk_Offset(Entry, entry.fontObj),-1,
170
+ 0,0,GEOMETRY_CHANGED},
171
+ {TK_OPTION_STRING, "-invalidcommand", "invalidCommand", "InvalidCommand",
172
+ NULL, -1, Tk_Offset(Entry, entry.invalidCmd),
173
+ TK_OPTION_NULL_OK, 0, 0},
174
+ {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
175
+ "left", -1, Tk_Offset(Entry, entry.justify),
176
+ 0, 0, GEOMETRY_CHANGED},
177
+ {TK_OPTION_STRING, "-show", "show", "Show",
178
+ NULL, -1, Tk_Offset(Entry, entry.showChar),
179
+ TK_OPTION_NULL_OK, 0, 0},
180
+ {TK_OPTION_STRING, "-state", "state", "State",
181
+ "normal", Tk_Offset(Entry, entry.stateObj), -1,
182
+ 0,0,STATE_CHANGED},
183
+ {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
184
+ NULL, Tk_Offset(Entry, entry.textVariableObj), -1,
185
+ TK_OPTION_NULL_OK,0,TEXTVAR_CHANGED},
186
+ {TK_OPTION_STRING_TABLE, "-validate", "validate", "Validate",
187
+ "none", -1, Tk_Offset(Entry, entry.validate),
188
+ 0, (ClientData) validateStrings, 0},
189
+ {TK_OPTION_STRING, "-validatecommand", "validateCommand", "ValidateCommand",
190
+ NULL, -1, Tk_Offset(Entry, entry.validateCmd),
191
+ TK_OPTION_NULL_OK, 0, 0},
192
+ {TK_OPTION_INT, "-width", "width", "Width",
193
+ DEF_ENTRY_WIDTH, Tk_Offset(Entry, entry.widthObj), -1,
194
+ 0,0,GEOMETRY_CHANGED},
195
+ {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
196
+ NULL, -1, Tk_Offset(Entry, entry.xscroll.scrollCmd),
197
+ TK_OPTION_NULL_OK, 0, SCROLLCMD_CHANGED},
198
+
199
+ /* EntryStyleData options:
200
+ */
201
+ {TK_OPTION_COLOR, "-foreground", "textColor", "TextColor",
202
+ NULL, Tk_Offset(Entry, entry.styleData.foregroundObj), -1,
203
+ TK_OPTION_NULL_OK,0,0},
204
+ {TK_OPTION_COLOR, "-background", "windowColor", "WindowColor",
205
+ NULL, Tk_Offset(Entry, entry.styleData.backgroundObj), -1,
206
+ TK_OPTION_NULL_OK,0,0},
207
+
208
+ WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
209
+ };
210
+
211
+ /*------------------------------------------------------------------------
212
+ * +++ EntryStyleData management.
213
+ * This is still more awkward than it should be;
214
+ * it should be able to use the Element API instead.
215
+ */
216
+
217
+ /* EntryInitStyleDefaults --
218
+ * Initialize EntryStyleData record to fallback values.
219
+ */
220
+ static void EntryInitStyleDefaults(EntryStyleData *es)
221
+ {
222
+ #define INIT(member, value) \
223
+ es->member = Tcl_NewStringObj(value, -1); \
224
+ Tcl_IncrRefCount(es->member);
225
+ INIT(foregroundObj, DEFAULT_FOREGROUND)
226
+ INIT(selBorderObj, DEF_SELECT_BG)
227
+ INIT(selForegroundObj, DEF_SELECT_FG)
228
+ INIT(insertColorObj, DEFAULT_FOREGROUND)
229
+ INIT(selBorderWidthObj, "0")
230
+ INIT(insertWidthObj, "1")
231
+ #undef INIT
232
+ }
233
+
234
+ static void EntryFreeStyleDefaults(EntryStyleData *es)
235
+ {
236
+ Tcl_DecrRefCount(es->foregroundObj);
237
+ Tcl_DecrRefCount(es->selBorderObj);
238
+ Tcl_DecrRefCount(es->selForegroundObj);
239
+ Tcl_DecrRefCount(es->insertColorObj);
240
+ Tcl_DecrRefCount(es->selBorderWidthObj);
241
+ Tcl_DecrRefCount(es->insertWidthObj);
242
+ }
243
+
244
+ /*
245
+ * EntryInitStyleData --
246
+ * Look up style-specific data for an entry widget.
247
+ */
248
+ static void EntryInitStyleData(Entry *entryPtr, EntryStyleData *es)
249
+ {
250
+ Ttk_State state = entryPtr->core.state;
251
+ Ttk_ResourceCache cache = Ttk_GetResourceCache(entryPtr->core.interp);
252
+ Tk_Window tkwin = entryPtr->core.tkwin;
253
+ Tcl_Obj *tmp;
254
+
255
+ /* Initialize to fallback values:
256
+ */
257
+ *es = entryPtr->entry.styleDefaults;
258
+
259
+ # define INIT(member, name) \
260
+ if ((tmp=Ttk_QueryOption(entryPtr->core.layout,name,state))) \
261
+ es->member=tmp;
262
+ INIT(foregroundObj, "-foreground");
263
+ INIT(selBorderObj, "-selectbackground")
264
+ INIT(selBorderWidthObj, "-selectborderwidth")
265
+ INIT(selForegroundObj, "-selectforeground")
266
+ INIT(insertColorObj, "-insertcolor")
267
+ INIT(insertWidthObj, "-insertwidth")
268
+ #undef INIT
269
+
270
+ /* Reacquire color & border resources from resource cache.
271
+ */
272
+ es->foregroundObj = Ttk_UseColor(cache, tkwin, es->foregroundObj);
273
+ es->selForegroundObj = Ttk_UseColor(cache, tkwin, es->selForegroundObj);
274
+ es->insertColorObj = Ttk_UseColor(cache, tkwin, es->insertColorObj);
275
+ es->selBorderObj = Ttk_UseBorder(cache, tkwin, es->selBorderObj);
276
+ }
277
+
278
+ /*------------------------------------------------------------------------
279
+ * +++ Resource management.
280
+ */
281
+
282
+ /* EntryDisplayString --
283
+ * Return a malloc'ed string consisting of 'numChars' copies
284
+ * of (the first character in the string) 'showChar'.
285
+ * Used to compute the displayString if -show is non-NULL.
286
+ */
287
+ static char *EntryDisplayString(const char *showChar, int numChars)
288
+ {
289
+ char *displayString, *p;
290
+ int size;
291
+ Tcl_UniChar ch;
292
+ char buf[TCL_UTF_MAX];
293
+
294
+ Tcl_UtfToUniChar(showChar, &ch);
295
+ size = Tcl_UniCharToUtf(ch, buf);
296
+ p = displayString = ckalloc(numChars * size + 1);
297
+
298
+ while (numChars--) {
299
+ p += Tcl_UniCharToUtf(ch, p);
300
+ }
301
+ *p = '\0';
302
+
303
+ return displayString;
304
+ }
305
+
306
+ /* EntryUpdateTextLayout --
307
+ * Recompute textLayout, layoutWidth, and layoutHeight
308
+ * from displayString and fontObj.
309
+ */
310
+ static void EntryUpdateTextLayout(Entry *entryPtr)
311
+ {
312
+ Tk_FreeTextLayout(entryPtr->entry.textLayout);
313
+ entryPtr->entry.textLayout = Tk_ComputeTextLayout(
314
+ Tk_GetFontFromObj(entryPtr->core.tkwin, entryPtr->entry.fontObj),
315
+ entryPtr->entry.displayString, entryPtr->entry.numChars,
316
+ 0/*wraplength*/, entryPtr->entry.justify, TK_IGNORE_NEWLINES,
317
+ &entryPtr->entry.layoutWidth, &entryPtr->entry.layoutHeight);
318
+ }
319
+
320
+ /* EntryEditable --
321
+ * Returns 1 if the entry widget accepts user changes, 0 otherwise
322
+ */
323
+ static int
324
+ EntryEditable(Entry *entryPtr)
325
+ {
326
+ return !(entryPtr->core.state & (TTK_STATE_DISABLED|TTK_STATE_READONLY));
327
+ }
328
+
329
+ /*------------------------------------------------------------------------
330
+ * +++ Selection management.
331
+ */
332
+
333
+ /* EntryFetchSelection --
334
+ * Selection handler for entry widgets.
335
+ */
336
+ static int
337
+ EntryFetchSelection(
338
+ ClientData clientData, int offset, char *buffer, int maxBytes)
339
+ {
340
+ Entry *entryPtr = (Entry *) clientData;
341
+ size_t byteCount;
342
+ const char *string;
343
+ const char *selStart, *selEnd;
344
+
345
+ if (entryPtr->entry.selectFirst < 0 || !entryPtr->entry.exportSelection) {
346
+ return -1;
347
+ }
348
+ string = entryPtr->entry.displayString;
349
+
350
+ selStart = Tcl_UtfAtIndex(string, entryPtr->entry.selectFirst);
351
+ selEnd = Tcl_UtfAtIndex(selStart,
352
+ entryPtr->entry.selectLast - entryPtr->entry.selectFirst);
353
+ byteCount = selEnd - selStart - offset;
354
+ if (byteCount > (size_t)maxBytes) {
355
+ /* @@@POSSIBLE BUG: Can transfer partial UTF-8 sequences. Is this OK? */
356
+ byteCount = maxBytes;
357
+ }
358
+ if (byteCount <= 0) {
359
+ return 0;
360
+ }
361
+ memcpy(buffer, selStart + offset, byteCount);
362
+ buffer[byteCount] = '\0';
363
+ return byteCount;
364
+ }
365
+
366
+ /* EntryLostSelection --
367
+ * Tk_LostSelProc for Entry widgets; called when an entry
368
+ * loses ownership of the selection.
369
+ */
370
+ static void EntryLostSelection(ClientData clientData)
371
+ {
372
+ Entry *entryPtr = (Entry *) clientData;
373
+ entryPtr->core.flags &= ~GOT_SELECTION;
374
+ entryPtr->entry.selectFirst = entryPtr->entry.selectLast = -1;
375
+ TtkRedisplayWidget(&entryPtr->core);
376
+ }
377
+
378
+ /* EntryOwnSelection --
379
+ * Assert ownership of the PRIMARY selection,
380
+ * if -exportselection set and selection is present.
381
+ */
382
+ static void EntryOwnSelection(Entry *entryPtr)
383
+ {
384
+ if (entryPtr->entry.exportSelection
385
+ && !(entryPtr->core.flags & GOT_SELECTION)) {
386
+ Tk_OwnSelection(entryPtr->core.tkwin, XA_PRIMARY, EntryLostSelection,
387
+ (ClientData) entryPtr);
388
+ entryPtr->core.flags |= GOT_SELECTION;
389
+ }
390
+ }
391
+
392
+ /*------------------------------------------------------------------------
393
+ * +++ Validation.
394
+ */
395
+
396
+ /* ExpandPercents --
397
+ * Expand an entry validation script template (-validatecommand
398
+ * or -invalidcommand).
399
+ */
400
+ static void
401
+ ExpandPercents(
402
+ Entry *entryPtr, /* Entry that needs validation. */
403
+ const char *template, /* Script template */
404
+ const char *new, /* Potential new value of entry string */
405
+ int index, /* index of insert/delete */
406
+ int count, /* #changed characters */
407
+ VREASON reason, /* Reason for change */
408
+ Tcl_DString *dsPtr) /* Result of %-substitutions */
409
+ {
410
+ int spaceNeeded, cvtFlags;
411
+ int number, length;
412
+ const char *string;
413
+ int stringLength;
414
+ Tcl_UniChar ch;
415
+ char numStorage[2*TCL_INTEGER_SPACE];
416
+
417
+ while (*template) {
418
+ /* Find everything up to the next % character and append it
419
+ * to the result string.
420
+ */
421
+ string = Tcl_UtfFindFirst(template, '%');
422
+ if (string == NULL) {
423
+ /* No more %-sequences to expand.
424
+ * Copy the rest of the template.
425
+ */
426
+ Tcl_DStringAppend(dsPtr, template, -1);
427
+ return;
428
+ }
429
+ if (string != template) {
430
+ Tcl_DStringAppend(dsPtr, template, string - template);
431
+ template = string;
432
+ }
433
+
434
+ /* There's a percent sequence here. Process it.
435
+ */
436
+ ++template; /* skip over % */
437
+ if (*template != '\0') {
438
+ template += Tcl_UtfToUniChar(template, &ch);
439
+ } else {
440
+ ch = '%';
441
+ }
442
+
443
+ stringLength = -1;
444
+ switch (ch) {
445
+ case 'd': /* Type of call that caused validation */
446
+ if (reason == VALIDATE_INSERT) {
447
+ number = 1;
448
+ } else if (reason == VALIDATE_DELETE) {
449
+ number = 0;
450
+ } else {
451
+ number = -1;
452
+ }
453
+ sprintf(numStorage, "%d", number);
454
+ string = numStorage;
455
+ break;
456
+ case 'i': /* index of insert/delete */
457
+ sprintf(numStorage, "%d", index);
458
+ string = numStorage;
459
+ break;
460
+ case 'P': /* 'Peeked' new value of the string */
461
+ string = new;
462
+ break;
463
+ case 's': /* Current string value */
464
+ string = entryPtr->entry.string;
465
+ break;
466
+ case 'S': /* string to be inserted/deleted, if any */
467
+ if (reason == VALIDATE_INSERT) {
468
+ string = Tcl_UtfAtIndex(new, index);
469
+ stringLength = Tcl_UtfAtIndex(string, count) - string;
470
+ } else if (reason == VALIDATE_DELETE) {
471
+ string = Tcl_UtfAtIndex(entryPtr->entry.string, index);
472
+ stringLength = Tcl_UtfAtIndex(string, count) - string;
473
+ } else {
474
+ string = "";
475
+ stringLength = 0;
476
+ }
477
+ break;
478
+ case 'v': /* type of validation currently set */
479
+ string = validateStrings[entryPtr->entry.validate];
480
+ break;
481
+ case 'V': /* type of validation in effect */
482
+ string = validateReasonStrings[reason];
483
+ break;
484
+ case 'W': /* widget name */
485
+ string = Tk_PathName(entryPtr->core.tkwin);
486
+ break;
487
+ default:
488
+ length = Tcl_UniCharToUtf(ch, numStorage);
489
+ numStorage[length] = '\0';
490
+ string = numStorage;
491
+ break;
492
+ }
493
+
494
+ spaceNeeded = Tcl_ScanCountedElement(string, stringLength, &cvtFlags);
495
+ length = Tcl_DStringLength(dsPtr);
496
+ Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
497
+ spaceNeeded = Tcl_ConvertCountedElement(string, stringLength,
498
+ Tcl_DStringValue(dsPtr) + length,
499
+ cvtFlags | TCL_DONT_USE_BRACES);
500
+ Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
501
+ }
502
+ }
503
+
504
+ /* RunValidationScript --
505
+ * Build and evaluate an entry validation script.
506
+ * If the script raises an error, disable validation
507
+ * by setting '-validate none'
508
+ */
509
+ static int RunValidationScript(
510
+ Tcl_Interp *interp, /* Interpreter to use */
511
+ Entry *entryPtr, /* Entry being validated */
512
+ const char *template, /* Script template */
513
+ const char *optionName, /* "-validatecommand", "-invalidcommand" */
514
+ const char *new, /* Potential new value of entry string */
515
+ int index, /* index of insert/delete */
516
+ int count, /* #changed characters */
517
+ VREASON reason) /* Reason for change */
518
+ {
519
+ Tcl_DString script;
520
+ int code;
521
+
522
+ Tcl_DStringInit(&script);
523
+ ExpandPercents(entryPtr, template, new, index, count, reason, &script);
524
+ code = Tcl_EvalEx(interp,
525
+ Tcl_DStringValue(&script), Tcl_DStringLength(&script),
526
+ TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
527
+ Tcl_DStringFree(&script);
528
+ if (WidgetDestroyed(&entryPtr->core))
529
+ return TCL_ERROR;
530
+
531
+ if (code != TCL_OK && code != TCL_RETURN) {
532
+ Tcl_AddErrorInfo(interp, "\n\t(in ");
533
+ Tcl_AddErrorInfo(interp, optionName);
534
+ Tcl_AddErrorInfo(interp, " validation command executed by ");
535
+ Tcl_AddErrorInfo(interp, Tk_PathName(entryPtr->core.tkwin));
536
+ Tcl_AddErrorInfo(interp, ")");
537
+ entryPtr->entry.validate = VMODE_NONE;
538
+ return TCL_ERROR;
539
+ }
540
+ return TCL_OK;
541
+ }
542
+
543
+ /* EntryNeedsValidation --
544
+ * Determine whether the specified VREASON should trigger validation
545
+ * in the current VMODE.
546
+ */
547
+ static int EntryNeedsValidation(VMODE vmode, VREASON reason)
548
+ {
549
+ return (reason == VALIDATE_FORCED)
550
+ || (vmode == VMODE_ALL)
551
+ || (reason == VALIDATE_FOCUSIN
552
+ && (vmode == VMODE_FOCUSIN || vmode == VMODE_FOCUS))
553
+ || (reason == VALIDATE_FOCUSOUT
554
+ && (vmode == VMODE_FOCUSOUT || vmode == VMODE_FOCUS))
555
+ || (reason == VALIDATE_INSERT && vmode == VMODE_KEY)
556
+ || (reason == VALIDATE_DELETE && vmode == VMODE_KEY)
557
+ ;
558
+ }
559
+
560
+ /* EntryValidateChange --
561
+ * Validate a proposed change to the entry widget's value if required.
562
+ * Call the -invalidcommand if validation fails.
563
+ *
564
+ * Returns:
565
+ * TCL_OK if the change is accepted
566
+ * TCL_BREAK if the change is rejected
567
+ * TCL_ERROR if any errors occured
568
+ *
569
+ * The change will be rejected if -validatecommand returns 0,
570
+ * or if -validatecommand or -invalidcommand modifies the value.
571
+ */
572
+ static int
573
+ EntryValidateChange(
574
+ Entry *entryPtr, /* Entry that needs validation. */
575
+ const char *newValue, /* Potential new value of entry string */
576
+ int index, /* index of insert/delete, -1 otherwise */
577
+ int count, /* #changed characters */
578
+ VREASON reason) /* Reason for change */
579
+ {
580
+ Tcl_Interp *interp = entryPtr->core.interp;
581
+ VMODE vmode = entryPtr->entry.validate;
582
+ int code, change_ok;
583
+
584
+ if ( (entryPtr->entry.validateCmd == NULL)
585
+ || (entryPtr->core.flags & VALIDATING)
586
+ || !EntryNeedsValidation(vmode, reason) )
587
+ {
588
+ return TCL_OK;
589
+ }
590
+
591
+ entryPtr->core.flags |= VALIDATING;
592
+
593
+ /* Run -validatecommand and check return value:
594
+ */
595
+ code = RunValidationScript(interp, entryPtr,
596
+ entryPtr->entry.validateCmd, "-validatecommand",
597
+ newValue, index, count, reason);
598
+ if (code != TCL_OK) {
599
+ goto done;
600
+ }
601
+
602
+ code = Tcl_GetBooleanFromObj(interp,Tcl_GetObjResult(interp), &change_ok);
603
+ if (code != TCL_OK) {
604
+ entryPtr->entry.validate = VMODE_NONE; /* Disable validation */
605
+ Tcl_AddErrorInfo(interp,
606
+ "\n(validation command did not return valid boolean)");
607
+ goto done;
608
+ }
609
+
610
+ /* Run the -invalidcommand if validation failed:
611
+ */
612
+ if (!change_ok && entryPtr->entry.invalidCmd != NULL) {
613
+ code = RunValidationScript(interp, entryPtr,
614
+ entryPtr->entry.invalidCmd, "-invalidcommand",
615
+ newValue, index, count, reason);
616
+ if (code != TCL_OK) {
617
+ goto done;
618
+ }
619
+ }
620
+
621
+ /* Reject the pending change if validation failed
622
+ * or if a validation script changed the value.
623
+ */
624
+ if (!change_ok || (entryPtr->core.flags & VALIDATION_SET_VALUE)) {
625
+ code = TCL_BREAK;
626
+ }
627
+
628
+ done:
629
+ entryPtr->core.flags &= ~(VALIDATING|VALIDATION_SET_VALUE);
630
+ return code;
631
+ }
632
+
633
+ /* EntryRevalidate --
634
+ * Revalidate the current value of an entry widget,
635
+ * update the TTK_STATE_INVALID bit.
636
+ *
637
+ * Returns:
638
+ * TCL_OK if valid, TCL_BREAK if invalid, TCL_ERROR on error.
639
+ */
640
+ static int EntryRevalidate(Tcl_Interp *interp, Entry *entryPtr, VREASON reason)
641
+ {
642
+ int code = EntryValidateChange(
643
+ entryPtr, entryPtr->entry.string, -1,0, reason);
644
+
645
+ if (code == TCL_BREAK) {
646
+ TtkWidgetChangeState(&entryPtr->core, TTK_STATE_INVALID, 0);
647
+ } else if (code == TCL_OK) {
648
+ TtkWidgetChangeState(&entryPtr->core, 0, TTK_STATE_INVALID);
649
+ }
650
+
651
+ return code;
652
+ }
653
+
654
+ /* EntryRevalidateBG --
655
+ * Revalidate in the background (called from event handler).
656
+ */
657
+ static void EntryRevalidateBG(Entry *entryPtr, VREASON reason)
658
+ {
659
+ Tcl_Interp *interp = entryPtr->core.interp;
660
+ if (EntryRevalidate(interp, entryPtr, reason) == TCL_ERROR) {
661
+ Tcl_BackgroundError(interp);
662
+ }
663
+ }
664
+
665
+ /*------------------------------------------------------------------------
666
+ * +++ Entry widget modification.
667
+ */
668
+
669
+ /* AdjustIndex --
670
+ * Adjust index to account for insertion (nChars > 0)
671
+ * or deletion (nChars < 0) at specified index.
672
+ */
673
+ static int AdjustIndex(int i0, int index, int nChars)
674
+ {
675
+ if (i0 >= index) {
676
+ i0 += nChars;
677
+ if (i0 < index) { /* index was inside deleted range */
678
+ i0 = index;
679
+ }
680
+ }
681
+ return i0;
682
+ }
683
+
684
+ /* AdjustIndices --
685
+ * Adjust all internal entry indexes to account for change.
686
+ * Note that insertPos, and selectFirst have "right gravity",
687
+ * while leftIndex (=xscroll.first) and selectLast have "left gravity".
688
+ */
689
+ static void AdjustIndices(Entry *entryPtr, int index, int nChars)
690
+ {
691
+ EntryPart *e = &entryPtr->entry;
692
+ int g = nChars > 0; /* left gravity adjustment */
693
+
694
+ e->insertPos = AdjustIndex(e->insertPos, index, nChars);
695
+ e->selectFirst = AdjustIndex(e->selectFirst, index, nChars);
696
+ e->selectLast = AdjustIndex(e->selectLast, index+g, nChars);
697
+ e->xscroll.first= AdjustIndex(e->xscroll.first, index+g, nChars);
698
+
699
+ if (e->selectLast <= e->selectFirst)
700
+ e->selectFirst = e->selectLast = -1;
701
+ }
702
+
703
+ /* EntryStoreValue --
704
+ * Replace the contents of a text entry with a given value,
705
+ * recompute dependent resources, and schedule a redisplay.
706
+ *
707
+ * See also: EntrySetValue().
708
+ */
709
+ static void
710
+ EntryStoreValue(Entry *entryPtr, const char *value)
711
+ {
712
+ size_t numBytes = strlen(value);
713
+ int numChars = Tcl_NumUtfChars(value, numBytes);
714
+
715
+ if (entryPtr->core.flags & VALIDATING)
716
+ entryPtr->core.flags |= VALIDATION_SET_VALUE;
717
+
718
+ /* Make sure all indices remain in bounds:
719
+ */
720
+ if (numChars < entryPtr->entry.numChars)
721
+ AdjustIndices(entryPtr, numChars, numChars - entryPtr->entry.numChars);
722
+
723
+ /* Free old value:
724
+ */
725
+ if (entryPtr->entry.displayString != entryPtr->entry.string)
726
+ ckfree(entryPtr->entry.displayString);
727
+ ckfree(entryPtr->entry.string);
728
+
729
+ /* Store new value:
730
+ */
731
+ entryPtr->entry.string = ckalloc(numBytes + 1);
732
+ strcpy(entryPtr->entry.string, value);
733
+ entryPtr->entry.numBytes = numBytes;
734
+ entryPtr->entry.numChars = numChars;
735
+
736
+ entryPtr->entry.displayString
737
+ = entryPtr->entry.showChar
738
+ ? EntryDisplayString(entryPtr->entry.showChar, numChars)
739
+ : entryPtr->entry.string
740
+ ;
741
+
742
+ /* Update layout, schedule redisplay:
743
+ */
744
+ EntryUpdateTextLayout(entryPtr);
745
+ TtkRedisplayWidget(&entryPtr->core);
746
+ }
747
+
748
+ /* EntrySetValue --
749
+ * Stores a new value in the entry widget and updates the
750
+ * linked -textvariable, if any. The write trace on the
751
+ * text variable is temporarily disabled; however, other
752
+ * write traces may change the value of the variable.
753
+ * If so, the widget is updated again with the new value.
754
+ *
755
+ * Returns:
756
+ * TCL_OK if successful, TCL_ERROR otherwise.
757
+ */
758
+ static int EntrySetValue(Entry *entryPtr, const char *value)
759
+ {
760
+ EntryStoreValue(entryPtr, value);
761
+
762
+ if (entryPtr->entry.textVariableObj) {
763
+ const char *textVarName =
764
+ Tcl_GetString(entryPtr->entry.textVariableObj);
765
+ if (textVarName && *textVarName) {
766
+ entryPtr->core.flags |= SYNCING_VARIABLE;
767
+ value = Tcl_SetVar(entryPtr->core.interp, textVarName,
768
+ value, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG);
769
+ entryPtr->core.flags &= ~SYNCING_VARIABLE;
770
+ if (!value || WidgetDestroyed(&entryPtr->core)) {
771
+ return TCL_ERROR;
772
+ } else if (strcmp(value, entryPtr->entry.string) != 0) {
773
+ /* Some write trace has changed the variable value.
774
+ */
775
+ EntryStoreValue(entryPtr, value);
776
+ }
777
+ }
778
+ }
779
+
780
+ return TCL_OK;
781
+ }
782
+
783
+ /* EntryTextVariableTrace --
784
+ * Variable trace procedure for entry -textvariable
785
+ */
786
+ static void EntryTextVariableTrace(void *recordPtr, const char *value)
787
+ {
788
+ Entry *entryPtr = recordPtr;
789
+
790
+ if (WidgetDestroyed(&entryPtr->core)) {
791
+ return;
792
+ }
793
+
794
+ if (entryPtr->core.flags & SYNCING_VARIABLE) {
795
+ /* Trace was fired due to Tcl_SetVar call in EntrySetValue.
796
+ * Don't do anything.
797
+ */
798
+ return;
799
+ }
800
+
801
+ EntryStoreValue(entryPtr, value ? value : "");
802
+ }
803
+
804
+ /*------------------------------------------------------------------------
805
+ * +++ Insertion and deletion.
806
+ */
807
+
808
+ /* InsertChars --
809
+ * Add new characters to an entry widget.
810
+ */
811
+ static int
812
+ InsertChars(
813
+ Entry *entryPtr, /* Entry that is to get the new elements. */
814
+ int index, /* Insert before this index */
815
+ const char *value) /* New characters to add */
816
+ {
817
+ char *string = entryPtr->entry.string;
818
+ size_t byteIndex = Tcl_UtfAtIndex(string, index) - string;
819
+ size_t byteCount = strlen(value);
820
+ int charsAdded = Tcl_NumUtfChars(value, byteCount);
821
+ size_t newByteCount = entryPtr->entry.numBytes + byteCount + 1;
822
+ char *new;
823
+ int code;
824
+
825
+ if (byteCount == 0) {
826
+ return TCL_OK;
827
+ }
828
+
829
+ new = ckalloc(newByteCount);
830
+ memcpy(new, string, byteIndex);
831
+ strcpy(new + byteIndex, value);
832
+ strcpy(new + byteIndex + byteCount, string + byteIndex);
833
+
834
+ code = EntryValidateChange(
835
+ entryPtr, new, index, charsAdded, VALIDATE_INSERT);
836
+
837
+ if (code == TCL_OK) {
838
+ AdjustIndices(entryPtr, index, charsAdded);
839
+ code = EntrySetValue(entryPtr, new);
840
+ } else if (code == TCL_BREAK) {
841
+ code = TCL_OK;
842
+ }
843
+
844
+ ckfree(new);
845
+ return code;
846
+ }
847
+
848
+ /* DeleteChars --
849
+ * Remove one or more characters from an entry widget.
850
+ */
851
+ static int
852
+ DeleteChars(
853
+ Entry *entryPtr, /* Entry widget to modify. */
854
+ int index, /* Index of first character to delete. */
855
+ int count) /* How many characters to delete. */
856
+ {
857
+ char *string = entryPtr->entry.string;
858
+ size_t byteIndex, byteCount, newByteCount;
859
+ char *new;
860
+ int code;
861
+
862
+ if (index < 0) {
863
+ index = 0;
864
+ }
865
+ if (count > entryPtr->entry.numChars - index) {
866
+ count = entryPtr->entry.numChars - index;
867
+ }
868
+ if (count <= 0) {
869
+ return TCL_OK;
870
+ }
871
+
872
+ byteIndex = Tcl_UtfAtIndex(string, index) - string;
873
+ byteCount = Tcl_UtfAtIndex(string+byteIndex, count) - (string+byteIndex);
874
+
875
+ newByteCount = entryPtr->entry.numBytes + 1 - byteCount;
876
+ new = ckalloc(newByteCount);
877
+ memcpy(new, string, byteIndex);
878
+ strcpy(new + byteIndex, string + byteIndex + byteCount);
879
+
880
+ code = EntryValidateChange(
881
+ entryPtr, new, index, count, VALIDATE_DELETE);
882
+
883
+ if (code == TCL_OK) {
884
+ AdjustIndices(entryPtr, index, -count);
885
+ code = EntrySetValue(entryPtr, new);
886
+ } else if (code == TCL_BREAK) {
887
+ code = TCL_OK;
888
+ }
889
+ ckfree(new);
890
+
891
+ return code;
892
+ }
893
+
894
+ /*------------------------------------------------------------------------
895
+ * +++ Event handler.
896
+ */
897
+
898
+ /* EntryEventProc --
899
+ * Extra event handling for entry widgets:
900
+ * Triggers validation on FocusIn and FocusOut events.
901
+ */
902
+ #define EntryEventMask (FocusChangeMask)
903
+ static void
904
+ EntryEventProc(ClientData clientData, XEvent *eventPtr)
905
+ {
906
+ Entry *entryPtr = (Entry *) clientData;
907
+
908
+ Tcl_Preserve(clientData);
909
+ switch (eventPtr->type) {
910
+ case DestroyNotify:
911
+ Tk_DeleteEventHandler(entryPtr->core.tkwin,
912
+ EntryEventMask, EntryEventProc, clientData);
913
+ break;
914
+ case FocusIn:
915
+ EntryRevalidateBG(entryPtr, VALIDATE_FOCUSIN);
916
+ break;
917
+ case FocusOut:
918
+ EntryRevalidateBG(entryPtr, VALIDATE_FOCUSOUT);
919
+ break;
920
+ }
921
+ Tcl_Release(clientData);
922
+ }
923
+
924
+ /*------------------------------------------------------------------------
925
+ * +++ Initialization and cleanup.
926
+ */
927
+
928
+ static int
929
+ EntryInitialize(Tcl_Interp *interp, void *recordPtr)
930
+ {
931
+ Entry *entryPtr = recordPtr;
932
+
933
+ Tk_CreateEventHandler(
934
+ entryPtr->core.tkwin, EntryEventMask, EntryEventProc, entryPtr);
935
+ Tk_CreateSelHandler(entryPtr->core.tkwin, XA_PRIMARY, XA_STRING,
936
+ EntryFetchSelection, (ClientData) entryPtr, XA_STRING);
937
+ TtkBlinkCursor(&entryPtr->core);
938
+
939
+ entryPtr->entry.string = ckalloc(1);
940
+ *entryPtr->entry.string = '\0';
941
+ entryPtr->entry.displayString = entryPtr->entry.string;
942
+ entryPtr->entry.textVariableTrace = 0;
943
+ entryPtr->entry.numBytes = entryPtr->entry.numChars = 0;
944
+
945
+ EntryInitStyleDefaults(&entryPtr->entry.styleDefaults);
946
+
947
+ entryPtr->entry.xscrollHandle =
948
+ TtkCreateScrollHandle(&entryPtr->core, &entryPtr->entry.xscroll);
949
+
950
+ entryPtr->entry.insertPos = 0;
951
+ entryPtr->entry.selectFirst = -1;
952
+ entryPtr->entry.selectLast = -1;
953
+
954
+ return TCL_OK;
955
+ }
956
+
957
+ static void
958
+ EntryCleanup(void *recordPtr)
959
+ {
960
+ Entry *entryPtr = recordPtr;
961
+
962
+ if (entryPtr->entry.textVariableTrace)
963
+ Ttk_UntraceVariable(entryPtr->entry.textVariableTrace);
964
+
965
+ TtkFreeScrollHandle(entryPtr->entry.xscrollHandle);
966
+
967
+ EntryFreeStyleDefaults(&entryPtr->entry.styleDefaults);
968
+
969
+ Tk_DeleteSelHandler(entryPtr->core.tkwin, XA_PRIMARY, XA_STRING);
970
+
971
+ Tk_FreeTextLayout(entryPtr->entry.textLayout);
972
+ if (entryPtr->entry.displayString != entryPtr->entry.string)
973
+ ckfree(entryPtr->entry.displayString);
974
+ ckfree(entryPtr->entry.string);
975
+ }
976
+
977
+ /* EntryConfigure --
978
+ * Configure hook for Entry widgets.
979
+ */
980
+ static int EntryConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
981
+ {
982
+ Entry *entryPtr = recordPtr;
983
+ Tcl_Obj *textVarName = entryPtr->entry.textVariableObj;
984
+ Ttk_TraceHandle *vt = 0;
985
+
986
+ if (mask & TEXTVAR_CHANGED) {
987
+ if (textVarName && *Tcl_GetString(textVarName)) {
988
+ vt = Ttk_TraceVariable(interp,
989
+ textVarName,EntryTextVariableTrace,entryPtr);
990
+ if (!vt) return TCL_ERROR;
991
+ }
992
+ }
993
+
994
+ if (TtkCoreConfigure(interp, recordPtr, mask) != TCL_OK) {
995
+ if (vt) Ttk_UntraceVariable(vt);
996
+ return TCL_ERROR;
997
+ }
998
+
999
+ /* Update derived resources:
1000
+ */
1001
+ if (mask & TEXTVAR_CHANGED) {
1002
+ if (entryPtr->entry.textVariableTrace)
1003
+ Ttk_UntraceVariable(entryPtr->entry.textVariableTrace);
1004
+ entryPtr->entry.textVariableTrace = vt;
1005
+ }
1006
+
1007
+ /* Claim the selection, in case we've suddenly started exporting it.
1008
+ */
1009
+ if (entryPtr->entry.exportSelection && entryPtr->entry.selectFirst != -1) {
1010
+ EntryOwnSelection(entryPtr);
1011
+ }
1012
+
1013
+ /* Handle -state compatibility option:
1014
+ */
1015
+ if (mask & STATE_CHANGED) {
1016
+ TtkCheckStateOption(&entryPtr->core, entryPtr->entry.stateObj);
1017
+ }
1018
+
1019
+ /* Force scrollbar update if needed:
1020
+ */
1021
+ if (mask & SCROLLCMD_CHANGED) {
1022
+ TtkScrollbarUpdateRequired(entryPtr->entry.xscrollHandle);
1023
+ }
1024
+
1025
+ /* Recompute the displayString, in case showChar changed:
1026
+ */
1027
+ if (entryPtr->entry.displayString != entryPtr->entry.string)
1028
+ ckfree(entryPtr->entry.displayString);
1029
+
1030
+ entryPtr->entry.displayString
1031
+ = entryPtr->entry.showChar
1032
+ ? EntryDisplayString(entryPtr->entry.showChar, entryPtr->entry.numChars)
1033
+ : entryPtr->entry.string
1034
+ ;
1035
+
1036
+ /* Update textLayout:
1037
+ */
1038
+ EntryUpdateTextLayout(entryPtr);
1039
+ return TCL_OK;
1040
+ }
1041
+
1042
+ /* EntryPostConfigure --
1043
+ * Post-configuration hook for entry widgets.
1044
+ */
1045
+ static int EntryPostConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
1046
+ {
1047
+ Entry *entryPtr = recordPtr;
1048
+ int status = TCL_OK;
1049
+
1050
+ if ((mask & TEXTVAR_CHANGED) && entryPtr->entry.textVariableTrace != NULL) {
1051
+ status = Ttk_FireTrace(entryPtr->entry.textVariableTrace);
1052
+ }
1053
+
1054
+ return status;
1055
+ }
1056
+
1057
+ /*------------------------------------------------------------------------
1058
+ * +++ Layout and display.
1059
+ */
1060
+
1061
+ /* EntryTextArea --
1062
+ * Return bounding box of entry display ("owner-draw") area.
1063
+ */
1064
+ static Ttk_Box
1065
+ EntryTextArea(Entry *entryPtr)
1066
+ {
1067
+ WidgetCore *corePtr = &entryPtr->core;
1068
+ Ttk_LayoutNode *node = Ttk_LayoutFindNode(corePtr->layout, "textarea");
1069
+ return node ? Ttk_LayoutNodeParcel(node) : Ttk_WinBox(corePtr->tkwin);
1070
+ }
1071
+
1072
+ /* EntryCharPosition --
1073
+ * Return the X coordinate of the specified character index.
1074
+ * Precondition: textLayout and layoutX up-to-date.
1075
+ */
1076
+ static int
1077
+ EntryCharPosition(Entry *entryPtr, int index)
1078
+ {
1079
+ int xPos;
1080
+ Tk_CharBbox(entryPtr->entry.textLayout, index, &xPos, NULL, NULL, NULL);
1081
+ return xPos + entryPtr->entry.layoutX;
1082
+ }
1083
+
1084
+ /* EntryDoLayout --
1085
+ * Layout hook for entry widgets.
1086
+ *
1087
+ * Determine position of textLayout based on xscroll.first, justify,
1088
+ * and display area.
1089
+ *
1090
+ * Recalculates layoutX, layoutY, and rightIndex,
1091
+ * and updates xscroll accordingly.
1092
+ * May adjust xscroll.first to ensure the maximum #characters are onscreen.
1093
+ */
1094
+ static void
1095
+ EntryDoLayout(void *recordPtr)
1096
+ {
1097
+ Entry *entryPtr = recordPtr;
1098
+ WidgetCore *corePtr = &entryPtr->core;
1099
+ Tk_TextLayout textLayout = entryPtr->entry.textLayout;
1100
+ int leftIndex = entryPtr->entry.xscroll.first;
1101
+ int rightIndex;
1102
+ Ttk_Box textarea;
1103
+
1104
+ Ttk_PlaceLayout(corePtr->layout,corePtr->state,Ttk_WinBox(corePtr->tkwin));
1105
+ textarea = EntryTextArea(entryPtr);
1106
+
1107
+ /* Center the text vertically within the available parcel:
1108
+ */
1109
+ entryPtr->entry.layoutY = textarea.y +
1110
+ (textarea.height - entryPtr->entry.layoutHeight)/2;
1111
+
1112
+ /* Recompute where the leftmost character on the display will
1113
+ * be drawn (layoutX) and adjust leftIndex if necessary.
1114
+ */
1115
+ if (entryPtr->entry.layoutWidth <= textarea.width) {
1116
+ /* Everything fits. Set leftIndex to zero (no need to scroll),
1117
+ * and compute layoutX based on -justify.
1118
+ */
1119
+ int extraSpace = textarea.width - entryPtr->entry.layoutWidth;
1120
+ leftIndex = 0;
1121
+ rightIndex = entryPtr->entry.numChars;
1122
+ entryPtr->entry.layoutX = textarea.x;
1123
+ if (entryPtr->entry.justify == TK_JUSTIFY_RIGHT) {
1124
+ entryPtr->entry.layoutX += extraSpace;
1125
+ } else if (entryPtr->entry.justify == TK_JUSTIFY_CENTER) {
1126
+ entryPtr->entry.layoutX += extraSpace / 2;
1127
+ }
1128
+ } else {
1129
+ /* The whole string doesn't fit in the window.
1130
+ * Limit leftIndex to leave at most one character's worth
1131
+ * of empty space on the right.
1132
+ */
1133
+ int overflow = entryPtr->entry.layoutWidth - textarea.width;
1134
+ int maxLeftIndex = 1 + Tk_PointToChar(textLayout, overflow, 0);
1135
+ int leftX;
1136
+
1137
+ if (leftIndex > maxLeftIndex) {
1138
+ leftIndex = maxLeftIndex;
1139
+ }
1140
+
1141
+ /* Compute layoutX and rightIndex.
1142
+ * rightIndex is set to one past the last fully-visible character.
1143
+ */
1144
+ Tk_CharBbox(textLayout, leftIndex, &leftX, NULL, NULL, NULL);
1145
+ rightIndex = Tk_PointToChar(textLayout, leftX + textarea.width, 0);
1146
+ entryPtr->entry.layoutX = textarea.x - leftX;
1147
+ }
1148
+
1149
+ TtkScrolled(entryPtr->entry.xscrollHandle,
1150
+ leftIndex, rightIndex, entryPtr->entry.numChars);
1151
+ }
1152
+
1153
+ /* EntryGetGC -- Helper routine.
1154
+ * Get a GC using the specified foreground color and the entry's font.
1155
+ * Result must be freed with Tk_FreeGC().
1156
+ */
1157
+ static GC EntryGetGC(Entry *entryPtr, Tcl_Obj *colorObj)
1158
+ {
1159
+ Tk_Window tkwin = entryPtr->core.tkwin;
1160
+ Tk_Font font = Tk_GetFontFromObj(tkwin, entryPtr->entry.fontObj);
1161
+ XColor *colorPtr;
1162
+ unsigned long mask = 0ul;
1163
+ XGCValues gcValues;
1164
+
1165
+ gcValues.line_width = 1; mask |= GCLineWidth;
1166
+ gcValues.font = Tk_FontId(font); mask |= GCFont;
1167
+ if (colorObj != 0 && (colorPtr=Tk_GetColorFromObj(tkwin,colorObj)) != 0) {
1168
+ gcValues.foreground = colorPtr->pixel;
1169
+ mask |= GCForeground;
1170
+ }
1171
+ return Tk_GetGC(entryPtr->core.tkwin, mask, &gcValues);
1172
+ }
1173
+
1174
+ /* EntryDisplay --
1175
+ * Redraws the contents of an entry window.
1176
+ */
1177
+ static void EntryDisplay(void *clientData, Drawable d)
1178
+ {
1179
+ Entry *entryPtr = clientData;
1180
+ Tk_Window tkwin = entryPtr->core.tkwin;
1181
+ int leftIndex = entryPtr->entry.xscroll.first,
1182
+ rightIndex = entryPtr->entry.xscroll.last,
1183
+ selFirst = entryPtr->entry.selectFirst,
1184
+ selLast = entryPtr->entry.selectLast;
1185
+ EntryStyleData es;
1186
+ GC gc;
1187
+ int showSelection, showCursor;
1188
+
1189
+ EntryInitStyleData(entryPtr, &es);
1190
+
1191
+ showCursor =
1192
+ (entryPtr->core.flags & CURSOR_ON) != 0
1193
+ && EntryEditable(entryPtr)
1194
+ && entryPtr->entry.insertPos >= leftIndex
1195
+ && entryPtr->entry.insertPos <= rightIndex
1196
+ ;
1197
+ showSelection =
1198
+ (entryPtr->core.state & TTK_STATE_DISABLED) == 0
1199
+ && selFirst > -1
1200
+ && selLast > leftIndex
1201
+ && selFirst <= rightIndex
1202
+ ;
1203
+
1204
+ /* Adjust selection range to keep in display bounds.
1205
+ */
1206
+ if (showSelection) {
1207
+ if (selFirst < leftIndex)
1208
+ selFirst = leftIndex;
1209
+ if (selLast > rightIndex)
1210
+ selLast = rightIndex;
1211
+ }
1212
+
1213
+ /* Draw widget background & border
1214
+ */
1215
+ Ttk_DrawLayout(entryPtr->core.layout, entryPtr->core.state, d);
1216
+
1217
+ /* Draw selection background
1218
+ */
1219
+ if (showSelection && es.selBorderObj) {
1220
+ Tk_3DBorder selBorder = Tk_Get3DBorderFromObj(tkwin, es.selBorderObj);
1221
+ int selStartX = EntryCharPosition(entryPtr, selFirst);
1222
+ int selEndX = EntryCharPosition(entryPtr, selLast);
1223
+ int borderWidth = 1;
1224
+
1225
+ Tcl_GetIntFromObj(NULL, es.selBorderWidthObj, &borderWidth);
1226
+
1227
+ if (selBorder) {
1228
+ Tk_Fill3DRectangle(tkwin, d, selBorder,
1229
+ selStartX - borderWidth, entryPtr->entry.layoutY - borderWidth,
1230
+ selEndX - selStartX + 2*borderWidth,
1231
+ entryPtr->entry.layoutHeight + 2*borderWidth,
1232
+ borderWidth, TK_RELIEF_RAISED);
1233
+ }
1234
+ }
1235
+
1236
+ /* Draw cursor:
1237
+ */
1238
+ if (showCursor) {
1239
+ int cursorX = EntryCharPosition(entryPtr, entryPtr->entry.insertPos),
1240
+ cursorY = entryPtr->entry.layoutY,
1241
+ cursorHeight = entryPtr->entry.layoutHeight,
1242
+ cursorWidth = 1;
1243
+
1244
+ Tcl_GetIntFromObj(NULL,es.insertWidthObj,&cursorWidth);
1245
+ if (cursorWidth <= 0) {
1246
+ cursorWidth = 1;
1247
+ }
1248
+
1249
+ /* @@@ should: maybe: SetCaretPos even when blinked off */
1250
+ Tk_SetCaretPos(tkwin, cursorX, cursorY, cursorHeight);
1251
+
1252
+ gc = EntryGetGC(entryPtr, es.insertColorObj);
1253
+ XFillRectangle(Tk_Display(tkwin), d, gc,
1254
+ cursorX-cursorWidth/2, cursorY, cursorWidth, cursorHeight);
1255
+ Tk_FreeGC(Tk_Display(tkwin), gc);
1256
+ }
1257
+
1258
+ /* Draw the text:
1259
+ */
1260
+ gc = EntryGetGC(entryPtr, es.foregroundObj);
1261
+ Tk_DrawTextLayout(
1262
+ Tk_Display(tkwin), d, gc, entryPtr->entry.textLayout,
1263
+ entryPtr->entry.layoutX, entryPtr->entry.layoutY,
1264
+ leftIndex, rightIndex);
1265
+ Tk_FreeGC(Tk_Display(tkwin), gc);
1266
+
1267
+ /* Overwrite the selected portion (if any) in the -selectforeground color:
1268
+ */
1269
+ if (showSelection) {
1270
+ gc = EntryGetGC(entryPtr, es.selForegroundObj);
1271
+ Tk_DrawTextLayout(
1272
+ Tk_Display(tkwin), d, gc, entryPtr->entry.textLayout,
1273
+ entryPtr->entry.layoutX, entryPtr->entry.layoutY,
1274
+ selFirst, selLast);
1275
+ Tk_FreeGC(Tk_Display(tkwin), gc);
1276
+ }
1277
+ }
1278
+
1279
+ /*------------------------------------------------------------------------
1280
+ * +++ Widget commands.
1281
+ */
1282
+
1283
+ /* EntryIndex --
1284
+ * Parse an index into an entry and return either its value
1285
+ * or an error.
1286
+ *
1287
+ * Results:
1288
+ * A standard Tcl result. If all went well, then *indexPtr is
1289
+ * filled in with the character index (into entryPtr) corresponding to
1290
+ * string. The index value is guaranteed to lie between 0 and
1291
+ * the number of characters in the string, inclusive. If an
1292
+ * error occurs then an error message is left in the interp's result.
1293
+ */
1294
+ static int
1295
+ EntryIndex(
1296
+ Tcl_Interp *interp, /* For error messages. */
1297
+ Entry *entryPtr, /* Entry widget to query */
1298
+ Tcl_Obj *indexObj, /* Symbolic index name */
1299
+ int *indexPtr) /* Return value */
1300
+ {
1301
+ # define EntryWidth(e) (Tk_Width(entryPtr->core.tkwin)) /* Not Right */
1302
+ int length;
1303
+ const char *string = Tcl_GetStringFromObj(indexObj, &length);
1304
+
1305
+ if (strncmp(string, "end", length) == 0) {
1306
+ *indexPtr = entryPtr->entry.numChars;
1307
+ } else if (strncmp(string, "insert", length) == 0) {
1308
+ *indexPtr = entryPtr->entry.insertPos;
1309
+ } else if (strncmp(string, "left", length) == 0) { /* for debugging */
1310
+ *indexPtr = entryPtr->entry.xscroll.first;
1311
+ } else if (strncmp(string, "right", length) == 0) { /* for debugging */
1312
+ *indexPtr = entryPtr->entry.xscroll.last;
1313
+ } else if (strncmp(string, "sel.", 4) == 0) {
1314
+ if (entryPtr->entry.selectFirst < 0) {
1315
+ Tcl_ResetResult(interp);
1316
+ Tcl_AppendResult(interp, "selection isn't in widget ",
1317
+ Tk_PathName(entryPtr->core.tkwin), NULL);
1318
+ return TCL_ERROR;
1319
+ }
1320
+ if (strncmp(string, "sel.first", length) == 0) {
1321
+ *indexPtr = entryPtr->entry.selectFirst;
1322
+ } else if (strncmp(string, "sel.last", length) == 0) {
1323
+ *indexPtr = entryPtr->entry.selectLast;
1324
+ } else {
1325
+ goto badIndex;
1326
+ }
1327
+ } else if (string[0] == '@') {
1328
+ int roundUp = 0;
1329
+ int maxWidth = EntryWidth(entryPtr);
1330
+ int x;
1331
+
1332
+ if (Tcl_GetInt(interp, string + 1, &x) != TCL_OK) {
1333
+ goto badIndex;
1334
+ }
1335
+ if (x > maxWidth) {
1336
+ x = maxWidth;
1337
+ roundUp = 1;
1338
+ }
1339
+ *indexPtr = Tk_PointToChar(entryPtr->entry.textLayout,
1340
+ x - entryPtr->entry.layoutX, 0);
1341
+
1342
+ if (*indexPtr < entryPtr->entry.xscroll.first) {
1343
+ *indexPtr = entryPtr->entry.xscroll.first;
1344
+ }
1345
+
1346
+ /*
1347
+ * Special trick: if the x-position was off-screen to the right,
1348
+ * round the index up to refer to the character just after the
1349
+ * last visible one on the screen. This is needed to enable the
1350
+ * last character to be selected, for example.
1351
+ */
1352
+
1353
+ if (roundUp && (*indexPtr < entryPtr->entry.numChars)) {
1354
+ *indexPtr += 1;
1355
+ }
1356
+ } else {
1357
+ if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
1358
+ goto badIndex;
1359
+ }
1360
+ if (*indexPtr < 0) {
1361
+ *indexPtr = 0;
1362
+ } else if (*indexPtr > entryPtr->entry.numChars) {
1363
+ *indexPtr = entryPtr->entry.numChars;
1364
+ }
1365
+ }
1366
+ return TCL_OK;
1367
+
1368
+ badIndex:
1369
+ Tcl_ResetResult(interp);
1370
+ Tcl_AppendResult(interp, "bad entry index \"", string, "\"", NULL);
1371
+ return TCL_ERROR;
1372
+ }
1373
+
1374
+ /* $entry bbox $index --
1375
+ * Return the bounding box of the character at the specified index.
1376
+ */
1377
+ static int
1378
+ EntryBBoxCommand(
1379
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1380
+ {
1381
+ Entry *entryPtr = recordPtr;
1382
+ Ttk_Box b;
1383
+ int index;
1384
+
1385
+ if (objc != 3) {
1386
+ Tcl_WrongNumArgs(interp, 2, objv, "index");
1387
+ return TCL_ERROR;
1388
+ }
1389
+ if (EntryIndex(interp, entryPtr, objv[2], &index) != TCL_OK) {
1390
+ return TCL_ERROR;
1391
+ }
1392
+ if ((index == entryPtr->entry.numChars) && (index > 0)) {
1393
+ index--;
1394
+ }
1395
+ Tk_CharBbox(entryPtr->entry.textLayout, index,
1396
+ &b.x, &b.y, &b.width, &b.height);
1397
+ b.x += entryPtr->entry.layoutX;
1398
+ b.y += entryPtr->entry.layoutY;
1399
+ Tcl_SetObjResult(interp, Ttk_NewBoxObj(b));
1400
+ return TCL_OK;
1401
+ }
1402
+
1403
+ /* $entry delete $from ?$to? --
1404
+ * Delete the characters in the range [$from,$to).
1405
+ * $to defaults to $from+1 if not specified.
1406
+ */
1407
+ static int
1408
+ EntryDeleteCommand(
1409
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1410
+ {
1411
+ Entry *entryPtr = recordPtr;
1412
+ int first, last;
1413
+
1414
+ if ((objc < 3) || (objc > 4)) {
1415
+ Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?");
1416
+ return TCL_ERROR;
1417
+ }
1418
+ if (EntryIndex(interp, entryPtr, objv[2], &first) != TCL_OK) {
1419
+ return TCL_ERROR;
1420
+ }
1421
+ if (objc == 3) {
1422
+ last = first + 1;
1423
+ } else if (EntryIndex(interp, entryPtr, objv[3], &last) != TCL_OK) {
1424
+ return TCL_ERROR;
1425
+ }
1426
+
1427
+ if (last >= first && EntryEditable(entryPtr)) {
1428
+ return DeleteChars(entryPtr, first, last - first);
1429
+ }
1430
+ return TCL_OK;
1431
+ }
1432
+
1433
+ /* $entry get --
1434
+ * Return the current value of the entry widget.
1435
+ */
1436
+ static int
1437
+ EntryGetCommand(
1438
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1439
+ {
1440
+ Entry *entryPtr = recordPtr;
1441
+ if (objc != 2) {
1442
+ Tcl_WrongNumArgs(interp, 2, objv, NULL);
1443
+ return TCL_ERROR;
1444
+ }
1445
+ Tcl_SetResult(interp, entryPtr->entry.string, TCL_VOLATILE);
1446
+ return TCL_OK;
1447
+ }
1448
+
1449
+ /* $entry icursor $index --
1450
+ * Set the insert cursor position.
1451
+ */
1452
+ static int
1453
+ EntryICursorCommand(
1454
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1455
+ {
1456
+ Entry *entryPtr = recordPtr;
1457
+ if (objc != 3) {
1458
+ Tcl_WrongNumArgs(interp, 2, objv, "pos");
1459
+ return TCL_ERROR;
1460
+ }
1461
+ if (EntryIndex(interp, entryPtr, objv[2],
1462
+ &entryPtr->entry.insertPos) != TCL_OK) {
1463
+ return TCL_ERROR;
1464
+ }
1465
+ TtkRedisplayWidget(&entryPtr->core);
1466
+ return TCL_OK;
1467
+ }
1468
+
1469
+ /* $entry index $index --
1470
+ * Return numeric value (0..numChars) of the specified index.
1471
+ */
1472
+ static int
1473
+ EntryIndexCommand(
1474
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1475
+ {
1476
+ Entry *entryPtr = recordPtr;
1477
+ int index;
1478
+
1479
+ if (objc != 3) {
1480
+ Tcl_WrongNumArgs(interp, 2, objv, "string");
1481
+ return TCL_ERROR;
1482
+ }
1483
+ if (EntryIndex(interp, entryPtr, objv[2], &index) != TCL_OK) {
1484
+ return TCL_ERROR;
1485
+ }
1486
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
1487
+ return TCL_OK;
1488
+ }
1489
+
1490
+ /* $entry insert $index $text --
1491
+ * Insert $text after position $index.
1492
+ * Silent no-op if the entry is disabled or read-only.
1493
+ */
1494
+ static int
1495
+ EntryInsertCommand(
1496
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1497
+ {
1498
+ Entry *entryPtr = recordPtr;
1499
+ int index;
1500
+
1501
+ if (objc != 4) {
1502
+ Tcl_WrongNumArgs(interp, 2, objv, "index text");
1503
+ return TCL_ERROR;
1504
+ }
1505
+ if (EntryIndex(interp, entryPtr, objv[2], &index) != TCL_OK) {
1506
+ return TCL_ERROR;
1507
+ }
1508
+ if (EntryEditable(entryPtr)) {
1509
+ return InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
1510
+ }
1511
+ return TCL_OK;
1512
+ }
1513
+
1514
+ /* selection clear --
1515
+ * Clear selection.
1516
+ */
1517
+ static int EntrySelectionClearCommand(
1518
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1519
+ {
1520
+ Entry *entryPtr = recordPtr;
1521
+
1522
+ if (objc != 3) {
1523
+ Tcl_WrongNumArgs(interp, 3, objv, NULL);
1524
+ return TCL_ERROR;
1525
+ }
1526
+ entryPtr->entry.selectFirst = entryPtr->entry.selectLast = -1;
1527
+ TtkRedisplayWidget(&entryPtr->core);
1528
+ return TCL_OK;
1529
+ }
1530
+
1531
+ /* $entry selection present --
1532
+ * Returns 1 if any characters are selected, 0 otherwise.
1533
+ */
1534
+ static int EntrySelectionPresentCommand(
1535
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1536
+ {
1537
+ Entry *entryPtr = recordPtr;
1538
+ if (objc != 3) {
1539
+ Tcl_WrongNumArgs(interp, 3, objv, NULL);
1540
+ return TCL_ERROR;
1541
+ }
1542
+ Tcl_SetObjResult(interp,
1543
+ Tcl_NewBooleanObj(entryPtr->entry.selectFirst >= 0));
1544
+ return TCL_OK;
1545
+ }
1546
+
1547
+ /* $entry selection range $start $end --
1548
+ * Explicitly set the selection range.
1549
+ */
1550
+ static int EntrySelectionRangeCommand(
1551
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1552
+ {
1553
+ Entry *entryPtr = recordPtr;
1554
+ int start, end;
1555
+ if (objc != 5) {
1556
+ Tcl_WrongNumArgs(interp, 3, objv, "start end");
1557
+ return TCL_ERROR;
1558
+ }
1559
+ if ( EntryIndex(interp, entryPtr, objv[3], &start) != TCL_OK
1560
+ || EntryIndex(interp, entryPtr, objv[4], &end) != TCL_OK) {
1561
+ return TCL_ERROR;
1562
+ }
1563
+ if (entryPtr->core.state & TTK_STATE_DISABLED) {
1564
+ return TCL_OK;
1565
+ }
1566
+
1567
+ if (start >= end) {
1568
+ entryPtr->entry.selectFirst = entryPtr->entry.selectLast = -1;
1569
+ } else {
1570
+ entryPtr->entry.selectFirst = start;
1571
+ entryPtr->entry.selectLast = end;
1572
+ EntryOwnSelection(entryPtr);
1573
+ }
1574
+ TtkRedisplayWidget(&entryPtr->core);
1575
+ return TCL_OK;
1576
+ }
1577
+
1578
+ /* $entry selection $command ?arg arg...?
1579
+ * Ensemble, see above.
1580
+ */
1581
+ static int EntrySelectionCommand(
1582
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1583
+ {
1584
+ static WidgetCommandSpec EntrySelectionCommands[] = {
1585
+ { "clear", EntrySelectionClearCommand },
1586
+ { "present", EntrySelectionPresentCommand },
1587
+ { "range", EntrySelectionRangeCommand },
1588
+ {0,0}
1589
+ };
1590
+ return TtkWidgetEnsembleCommand(
1591
+ EntrySelectionCommands, 2, interp, objc, objv, recordPtr);
1592
+ }
1593
+
1594
+ /* $entry set $value
1595
+ * Sets the value of an entry widget.
1596
+ */
1597
+ static int EntrySetCommand(
1598
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1599
+ {
1600
+ Entry *entryPtr = recordPtr;
1601
+ if (objc != 3) {
1602
+ Tcl_WrongNumArgs(interp, 2, objv, "value");
1603
+ return TCL_ERROR;
1604
+ }
1605
+ EntrySetValue(entryPtr, Tcl_GetString(objv[2]));
1606
+ return TCL_OK;
1607
+ }
1608
+
1609
+ /* $entry validate --
1610
+ * Trigger forced validation. Returns 1/0 if validation succeeds/fails
1611
+ * or error status from -validatecommand / -invalidcommand.
1612
+ */
1613
+ static int EntryValidateCommand(
1614
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1615
+ {
1616
+ Entry *entryPtr = recordPtr;
1617
+ int code;
1618
+
1619
+ if (objc != 2) {
1620
+ Tcl_WrongNumArgs(interp, 2, objv, NULL);
1621
+ return TCL_ERROR;
1622
+ }
1623
+
1624
+ code = EntryRevalidate(interp, entryPtr, VALIDATE_FORCED);
1625
+
1626
+ if (code == TCL_ERROR)
1627
+ return code;
1628
+
1629
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(code == TCL_OK));
1630
+ return TCL_OK;
1631
+ }
1632
+
1633
+ /* $entry xview -- horizontal scrolling interface
1634
+ */
1635
+ static int EntryXViewCommand(
1636
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1637
+ {
1638
+ Entry *entryPtr = recordPtr;
1639
+ return TtkScrollviewCommand(interp, objc, objv, entryPtr->entry.xscrollHandle);
1640
+ }
1641
+
1642
+ static WidgetCommandSpec EntryCommands[] =
1643
+ {
1644
+ { "bbox", EntryBBoxCommand },
1645
+ { "cget", TtkWidgetCgetCommand },
1646
+ { "configure", TtkWidgetConfigureCommand },
1647
+ { "delete", EntryDeleteCommand },
1648
+ { "get", EntryGetCommand },
1649
+ { "icursor", EntryICursorCommand },
1650
+ { "identify", TtkWidgetIdentifyCommand },
1651
+ { "index", EntryIndexCommand },
1652
+ { "insert", EntryInsertCommand },
1653
+ { "instate", TtkWidgetInstateCommand },
1654
+ { "selection", EntrySelectionCommand },
1655
+ { "state", TtkWidgetStateCommand },
1656
+ { "validate", EntryValidateCommand },
1657
+ { "xview", EntryXViewCommand },
1658
+ {0,0}
1659
+ };
1660
+
1661
+ /*------------------------------------------------------------------------
1662
+ * +++ Entry widget definition.
1663
+ */
1664
+
1665
+ static WidgetSpec EntryWidgetSpec =
1666
+ {
1667
+ "TEntry", /* className */
1668
+ sizeof(Entry), /* recordSize */
1669
+ EntryOptionSpecs, /* optionSpecs */
1670
+ EntryCommands, /* subcommands */
1671
+ EntryInitialize, /* initializeProc */
1672
+ EntryCleanup, /* cleanupProc */
1673
+ EntryConfigure, /* configureProc */
1674
+ EntryPostConfigure, /* postConfigureProc */
1675
+ TtkWidgetGetLayout, /* getLayoutProc */
1676
+ TtkWidgetSize, /* sizeProc */
1677
+ EntryDoLayout, /* layoutProc */
1678
+ EntryDisplay /* displayProc */
1679
+ };
1680
+
1681
+ /*------------------------------------------------------------------------
1682
+ * +++ Combobox widget record.
1683
+ */
1684
+
1685
+ typedef struct {
1686
+ Tcl_Obj *postCommandObj;
1687
+ Tcl_Obj *valuesObj;
1688
+ Tcl_Obj *heightObj;
1689
+ int currentIndex;
1690
+ } ComboboxPart;
1691
+
1692
+ typedef struct {
1693
+ WidgetCore core;
1694
+ EntryPart entry;
1695
+ ComboboxPart combobox;
1696
+ } Combobox;
1697
+
1698
+ static Tk_OptionSpec ComboboxOptionSpecs[] =
1699
+ {
1700
+ {TK_OPTION_STRING, "-height", "height", "Height",
1701
+ DEF_LIST_HEIGHT, Tk_Offset(Combobox, combobox.heightObj), -1,
1702
+ 0,0,0 },
1703
+ {TK_OPTION_STRING, "-postcommand", "postCommand", "PostCommand",
1704
+ "", Tk_Offset(Combobox, combobox.postCommandObj), -1,
1705
+ 0,0,0 },
1706
+ {TK_OPTION_STRING, "-values", "values", "Values",
1707
+ "", Tk_Offset(Combobox, combobox.valuesObj), -1,
1708
+ 0,0,0 },
1709
+ WIDGET_INHERIT_OPTIONS(EntryOptionSpecs)
1710
+ };
1711
+
1712
+ /* ComboboxInitialize --
1713
+ * Initialization hook for combobox widgets.
1714
+ */
1715
+ static int
1716
+ ComboboxInitialize(Tcl_Interp *interp, void *recordPtr)
1717
+ {
1718
+ Combobox *cb = recordPtr;
1719
+ cb->combobox.currentIndex = -1;
1720
+ TtkTrackElementState(&cb->core);
1721
+ return EntryInitialize(interp, recordPtr);
1722
+ }
1723
+
1724
+ /* ComboboxConfigure --
1725
+ * Configuration hook for combobox widgets.
1726
+ */
1727
+ static int
1728
+ ComboboxConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
1729
+ {
1730
+ Combobox *cbPtr = recordPtr;
1731
+ int unused;
1732
+
1733
+ /* Make sure -values is a valid list:
1734
+ */
1735
+ if (Tcl_ListObjLength(interp,cbPtr->combobox.valuesObj,&unused) != TCL_OK)
1736
+ return TCL_ERROR;
1737
+
1738
+ return EntryConfigure(interp, recordPtr, mask);
1739
+ }
1740
+
1741
+ /* $cb current ?newIndex? -- get or set current index.
1742
+ * Setting the current index updates the combobox value,
1743
+ * but the value and -values may be changed independently
1744
+ * of the index. Instead of trying to keep currentIndex
1745
+ * in sync at all times, [$cb current] double-checks
1746
+ */
1747
+ static int ComboboxCurrentCommand(
1748
+ Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
1749
+ {
1750
+ Combobox *cbPtr = recordPtr;
1751
+ int currentIndex = cbPtr->combobox.currentIndex;
1752
+ const char *currentValue = cbPtr->entry.string;
1753
+ int nValues;
1754
+ Tcl_Obj **values;
1755
+
1756
+ Tcl_ListObjGetElements(interp,cbPtr->combobox.valuesObj,&nValues,&values);
1757
+
1758
+ if (objc == 2) {
1759
+ /* Check if currentIndex still valid:
1760
+ */
1761
+ if ( currentIndex < 0
1762
+ || currentIndex >= nValues
1763
+ || strcmp(currentValue,Tcl_GetString(values[currentIndex]))
1764
+ )
1765
+ {
1766
+ /* Not valid. Check current value against each element in -values:
1767
+ */
1768
+ for (currentIndex = 0; currentIndex < nValues; ++currentIndex) {
1769
+ if (!strcmp(currentValue,Tcl_GetString(values[currentIndex]))) {
1770
+ break;
1771
+ }
1772
+ }
1773
+ if (currentIndex >= nValues) {
1774
+ /* Not found */
1775
+ currentIndex = -1;
1776
+ }
1777
+ }
1778
+ cbPtr->combobox.currentIndex = currentIndex;
1779
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(currentIndex));
1780
+ return TCL_OK;
1781
+ } else if (objc == 3) {
1782
+ if (Tcl_GetIntFromObj(interp, objv[2], &currentIndex) != TCL_OK) {
1783
+ return TCL_ERROR;
1784
+ }
1785
+ if (currentIndex < 0 || currentIndex >= nValues) {
1786
+ Tcl_AppendResult(interp,
1787
+ "Index ", Tcl_GetString(objv[2]), " out of range",
1788
+ NULL);
1789
+ return TCL_ERROR;
1790
+ }
1791
+
1792
+ cbPtr->combobox.currentIndex = currentIndex;
1793
+
1794
+ return EntrySetValue(recordPtr, Tcl_GetString(values[currentIndex]));
1795
+ } else {
1796
+ Tcl_WrongNumArgs(interp, 2, objv, "?newIndex?");
1797
+ return TCL_ERROR;
1798
+ }
1799
+ return TCL_OK;
1800
+ }
1801
+
1802
+ /*------------------------------------------------------------------------
1803
+ * +++ Combobox widget definition.
1804
+ */
1805
+ static WidgetCommandSpec ComboboxCommands[] =
1806
+ {
1807
+ { "bbox", EntryBBoxCommand },
1808
+ { "cget", TtkWidgetCgetCommand },
1809
+ { "configure", TtkWidgetConfigureCommand },
1810
+ { "current", ComboboxCurrentCommand },
1811
+ { "delete", EntryDeleteCommand },
1812
+ { "get", EntryGetCommand },
1813
+ { "icursor", EntryICursorCommand },
1814
+ { "identify", TtkWidgetIdentifyCommand },
1815
+ { "index", EntryIndexCommand },
1816
+ { "insert", EntryInsertCommand },
1817
+ { "instate", TtkWidgetInstateCommand },
1818
+ { "selection", EntrySelectionCommand },
1819
+ { "state", TtkWidgetStateCommand },
1820
+ { "set", EntrySetCommand },
1821
+ { "xview", EntryXViewCommand },
1822
+ {0,0}
1823
+ };
1824
+
1825
+ static WidgetSpec ComboboxWidgetSpec =
1826
+ {
1827
+ "TCombobox", /* className */
1828
+ sizeof(Combobox), /* recordSize */
1829
+ ComboboxOptionSpecs, /* optionSpecs */
1830
+ ComboboxCommands, /* subcommands */
1831
+ ComboboxInitialize, /* initializeProc */
1832
+ EntryCleanup, /* cleanupProc */
1833
+ ComboboxConfigure, /* configureProc */
1834
+ EntryPostConfigure, /* postConfigureProc */
1835
+ TtkWidgetGetLayout, /* getLayoutProc */
1836
+ TtkWidgetSize, /* sizeProc */
1837
+ EntryDoLayout, /* layoutProc */
1838
+ EntryDisplay /* displayProc */
1839
+ };
1840
+
1841
+ /*------------------------------------------------------------------------
1842
+ * +++ Textarea element.
1843
+ *
1844
+ * Text display area for Entry widgets.
1845
+ * Just computes requested size; display is handled by the widget itself.
1846
+ */
1847
+
1848
+ typedef struct {
1849
+ Tcl_Obj *fontObj;
1850
+ Tcl_Obj *widthObj;
1851
+ } TextareaElement;
1852
+
1853
+ static Ttk_ElementOptionSpec TextareaElementOptions[] = {
1854
+ { "-font", TK_OPTION_FONT,
1855
+ Tk_Offset(TextareaElement,fontObj), DEF_ENTRY_FONT },
1856
+ { "-width", TK_OPTION_INT,
1857
+ Tk_Offset(TextareaElement,widthObj), "20" },
1858
+ {0,0,0}
1859
+ };
1860
+
1861
+ static void TextareaElementSize(
1862
+ void *clientData, void *elementRecord, Tk_Window tkwin,
1863
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1864
+ {
1865
+ TextareaElement *textarea = elementRecord;
1866
+ Tk_Font font = Tk_GetFontFromObj(tkwin, textarea->fontObj);
1867
+ int avgWidth = Tk_TextWidth(font, "0", 1);
1868
+ Tk_FontMetrics fm;
1869
+ int prefWidth = 1;
1870
+
1871
+ Tk_GetFontMetrics(font, &fm);
1872
+ Tcl_GetIntFromObj(NULL, textarea->widthObj, &prefWidth);
1873
+ if (prefWidth <= 0)
1874
+ prefWidth = 1;
1875
+
1876
+ *heightPtr = fm.linespace;
1877
+ *widthPtr = prefWidth * avgWidth;
1878
+ }
1879
+
1880
+ static Ttk_ElementSpec TextareaElementSpec = {
1881
+ TK_STYLE_VERSION_2,
1882
+ sizeof(TextareaElement),
1883
+ TextareaElementOptions,
1884
+ TextareaElementSize,
1885
+ TtkNullElementDraw
1886
+ };
1887
+
1888
+ /*------------------------------------------------------------------------
1889
+ * +++ Widget layouts.
1890
+ */
1891
+
1892
+ TTK_BEGIN_LAYOUT(EntryLayout)
1893
+ TTK_GROUP("Entry.field", TTK_FILL_BOTH|TTK_BORDER,
1894
+ TTK_GROUP("Entry.padding", TTK_FILL_BOTH,
1895
+ TTK_NODE("Entry.textarea", TTK_FILL_BOTH)))
1896
+ TTK_END_LAYOUT
1897
+
1898
+ TTK_BEGIN_LAYOUT(ComboboxLayout)
1899
+ TTK_GROUP("Combobox.field", TTK_FILL_BOTH,
1900
+ TTK_NODE("Combobox.downarrow", TTK_PACK_RIGHT|TTK_FILL_Y)
1901
+ TTK_GROUP("Combobox.padding", TTK_FILL_BOTH|TTK_PACK_LEFT|TTK_EXPAND,
1902
+ TTK_NODE("Combobox.textarea", TTK_FILL_BOTH)))
1903
+ TTK_END_LAYOUT
1904
+
1905
+ /*------------------------------------------------------------------------
1906
+ * +++ Initialization.
1907
+ */
1908
+
1909
+ void TtkEntry_Init(Tcl_Interp *interp)
1910
+ {
1911
+ Ttk_Theme themePtr = Ttk_GetDefaultTheme(interp);
1912
+
1913
+ Ttk_RegisterElement(interp, themePtr, "textarea", &TextareaElementSpec, 0);
1914
+
1915
+ Ttk_RegisterLayout(themePtr, "TEntry", EntryLayout);
1916
+ Ttk_RegisterLayout(themePtr, "TCombobox", ComboboxLayout);
1917
+
1918
+ RegisterWidget(interp, "ttk::entry", &EntryWidgetSpec);
1919
+ RegisterWidget(interp, "ttk::combobox", &ComboboxWidgetSpec);
1920
+ }
1921
+
1922
+ /*EOF*/