Pratt 1.5.6

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 (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*/