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.
- data/.exrc +61 -0
- data/.gitignore +4 -0
- data/History.txt +6 -0
- data/Manifest.txt +46 -0
- data/Pratt.gemspec +351 -0
- data/README.txt +66 -0
- data/Rakefile +85 -0
- data/TODO +54 -0
- data/VERSION +1 -0
- data/bin/pratt.rb +13 -0
- data/config.rb +34 -0
- data/lib/pratt.rb +527 -0
- data/lib/pratt/array.rb +11 -0
- data/lib/pratt/string.rb +18 -0
- data/models/app.rb +40 -0
- data/models/customer.rb +24 -0
- data/models/payment.rb +22 -0
- data/models/pratt.rb +19 -0
- data/models/project.rb +82 -0
- data/models/whence.rb +70 -0
- data/pkgs/tile-0.8.2.tar.gz +0 -0
- data/pkgs/tile-0.8.2/ANNOUNCE.txt +95 -0
- data/pkgs/tile-0.8.2/ChangeLog +4651 -0
- data/pkgs/tile-0.8.2/Makefile +250 -0
- data/pkgs/tile-0.8.2/Makefile.in +250 -0
- data/pkgs/tile-0.8.2/README.txt +86 -0
- data/pkgs/tile-0.8.2/aclocal.m4 +2 -0
- data/pkgs/tile-0.8.2/altTheme.o +0 -0
- data/pkgs/tile-0.8.2/blink.o +0 -0
- data/pkgs/tile-0.8.2/button.o +0 -0
- data/pkgs/tile-0.8.2/cache.o +0 -0
- data/pkgs/tile-0.8.2/clamTheme.o +0 -0
- data/pkgs/tile-0.8.2/classicTheme.o +0 -0
- data/pkgs/tile-0.8.2/config.log +1330 -0
- data/pkgs/tile-0.8.2/config.status +795 -0
- data/pkgs/tile-0.8.2/configure +15248 -0
- data/pkgs/tile-0.8.2/configure.in +89 -0
- data/pkgs/tile-0.8.2/demos/autocomplete.tcl +59 -0
- data/pkgs/tile-0.8.2/demos/demo.tcl +870 -0
- data/pkgs/tile-0.8.2/demos/dirbrowser.tcl +167 -0
- data/pkgs/tile-0.8.2/demos/dlgtest.tcl +97 -0
- data/pkgs/tile-0.8.2/demos/iconlib.tcl +110 -0
- data/pkgs/tile-0.8.2/demos/repeater.tcl +117 -0
- data/pkgs/tile-0.8.2/demos/toolbutton.tcl +101 -0
- data/pkgs/tile-0.8.2/doc/Geometry.3 +230 -0
- data/pkgs/tile-0.8.2/doc/INDEX.MAP +153 -0
- data/pkgs/tile-0.8.2/doc/Makefile +36 -0
- data/pkgs/tile-0.8.2/doc/TILE.XML +45 -0
- data/pkgs/tile-0.8.2/doc/Theme.3 +34 -0
- data/pkgs/tile-0.8.2/doc/button.n +75 -0
- data/pkgs/tile-0.8.2/doc/checkbutton.n +61 -0
- data/pkgs/tile-0.8.2/doc/combobox.n +98 -0
- data/pkgs/tile-0.8.2/doc/converting.txt +97 -0
- data/pkgs/tile-0.8.2/doc/dialog.n +122 -0
- data/pkgs/tile-0.8.2/doc/entry.n +438 -0
- data/pkgs/tile-0.8.2/doc/frame.n +43 -0
- data/pkgs/tile-0.8.2/doc/html/Geometry.html +304 -0
- data/pkgs/tile-0.8.2/doc/html/Theme.html +48 -0
- data/pkgs/tile-0.8.2/doc/html/button.html +120 -0
- data/pkgs/tile-0.8.2/doc/html/category-index.html +18 -0
- data/pkgs/tile-0.8.2/doc/html/checkbutton.html +94 -0
- data/pkgs/tile-0.8.2/doc/html/combobox.html +164 -0
- data/pkgs/tile-0.8.2/doc/html/converting.txt +97 -0
- data/pkgs/tile-0.8.2/doc/html/dialog.html +159 -0
- data/pkgs/tile-0.8.2/doc/html/entry.html +613 -0
- data/pkgs/tile-0.8.2/doc/html/frame.html +76 -0
- data/pkgs/tile-0.8.2/doc/html/image.html +100 -0
- data/pkgs/tile-0.8.2/doc/html/index.html +25 -0
- data/pkgs/tile-0.8.2/doc/html/keyword-index.html +228 -0
- data/pkgs/tile-0.8.2/doc/html/label.html +133 -0
- data/pkgs/tile-0.8.2/doc/html/labelframe.html +91 -0
- data/pkgs/tile-0.8.2/doc/html/manpage.css +212 -0
- data/pkgs/tile-0.8.2/doc/html/menubutton.html +63 -0
- data/pkgs/tile-0.8.2/doc/html/notebook.html +280 -0
- data/pkgs/tile-0.8.2/doc/html/paned.html +149 -0
- data/pkgs/tile-0.8.2/doc/html/progressbar.html +138 -0
- data/pkgs/tile-0.8.2/doc/html/radiobutton.html +89 -0
- data/pkgs/tile-0.8.2/doc/html/scrollbar.html +221 -0
- data/pkgs/tile-0.8.2/doc/html/separator.html +48 -0
- data/pkgs/tile-0.8.2/doc/html/sizegrip.html +62 -0
- data/pkgs/tile-0.8.2/doc/html/style.html +172 -0
- data/pkgs/tile-0.8.2/doc/html/tile-intro.html +164 -0
- data/pkgs/tile-0.8.2/doc/html/treeview.html +634 -0
- data/pkgs/tile-0.8.2/doc/html/widget.html +342 -0
- data/pkgs/tile-0.8.2/doc/image.n +81 -0
- data/pkgs/tile-0.8.2/doc/internals.txt +409 -0
- data/pkgs/tile-0.8.2/doc/label.n +75 -0
- data/pkgs/tile-0.8.2/doc/labelframe.n +64 -0
- data/pkgs/tile-0.8.2/doc/man.macros +239 -0
- data/pkgs/tile-0.8.2/doc/menubutton.n +41 -0
- data/pkgs/tile-0.8.2/doc/notebook.n +188 -0
- data/pkgs/tile-0.8.2/doc/paned.n +95 -0
- data/pkgs/tile-0.8.2/doc/progressbar.n +79 -0
- data/pkgs/tile-0.8.2/doc/radiobutton.n +57 -0
- data/pkgs/tile-0.8.2/doc/scrollbar.n +160 -0
- data/pkgs/tile-0.8.2/doc/separator.n +30 -0
- data/pkgs/tile-0.8.2/doc/sizegrip.n +53 -0
- data/pkgs/tile-0.8.2/doc/style.n +119 -0
- data/pkgs/tile-0.8.2/doc/tile-intro.n +165 -0
- data/pkgs/tile-0.8.2/doc/tmml.options +4 -0
- data/pkgs/tile-0.8.2/doc/treeview.n +415 -0
- data/pkgs/tile-0.8.2/doc/widget.n +227 -0
- data/pkgs/tile-0.8.2/doc/xml/Geometry.tmml +379 -0
- data/pkgs/tile-0.8.2/doc/xml/INDEX.MAP +153 -0
- data/pkgs/tile-0.8.2/doc/xml/Theme.tmml +63 -0
- data/pkgs/tile-0.8.2/doc/xml/button.tmml +134 -0
- data/pkgs/tile-0.8.2/doc/xml/checkbutton.tmml +119 -0
- data/pkgs/tile-0.8.2/doc/xml/combobox.tmml +184 -0
- data/pkgs/tile-0.8.2/doc/xml/dialog.tmml +195 -0
- data/pkgs/tile-0.8.2/doc/xml/entry.tmml +630 -0
- data/pkgs/tile-0.8.2/doc/xml/frame.tmml +98 -0
- data/pkgs/tile-0.8.2/doc/xml/image.tmml +101 -0
- data/pkgs/tile-0.8.2/doc/xml/label.tmml +154 -0
- data/pkgs/tile-0.8.2/doc/xml/labelframe.tmml +116 -0
- data/pkgs/tile-0.8.2/doc/xml/menubutton.tmml +80 -0
- data/pkgs/tile-0.8.2/doc/xml/notebook.tmml +306 -0
- data/pkgs/tile-0.8.2/doc/xml/paned.tmml +154 -0
- data/pkgs/tile-0.8.2/doc/xml/progressbar.tmml +151 -0
- data/pkgs/tile-0.8.2/doc/xml/radiobutton.tmml +109 -0
- data/pkgs/tile-0.8.2/doc/xml/scrollbar.tmml +233 -0
- data/pkgs/tile-0.8.2/doc/xml/separator.tmml +59 -0
- data/pkgs/tile-0.8.2/doc/xml/sizegrip.tmml +82 -0
- data/pkgs/tile-0.8.2/doc/xml/style.tmml +171 -0
- data/pkgs/tile-0.8.2/doc/xml/tile-intro.tmml +192 -0
- data/pkgs/tile-0.8.2/doc/xml/treeview.tmml +604 -0
- data/pkgs/tile-0.8.2/doc/xml/widget.tmml +372 -0
- data/pkgs/tile-0.8.2/entry.o +0 -0
- data/pkgs/tile-0.8.2/frame.o +0 -0
- data/pkgs/tile-0.8.2/generic/Makefile.in +221 -0
- data/pkgs/tile-0.8.2/generic/TODO +493 -0
- data/pkgs/tile-0.8.2/generic/altTheme.c +1172 -0
- data/pkgs/tile-0.8.2/generic/blink.c +168 -0
- data/pkgs/tile-0.8.2/generic/button.c +858 -0
- data/pkgs/tile-0.8.2/generic/cache.c +354 -0
- data/pkgs/tile-0.8.2/generic/clamTheme.c +974 -0
- data/pkgs/tile-0.8.2/generic/classicTheme.c +518 -0
- data/pkgs/tile-0.8.2/generic/configure +10334 -0
- data/pkgs/tile-0.8.2/generic/configure.in +100 -0
- data/pkgs/tile-0.8.2/generic/entry.c +1922 -0
- data/pkgs/tile-0.8.2/generic/frame.c +648 -0
- data/pkgs/tile-0.8.2/generic/gunk.h +44 -0
- data/pkgs/tile-0.8.2/generic/image.c +416 -0
- data/pkgs/tile-0.8.2/generic/label.c +663 -0
- data/pkgs/tile-0.8.2/generic/layout.c +1215 -0
- data/pkgs/tile-0.8.2/generic/manager.c +554 -0
- data/pkgs/tile-0.8.2/generic/manager.h +91 -0
- data/pkgs/tile-0.8.2/generic/notebook.c +1380 -0
- data/pkgs/tile-0.8.2/generic/paned.c +958 -0
- data/pkgs/tile-0.8.2/generic/pkgIndex.tcl.in +7 -0
- data/pkgs/tile-0.8.2/generic/progress.c +549 -0
- data/pkgs/tile-0.8.2/generic/scale.c +526 -0
- data/pkgs/tile-0.8.2/generic/scroll.c +253 -0
- data/pkgs/tile-0.8.2/generic/scrollbar.c +346 -0
- data/pkgs/tile-0.8.2/generic/separator.c +132 -0
- data/pkgs/tile-0.8.2/generic/square.c +306 -0
- data/pkgs/tile-0.8.2/generic/tagset.c +147 -0
- data/pkgs/tile-0.8.2/generic/tile.c +296 -0
- data/pkgs/tile-0.8.2/generic/tkElements.c +1280 -0
- data/pkgs/tile-0.8.2/generic/tkTheme.c +1708 -0
- data/pkgs/tile-0.8.2/generic/tkTheme.h +419 -0
- data/pkgs/tile-0.8.2/generic/tkThemeInt.h +45 -0
- data/pkgs/tile-0.8.2/generic/tkstate.c +268 -0
- data/pkgs/tile-0.8.2/generic/trace.c +145 -0
- data/pkgs/tile-0.8.2/generic/track.c +174 -0
- data/pkgs/tile-0.8.2/generic/treeview.c +3211 -0
- data/pkgs/tile-0.8.2/generic/ttk.decls +154 -0
- data/pkgs/tile-0.8.2/generic/ttkDecls.h +340 -0
- data/pkgs/tile-0.8.2/generic/ttkStubInit.c +61 -0
- data/pkgs/tile-0.8.2/generic/ttkStubLib.c +70 -0
- data/pkgs/tile-0.8.2/generic/widget.c +785 -0
- data/pkgs/tile-0.8.2/generic/widget.h +263 -0
- data/pkgs/tile-0.8.2/image.o +0 -0
- data/pkgs/tile-0.8.2/label.o +0 -0
- data/pkgs/tile-0.8.2/layout.o +0 -0
- data/pkgs/tile-0.8.2/library/altTheme.tcl +101 -0
- data/pkgs/tile-0.8.2/library/aquaTheme.tcl +62 -0
- data/pkgs/tile-0.8.2/library/button.tcl +85 -0
- data/pkgs/tile-0.8.2/library/clamTheme.tcl +139 -0
- data/pkgs/tile-0.8.2/library/classicTheme.tcl +108 -0
- data/pkgs/tile-0.8.2/library/combobox.tcl +439 -0
- data/pkgs/tile-0.8.2/library/cursors.tcl +36 -0
- data/pkgs/tile-0.8.2/library/defaults.tcl +118 -0
- data/pkgs/tile-0.8.2/library/dialog.tcl +274 -0
- data/pkgs/tile-0.8.2/library/entry.tcl +580 -0
- data/pkgs/tile-0.8.2/library/fonts.tcl +153 -0
- data/pkgs/tile-0.8.2/library/icons.tcl +105 -0
- data/pkgs/tile-0.8.2/library/keynav.tcl +192 -0
- data/pkgs/tile-0.8.2/library/menubutton.tcl +171 -0
- data/pkgs/tile-0.8.2/library/notebook.tcl +193 -0
- data/pkgs/tile-0.8.2/library/paned.tcl +87 -0
- data/pkgs/tile-0.8.2/library/progress.tcl +51 -0
- data/pkgs/tile-0.8.2/library/scale.tcl +54 -0
- data/pkgs/tile-0.8.2/library/scrollbar.tcl +125 -0
- data/pkgs/tile-0.8.2/library/sizegrip.tcl +77 -0
- data/pkgs/tile-0.8.2/library/tile.tcl +211 -0
- data/pkgs/tile-0.8.2/library/treeview.tcl +382 -0
- data/pkgs/tile-0.8.2/library/utils.tcl +254 -0
- data/pkgs/tile-0.8.2/library/winTheme.tcl +77 -0
- data/pkgs/tile-0.8.2/library/xpTheme.tcl +63 -0
- data/pkgs/tile-0.8.2/libtile0.8.2.so +0 -0
- data/pkgs/tile-0.8.2/libttkstub.a +0 -0
- data/pkgs/tile-0.8.2/license.terms +24 -0
- data/pkgs/tile-0.8.2/macosx/aquaTheme.c +1076 -0
- data/pkgs/tile-0.8.2/manager.o +0 -0
- data/pkgs/tile-0.8.2/notebook.o +0 -0
- data/pkgs/tile-0.8.2/paned.o +0 -0
- data/pkgs/tile-0.8.2/pkgIndex.tcl +3 -0
- data/pkgs/tile-0.8.2/progress.o +0 -0
- data/pkgs/tile-0.8.2/scale.o +0 -0
- data/pkgs/tile-0.8.2/scroll.o +0 -0
- data/pkgs/tile-0.8.2/scrollbar.o +0 -0
- data/pkgs/tile-0.8.2/separator.o +0 -0
- data/pkgs/tile-0.8.2/tagset.o +0 -0
- data/pkgs/tile-0.8.2/tclconfig/install-sh +119 -0
- data/pkgs/tile-0.8.2/tclconfig/tcl.m4 +4069 -0
- data/pkgs/tile-0.8.2/tclconfig/teax.m4 +109 -0
- data/pkgs/tile-0.8.2/tests/all.tcl +18 -0
- data/pkgs/tile-0.8.2/tests/bwidget.test +103 -0
- data/pkgs/tile-0.8.2/tests/cbtest.tcl +125 -0
- data/pkgs/tile-0.8.2/tests/combobox.test +51 -0
- data/pkgs/tile-0.8.2/tests/compound.tcl +92 -0
- data/pkgs/tile-0.8.2/tests/entry.test +285 -0
- data/pkgs/tile-0.8.2/tests/entrytest.tcl +78 -0
- data/pkgs/tile-0.8.2/tests/image.test +94 -0
- data/pkgs/tile-0.8.2/tests/labelframe.tcl +41 -0
- data/pkgs/tile-0.8.2/tests/labelframe.test +137 -0
- data/pkgs/tile-0.8.2/tests/layout.test +33 -0
- data/pkgs/tile-0.8.2/tests/misc.test +35 -0
- data/pkgs/tile-0.8.2/tests/nbtest.tcl +66 -0
- data/pkgs/tile-0.8.2/tests/notebook.test +500 -0
- data/pkgs/tile-0.8.2/tests/paned.test +298 -0
- data/pkgs/tile-0.8.2/tests/progress.test +92 -0
- data/pkgs/tile-0.8.2/tests/pwtest.tcl +90 -0
- data/pkgs/tile-0.8.2/tests/sbtest.tcl +79 -0
- data/pkgs/tile-0.8.2/tests/scrollbar.test +77 -0
- data/pkgs/tile-0.8.2/tests/sgtest.tcl +52 -0
- data/pkgs/tile-0.8.2/tests/testutils.tcl +20 -0
- data/pkgs/tile-0.8.2/tests/tile.test +674 -0
- data/pkgs/tile-0.8.2/tests/treetags.test +78 -0
- data/pkgs/tile-0.8.2/tests/treeview.test +563 -0
- data/pkgs/tile-0.8.2/tests/tvtest.tcl +332 -0
- data/pkgs/tile-0.8.2/tests/validate.test +278 -0
- data/pkgs/tile-0.8.2/tile.o +0 -0
- data/pkgs/tile-0.8.2/tkElements.o +0 -0
- data/pkgs/tile-0.8.2/tkTheme.o +0 -0
- data/pkgs/tile-0.8.2/tkstate.o +0 -0
- data/pkgs/tile-0.8.2/tools/genStubs.tcl +861 -0
- data/pkgs/tile-0.8.2/trace.o +0 -0
- data/pkgs/tile-0.8.2/track.o +0 -0
- data/pkgs/tile-0.8.2/treeview.o +0 -0
- data/pkgs/tile-0.8.2/ttkStubInit.o +0 -0
- data/pkgs/tile-0.8.2/ttkStubLib.o +0 -0
- data/pkgs/tile-0.8.2/widget.o +0 -0
- data/pkgs/tile-0.8.2/win/Tile.dsp +261 -0
- data/pkgs/tile-0.8.2/win/makefile.vc +527 -0
- data/pkgs/tile-0.8.2/win/monitor.c +164 -0
- data/pkgs/tile-0.8.2/win/nmakehlp.c +483 -0
- data/pkgs/tile-0.8.2/win/rules.vc +512 -0
- data/pkgs/tile-0.8.2/win/tile.rc +40 -0
- data/pkgs/tile-0.8.2/win/winTheme.c +734 -0
- data/pkgs/tile-0.8.2/win/xpTheme.c +1029 -0
- data/spec/app_spec.rb +48 -0
- data/spec/customer_spec.rb +31 -0
- data/spec/fixtures/graph.expectation +18 -0
- data/spec/payment_spec.rb +19 -0
- data/spec/pratt_spec.rb +148 -0
- data/spec/project_spec.rb +163 -0
- data/spec/rcov.opts +0 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/whence_spec.rb +54 -0
- data/tasks/pratt.rb +84 -0
- data/templates/model.eruby +12 -0
- data/templates/spec.eruby +8 -0
- data/views/env.rb +22 -0
- data/views/graph.eruby +20 -0
- data/views/invoice.eruby +148 -0
- data/views/main.rb +92 -0
- data/views/pid.eruby +3 -0
- data/views/pop.rb +94 -0
- data/views/pop2.rb +75 -0
- data/views/raw.eruby +11 -0
- 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], ¤tIndex) != 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*/
|