diff options
29 files changed, 6844 insertions, 198 deletions
diff --git a/libgui/ChangeLog b/libgui/ChangeLog index 2a16f91ba45..2651dbcd0a7 100644 --- a/libgui/ChangeLog +++ b/libgui/ChangeLog @@ -1,3 +1,86 @@ +2001-08-12 Mo DeJong <mdejong@redhat.com> + + * src/tkCanvEdge.c: Work around Windows gcc problem + initializing a static member with a dll imported + symbol by assigning the function pointer at runtime. + Static initialization works just fine in VC++ but + fails when compiling with the Windows version of gcc. + +2001-08-03 Mo DeJong <mdejong@redhat.com> + + * src/tclhelp.c (help_display_file_command): Pass int + address to Tcl_GetInt instead of an unsigned long to + avoid compiler warning. + +2001-08-03 Mo DeJong <mdejong@redhat.com> + + * src/subcommand.c: + * src/tclgetdir.c: + * src/tclhelp.c: + * src/tclmain.c: + * src/tclmsgbox.c: + * src/tclsizebox.c: + * src/tclwinmode.c: + * src/tclwinpath.c: + * src/tclwinprint.c: + * src/tkWinPrintCanvas.c: + * src/tkWinPrintText.c: + Use ckalloc/ckfree instead of Tcl_Alloc/Tcl_Free + or malloc/free so that allocations will + be marked with file positions when Tcl mem + debug is activated. + +2001-08-02 Mo DeJong <mdejong@redhat.com> + + * src/tkWinPrintCanvas.c (PrintCanvasCmd): + * src/tkWinPrintText.c (PrintTextCmd): Plug + memory leak by calling free on memory allocated + in PrintCanvasCmd and PrintTextCmd method. Make + sure error cases branch to the cleanup code at + the end of the method instead of just returning. + +2001-08-02 Mo DeJong <mdejong@redhat.com> + + * src/tkWinPrintText.c (DisplayDLineToDrawable): Fix + compiler warning by adding missing static modifier + to funciton declaration. + +2001-08-02 Mo DeJong <mdejong@redhat.com> + + * config.h.in: Regen. + * configure: Regen. + * configure.in: Don't check for strdup since it + is no longer used in libgui. + * src/tclhelp.c (help_initialize_command): Replace + use of strdup with calls to malloc and strcpy. + +2001-08-02 Mo DeJong <mdejong@redhat.com> + + * src/tclhelp.c (help_command_deleted): Free the + help_command_data->help_dir member allocated in + help_initialize_command. + +2001-08-02 Mo DeJong <mdejong@redhat.com> + + * src/tkGraphCanvas.c (GetEdgeNodes): Use ckalloc + and strcpy instead of calling strdup() since this + memory is deallocated with ckfree() later on. + +2001-08-02 Mo DeJong <mdejong@redhat.com> + + * Makefile.in: Regen. + * configure: Regen. + * configure.in: Check for cross AR using the + AC_CHECK_TOOL macro to fix cross compile. Use + AC_CHECK_TOOL instead of AC_PROG_RANLIB for + ranlib. The ranlib change is not required + but it is more correct. Move the call to + AC_CANONICAL_HOST up in the file. Don't + set or subst ITCL_DIR since it is not used + and depends on pre Itcl 3.1 paths. + * library/Makefile.in: Regen. + * src/Makefile.in: Regen. + Fri Sep 17 19:14:15 1999 Andrew Cagney <cagney@b1.cygnus.com> * src/guitcl.h (cyg_create_warp_pointer_command): Add declaration. diff --git a/libgui/Makefile.in b/libgui/Makefile.in index 7a332165274..0a369514dc5 100644 --- a/libgui/Makefile.in +++ b/libgui/Makefile.in @@ -59,6 +59,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : host_alias = @host_alias@ host_triplet = @host@ +AR = @AR@ BFDHDIR = @BFDHDIR@ BFDLIB = @BFDLIB@ CC = @CC@ @@ -84,7 +85,6 @@ ITCLLIB = @ITCLLIB@ ITCLMKIDX = @ITCLMKIDX@ ITCLSH = @ITCLSH@ ITCL_BUILD_LIB_SPEC = @ITCL_BUILD_LIB_SPEC@ -ITCL_DIR = @ITCL_DIR@ ITCL_LIB_FILE = @ITCL_LIB_FILE@ ITCL_LIB_FULL_PATH = @ITCL_LIB_FULL_PATH@ ITCL_SH = @ITCL_SH@ @@ -110,6 +110,7 @@ SIMHDIR = @SIMHDIR@ SIMLIB = @SIMLIB@ TCLCONFIG = @TCLCONFIG@ TCLHDIR = @TCLHDIR@ +TCL_BIN_DIR = @TCL_BIN_DIR@ TCL_BUILD_LIB_SPEC = @TCL_BUILD_LIB_SPEC@ TCL_CFLAGS = @TCL_CFLAGS@ TCL_DEFS = @TCL_DEFS@ @@ -154,7 +155,7 @@ configure.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) -TAR = tar +TAR = gtar GZIP_ENV = --best all: all-redirect .SUFFIXES: diff --git a/libgui/TODO b/libgui/TODO new file mode 100644 index 00000000000..6fd260c183f --- /dev/null +++ b/libgui/TODO @@ -0,0 +1,29 @@ +- should have an intelligent way of mapping color use to color name + likewise fonts + +- ulset.tcl is not very easy to use + should write class to manage menubar + this could integrate ulset functionality and also balloon help + should look at iwidgets 2.2 again to make sure we + aren't gratuitously incompatible + +- add more bitmaps/gifs from S-N + +- use a real gettext, not the dummy one we have now + see if it is possible to use some of the gnu code, for instance + xgettext. + the runtime code must be written by us; probably just use db + +- rewrite the canvas patches as a pure extension + the current situation is terrible + later, use a different layout algorithm. ISI sucks. + See: + A Technique for Drawing Directed Graphs + Emden R Gansner, Eleftherios Koutsofios, Stephen C. North, and + Kiem-Phong Vo + IEEE Transactions on Software Engineering Vol 19, No 3 + +- must have sensible way to track toplevel state and save in database + +- a way to make optionmenus which are statically sized to the + correct width diff --git a/libgui/config.h.in b/libgui/config.h.in index 3154f811749..c3779f19a6a 100644 --- a/libgui/config.h.in +++ b/libgui/config.h.in @@ -22,12 +22,6 @@ */ #undef STACK_DIRECTION -/* Name of package. */ -#undef PACKAGE - -/* Version of package. */ -#undef VERSION - /* Define this if <string.h> declares strncasecmp(). */ #undef HAVE_STRNCASECMP_DECL @@ -46,9 +40,6 @@ /* Define if you have the random function. */ #undef HAVE_RANDOM -/* Define if you have the strdup function. */ -#undef HAVE_STRDUP - /* Define if you have the <fcntl.h> header file. */ #undef HAVE_FCNTL_H @@ -75,3 +66,10 @@ /* Define if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* Version number of package */ +#undef VERSION + diff --git a/libgui/configure b/libgui/configure index f11edd44fc4..e50b9b68c58 100755 --- a/libgui/configure +++ b/libgui/configure @@ -826,10 +826,37 @@ fi MAINT=$MAINTAINER_MODE_TRUE + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:837: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:833: checking for $ac_word" >&5 +echo "configure:860: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -859,7 +886,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:863: checking for $ac_word" >&5 +echo "configure:890: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -910,7 +937,7 @@ fi # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:914: checking for $ac_word" >&5 +echo "configure:941: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -942,7 +969,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:946: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:973: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -953,12 +980,12 @@ cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF -#line 957 "configure" +#line 984 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:962: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:989: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -984,12 +1011,12 @@ if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:988: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:1015: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:993: checking whether we are using GNU C" >&5 +echo "configure:1020: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -998,7 +1025,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1002: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1029: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -1017,7 +1044,7 @@ ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:1021: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:1048: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1049,12 +1076,12 @@ else fi echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:1053: checking for Cygwin environment" >&5 +echo "configure:1080: checking for Cygwin environment" >&5 if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1058 "configure" +#line 1085 "configure" #include "confdefs.h" int main() { @@ -1065,7 +1092,7 @@ int main() { return __CYGWIN__; ; return 0; } EOF -if { (eval echo configure:1069: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1096: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else @@ -1082,19 +1109,19 @@ echo "$ac_t""$ac_cv_cygwin" 1>&6 CYGWIN= test "$ac_cv_cygwin" = yes && CYGWIN=yes echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 -echo "configure:1086: checking for mingw32 environment" >&5 +echo "configure:1113: checking for mingw32 environment" >&5 if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1091 "configure" +#line 1118 "configure" #include "confdefs.h" int main() { return __MINGW32__; ; return 0; } EOF -if { (eval echo configure:1098: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1125: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mingw32=yes else @@ -1113,7 +1140,7 @@ test "$ac_cv_mingw32" = yes && MINGW32=yes echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:1117: checking for executable suffix" >&5 +echo "configure:1144: checking for executable suffix" >&5 if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1123,7 +1150,7 @@ else rm -f conftest* echo 'int main () { return 0; }' > conftest.$ac_ext ac_cv_exeext= - if { (eval echo configure:1127: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + if { (eval echo configure:1154: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then for file in conftest.*; do case $file in *.c | *.o | *.obj | *.ilk | *.pdb) ;; @@ -1144,13 +1171,13 @@ echo "$ac_t""${ac_cv_exeext}" 1>&6 ac_exeext=$EXEEXT echo $ac_n "checking for object suffix""... $ac_c" 1>&6 -echo "configure:1148: checking for object suffix" >&5 +echo "configure:1175: checking for object suffix" >&5 if eval "test \"`echo '$''{'ac_cv_objext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else rm -f conftest* echo 'int i = 1;' > conftest.$ac_ext -if { (eval echo configure:1154: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1181: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then for ac_file in conftest.*; do case $ac_file in *.c) ;; @@ -1191,10 +1218,66 @@ else INSTALL_LIBGUI_TRUE='#' INSTALL_LIBGUI_FALSE= fi -# Extract the first word of "ranlib", so it can be a program name with args. +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:1223: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +if test $host != $build; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + +# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1249: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_RANLIB"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1198: checking for $ac_word" >&5 +echo "configure:1281: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1221,10 +1304,82 @@ else echo "$ac_t""no" 1>&6 fi +else + RANLIB=":" +fi +fi + +# Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1316: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_AR"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1348: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="ar" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_AR" && ac_cv_prog_AR=":" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + AR=":" +fi +fi + # Extract the first word of "itcl_sh", so it can be a program name with args. set dummy itcl_sh; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1228: checking for $ac_word" >&5 +echo "configure:1383: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ITCL_SH'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1253,7 +1408,7 @@ fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:1257: checking how to run the C preprocessor" >&5 +echo "configure:1412: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -1268,13 +1423,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext <<EOF -#line 1272 "configure" +#line 1427 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1278: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1433: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1285,13 +1440,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext <<EOF -#line 1289 "configure" +#line 1444 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1295: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1450: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1302,13 +1457,13 @@ else rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext <<EOF -#line 1306 "configure" +#line 1461 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1312: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1467: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1335,19 +1490,19 @@ echo "$ac_t""$CPP" 1>&6 # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 -echo "configure:1339: checking for working alloca.h" >&5 +echo "configure:1494: checking for working alloca.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1344 "configure" +#line 1499 "configure" #include "confdefs.h" #include <alloca.h> int main() { char *p = alloca(2 * sizeof(int)); ; return 0; } EOF -if { (eval echo configure:1351: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1506: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_header_alloca_h=yes else @@ -1368,12 +1523,12 @@ EOF fi echo $ac_n "checking for alloca""... $ac_c" 1>&6 -echo "configure:1372: checking for alloca" >&5 +echo "configure:1527: checking for alloca" >&5 if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1377 "configure" +#line 1532 "configure" #include "confdefs.h" #ifdef __GNUC__ @@ -1401,7 +1556,7 @@ int main() { char *p = (char *) alloca(1); ; return 0; } EOF -if { (eval echo configure:1405: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1560: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_func_alloca_works=yes else @@ -1433,12 +1588,12 @@ EOF echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 -echo "configure:1437: checking whether alloca needs Cray hooks" >&5 +echo "configure:1592: checking whether alloca needs Cray hooks" >&5 if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1442 "configure" +#line 1597 "configure" #include "confdefs.h" #if defined(CRAY) && ! defined(CRAY2) webecray @@ -1463,12 +1618,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6 if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1467: checking for $ac_func" >&5 +echo "configure:1622: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1472 "configure" +#line 1627 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -1491,7 +1646,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:1495: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1650: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -1518,7 +1673,7 @@ done fi echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 -echo "configure:1522: checking stack direction for C alloca" >&5 +echo "configure:1677: checking stack direction for C alloca" >&5 if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1526,7 +1681,7 @@ else ac_cv_c_stack_direction=0 else cat > conftest.$ac_ext <<EOF -#line 1530 "configure" +#line 1685 "configure" #include "confdefs.h" find_stack_direction () { @@ -1545,7 +1700,7 @@ main () exit (find_stack_direction() < 0); } EOF -if { (eval echo configure:1549: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1704: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_stack_direction=1 else @@ -1570,17 +1725,17 @@ for ac_hdr in stddef.h stdlib.h getopt.h unistd.h fcntl.h sys/file.h sys/wait.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:1574: checking for $ac_hdr" >&5 +echo "configure:1729: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1579 "configure" +#line 1734 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1584: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1739: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -1606,15 +1761,15 @@ else fi done -for ac_func in raise strdup +for ac_func in raise do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1613: checking for $ac_func" >&5 +echo "configure:1768: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1618 "configure" +#line 1773 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -1637,7 +1792,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:1641: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1796: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -1695,12 +1850,12 @@ fi for ac_func in random drand48 rand do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1699: checking for $ac_func" >&5 +echo "configure:1854: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1704 "configure" +#line 1859 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -1723,7 +1878,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:1727: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1882: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else @@ -1749,7 +1904,7 @@ done cat > conftest.$ac_ext <<EOF -#line 1753 "configure" +#line 1908 "configure" #include "confdefs.h" #include <string.h> EOF @@ -1774,12 +1929,12 @@ fi echo $ac_n "checking for cygwin32""... $ac_c" 1>&6 -echo "configure:1778: checking for cygwin32" >&5 +echo "configure:1933: checking for cygwin32" >&5 if eval "test \"`echo '$''{'ide_cv_os_cygwin32'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1783 "configure" +#line 1938 "configure" #include "confdefs.h" #ifdef __CYGWIN32__ @@ -1816,7 +1971,7 @@ fi # Find the init.tcl file. echo $ac_n "checking for init.tcl""... $ac_c" 1>&6 -echo "configure:1820: checking for init.tcl" >&5 +echo "configure:1975: checking for init.tcl" >&5 if eval "test \"`echo '$''{'ac_cv_c_tcl_libdir'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1851,7 +2006,7 @@ if test "${with_tclconfig+set}" = set; then fi echo $ac_n "checking for Tcl configuration script""... $ac_c" 1>&6 -echo "configure:1855: checking for Tcl configuration script" >&5 +echo "configure:2010: checking for Tcl configuration script" >&5 if eval "test \"`echo '$''{'ac_cv_c_tclconfig'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1928,6 +2083,7 @@ fi + @@ -1942,7 +2098,7 @@ if test "${with_tkconfig+set}" = set; then fi echo $ac_n "checking for Tk configuration script""... $ac_c" 1>&6 -echo "configure:1946: checking for Tk configuration script" >&5 +echo "configure:2102: checking for Tk configuration script" >&5 if eval "test \"`echo '$''{'ac_cv_c_tkconfig'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2022,7 +2178,7 @@ fi dirlist=".. ../../ ../../../ ../../../../ ../../../../../ ../../../../../../ ../../../../../../.. ../../../../../../../.. ../../../../../../../../.. ../../../../../../../../../.." no_tcl=true echo $ac_n "checking for Tcl headers in the source tree""... $ac_c" 1>&6 -echo "configure:2026: checking for Tcl headers in the source tree" >&5 +echo "configure:2182: checking for Tcl headers in the source tree" >&5 # Check whether --with-tclinclude or --without-tclinclude was given. if test "${with_tclinclude+set}" = set; then withval="$with_tclinclude" @@ -2079,17 +2235,17 @@ if test x"${ac_cv_c_tclh}" = x ; then echo "$ac_t""none" 1>&6 ac_safe=`echo "tcl.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for tcl.h""... $ac_c" 1>&6 -echo "configure:2083: checking for tcl.h" >&5 +echo "configure:2239: checking for tcl.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 2088 "configure" +#line 2244 "configure" #include "confdefs.h" #include <tcl.h> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2093: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2249: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -2153,7 +2309,7 @@ fi dirlist=".. ../../ ../../../ ../../../../ ../../../../../ ../../../../../../ ../../../../../../.. ../../../../../../../.. ../../../../../../../../.. ../../../../../../../../../.." no_tk=true echo $ac_n "checking for Tk headers in the source tree""... $ac_c" 1>&6 -echo "configure:2157: checking for Tk headers in the source tree" >&5 +echo "configure:2313: checking for Tk headers in the source tree" >&5 # Check whether --with-tkinclude or --without-tkinclude was given. if test "${with_tkinclude+set}" = set; then withval="$with_tkinclude" @@ -2231,39 +2387,6 @@ fi -# Make sure we can run config.sub. -if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : -else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } -fi - -echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:2241: checking host system type" >&5 - -host_alias=$host -case "$host_alias" in -NONE) - case $nonopt in - NONE) - if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : - else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } - fi ;; - *) host_alias=$nonopt ;; - esac ;; -esac - -host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` -host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` -host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` -host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` -echo "$ac_t""$host" 1>&6 - -case ${host} in -*cygwin*) ITCL_DIR=itcl/itcl/win ;; -*) ITCL_DIR=itcl/itcl/unix ;; -esac - - - @@ -2432,6 +2555,11 @@ s%@SET_MAKE@%$SET_MAKE%g s%@MAINTAINER_MODE_TRUE@%$MAINTAINER_MODE_TRUE%g s%@MAINTAINER_MODE_FALSE@%$MAINTAINER_MODE_FALSE%g s%@MAINT@%$MAINT%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g s%@CC@%$CC%g s%@EXEEXT@%$EXEEXT%g s%@OBJEXT@%$OBJEXT%g @@ -2439,7 +2567,13 @@ s%@CROSS_COMPILING_TRUE@%$CROSS_COMPILING_TRUE%g s%@CROSS_COMPILING_FALSE@%$CROSS_COMPILING_FALSE%g s%@INSTALL_LIBGUI_TRUE@%$INSTALL_LIBGUI_TRUE%g s%@INSTALL_LIBGUI_FALSE@%$INSTALL_LIBGUI_FALSE%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g s%@RANLIB@%$RANLIB%g +s%@AR@%$AR%g s%@ITCL_SH@%$ITCL_SH%g s%@CPP@%$CPP%g s%@ALLOCA@%$ALLOCA%g @@ -2461,6 +2595,7 @@ s%@TCL_LD_SEARCH_FLAGS@%$TCL_LD_SEARCH_FLAGS%g s%@TCL_RANLIB@%$TCL_RANLIB%g s%@TCL_BUILD_LIB_SPEC@%$TCL_BUILD_LIB_SPEC%g s%@TCL_LIB_SPEC@%$TCL_LIB_SPEC%g +s%@TCL_BIN_DIR@%$TCL_BIN_DIR%g s%@TKCONFIG@%$TKCONFIG%g s%@TK_VERSION@%$TK_VERSION%g s%@TK_DEFS@%$TK_DEFS%g @@ -2474,12 +2609,6 @@ s%@TK_BUILD_LIB_SPEC@%$TK_BUILD_LIB_SPEC%g s%@TK_LIB_SPEC@%$TK_LIB_SPEC%g s%@TCLHDIR@%$TCLHDIR%g s%@TKHDIR@%$TKHDIR%g -s%@host@%$host%g -s%@host_alias@%$host_alias%g -s%@host_cpu@%$host_cpu%g -s%@host_vendor@%$host_vendor%g -s%@host_os@%$host_os%g -s%@ITCL_DIR@%$ITCL_DIR%g s%@TCL_SHARED_TRUE@%$TCL_SHARED_TRUE%g s%@TCL_SHARED_FALSE@%$TCL_SHARED_FALSE%g s%@RPATH_ENVVAR@%$RPATH_ENVVAR%g @@ -2491,7 +2620,7 @@ cat >> $CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. -ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_max_sed_cmds=60 # Maximum number of lines to put in a sed script. ac_file=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_cmds # Line after last line for current file. diff --git a/libgui/configure.in b/libgui/configure.in index 479663d6732..c6466ce66ff 100644 --- a/libgui/configure.in +++ b/libgui/configure.in @@ -4,6 +4,7 @@ AC_INIT(src/subcommand.h) AM_INIT_AUTOMAKE(libgui, 0.0) AM_CONFIG_HEADER(config.h) AM_MAINTAINER_MODE +AC_CANONICAL_HOST AC_PROG_CC AC_EXEEXT AC_OBJEXT @@ -11,13 +12,14 @@ AC_ARG_ENABLE(install-libgui, \ [ --enable-install-libgui Install libgui.a and library header files]) AM_CONDITIONAL(CROSS_COMPILING, test x$cross_compiling = xyes) AM_CONDITIONAL(INSTALL_LIBGUI, test x$enable_install_libgui = xyes) -AC_PROG_RANLIB +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(AR, ar, :) AC_CHECK_PROG(ITCL_SH, itcl_sh, itcl_sh, [\$\$here/\$(top_builddir)/../itcl/itcl/unix/itcl_sh\$(EXEEXT)]) AC_FUNC_ALLOCA AC_HAVE_HEADERS(stddef.h stdlib.h getopt.h unistd.h fcntl.h sys/file.h sys/wait.h string.h strings.h) -AC_CHECK_FUNCS(raise strdup) +AC_CHECK_FUNCS(raise) AC_ARG_ENABLE(ide, [ --enable-ide Enable IDE support], [case "${enableval}" in @@ -99,13 +101,6 @@ CYG_AC_PATH_TCLH # FIXME: consider only doing this if --with-x given. CYG_AC_PATH_TKH -dnl what is the path to itclsh? -AC_CANONICAL_HOST -case ${host} in -*cygwin*) ITCL_DIR=itcl/itcl/win ;; -*) ITCL_DIR=itcl/itcl/unix ;; -esac - AC_SUBST(TCL_DEFS) AC_SUBST(TK_DEFS) AC_SUBST(TCLHDIR) @@ -115,7 +110,6 @@ AC_SUBST(TCL_LIBS) AC_SUBST(TK_BUILD_LIB_SPEC) AC_SUBST(TCL_BUILD_LIB_SPEC) AC_SUBST(TK_LIBS) -AC_SUBST(ITCL_DIR) AM_CONDITIONAL(TCL_SHARED, test x$TCL_SHARED_BUILD = x1) diff --git a/libgui/doc/tkTable.html b/libgui/doc/tkTable.html new file mode 100644 index 00000000000..e7c65978d75 --- /dev/null +++ b/libgui/doc/tkTable.html @@ -0,0 +1,1907 @@ +<!-- manual page source format generated by PolyglotMan v3.0.7, --> +<!-- available via anonymous ftp from ftp.cs.berkeley.edu:/ucb/people/phelps/tcltk/rman.tar.Z --> + +<HTML> +<HEAD> +<TITLE>man page(1)</TITLE> +</HEAD> +<BODY bgcolor=white> +<A HREF="#toc">Table of Contents</A><P> +_________________________________________________________________ + +<H2><A NAME="sect0" HREF="#toc0"><B>Name</B></A></H2> + +<P> +table - Create and manipulate tables + +<H2><A NAME="sect1" HREF="#toc1"><B>Synopsis</B></A></H2> + +<P> +<B>table</B> <I>pathName</I> ?<I>options</I>? + +<H2><A NAME="sect2" HREF="#toc2"><B>Standard</B> <B>Options</B></A></H2> + + +<DL> + +<DT><B>-anchor</B> </DT></DT> +<DD> <B>-background</B> <B>-cursor</B> +</DD> + +<DT><B>-exportselection</B> </DT></DT> +<DD> <B>-font</B> <B>-foreground</B> +</DD> + +<DT><B>-highlightbackground</B> </DT></DT> +<DD> <B>-highlightcolor</B> <B>-highlightthickness</B> +</DD> + +<DT><B>-insertbackground</B> </DT></DT> +<DD> <B>-insertborderwidth-insertofftime</B> +<B>-insertontime</B> <B>-insertwidth</B> <B>-invertselected</B> +</DD> + +<DT><B>-relief</B> </DT></DT> +<DD> <B>-takefocus</B> <B>-xscrollcommand</B> +<B>-yscrollcommand</B> +</DD> +</DL> +<P> +See the <B>options</B> manual entry for details on the standard +options. + +<H2><A NAME="sect3" HREF="#toc3"><B>Widget-specific</B> <B>Options</B></A></H2> + +<P> +Command-Line Name:<B>-autoclear</B><BR> + +Database Name: <B>autoClear</B><BR> + +Database Class: <B>AutoClear</B> +<P> +A boolean value which specifies whether the first +keypress in a cell will delete whatever text was +previously there. Defaults to 0. +<P> +Command-Line Name:<B>-bordercursor</B><BR> + +Database Name: <B>borderCursor</B><BR> + +Database Class: <B>Cursor</B> +<P> +Specifies the name of the cursor to show when over +borders, a visual indication that interactive +resizing is allowed (it is thus affect by the value +of -resizeborders). Defaults to <I>crosshair</I>. +<P> +Command-Line Name:<B>-borderwidth</B> <B>or</B> <B>-bd</B><BR> + +Database Name: <B>borderWidth</B><BR> + +Database Class: <B>BorderWidth</B> +<P> +Specifies a non-negative pixel value or list of +values indicating the width of the 3-D border to +draw on interior table cells (if such a border is +being drawn; the <B>relief</B> option typically determines +this). If one value is specified, a rectangle of +this width will be drawn. If two values are specified, +then only the left and right edges of the +cell will have borders. If four values are specified, +then the values correspond to the {left right +top bottom} edges. This can be overridden by the a +tag's borderwidth option. It can also be affected +by the defined <B>-drawmode</B> for the table. Each value +in the list must have one of the forms acceptable +to <B>Tk_GetPixels</B>. +<P> +Command-Line Name:<B>-browsecommand</B> <B>or</B> <B>-browsecmd</B> +Database Name: <B>browseCommand</B><BR> + +Database Class: <B>BrowseCommand</B> +<P> +Specifies a command which will be evaluated anytime +the active cell changes. It uses the %-substition +model described in COMMAND SUBSTITUTION below. +<P> +Command-Line Name:<B>-cache</B><BR> + +Database Name: <B>cache</B><BR> + +Database Class: <B>Cache</B> +<P> +A boolean value that specifies whether an internal +cache of the table contents should be kept. This +greatly enhances speed performance when used with +<B>-command</B> but uses extra memory. Can maintain state +when both <B>-command</B> and <B>-variable</B> are empty. The +cache is automatically flushed whenever the value +of <B>-cache</B> or <B>-variable</B> changes, otherwise you have +to explicitly call <B>clear</B> on it. Defaults to off. +<P> +Command-Line Name:<B>-colorigin</B><BR> + +Database Name: <B>colOrigin</B><BR> + +Database Class: <B>Origin</B> +<P> +Specifies what column index to interpret as the +leftmost column in the table. This value is used +for user indices in the table. Defaults to 0. +<P> +Command-Line Name:<B>-cols</B><BR> + +Database Name: <B>cols</B><BR> + +Database Class: <B>Cols</B> +<P> +Number of cols in the table. Defaults to 10. +<P> +Command-Line Name:<B>-colseparator</B><BR> + +Database Name: <B>colSeparator</B><BR> + +Database Class: <B>Separator</B> +<P> +Specifies a separator character that will be interpreted +as the column separator when cutting or +pasting data in a table. By default, columns are +separated as elements of a tcl list. +<P> +Command-Line Name:<B>-colstretchmode</B><BR> + +Database Name: <B>colStretchMode</B><BR> + +Database Class: <B>StretchMode</B> +<P> +Specifies one of the following stretch modes for +columns to fill extra allocated window space: +<B>none</B> Columns will not stretch to fill the +assigned window space. If the columns are +too narrow, there will be a blank space at +the right of the table. This is the +default. +<P> +<B>unset</B> Only columns that do not have a specific +width set will be stretched. + +<DL> + +<DT><B>all</B> </DT></DT> +<DD> All columns will be stretched by the same +number of pixels to fill the window space +allocated to the table. This mode can +interfere with interactive border resizing +which tries to force column width. +</DD> +</DL> +<P> +<B>last</B> The last column will be stretched to fill +the window space allocated to the table. +<P> +<B>fill</B> (only valid for <B>-rowstretch</B> currently) +The table will get more or less columns +according to the window space allocated to +the table. This mode has numerous quirks +and may disappear in the future. +<P> +Command-Line Name:<B>-coltagcommand</B><BR> + +Database Name: <B>colTagCommand</B><BR> + +Database Class: <B>TagCommand</B> +<P> +Provides the name of a procedure that will be evaluated +by the widget to determine the tag to be used +for a given column. When displaying a cell, the +table widget will first check to see if a tag has +been defined using the <B>tag</B> <B>col</B> widget method. If +no tag is found, it will evaluate the named procedure +passing the column number in question as the +sole argument. The procedure is expected to return +the name of a tag to use, or a null string. Errors +occuring during the evaluation of the procedure, or +the return of an invalid tag name are silently +ignored. +<P> +Command-Line Name:<B>-colwidth</B><BR> + +Database Name: <B>colWidth</B><BR> + +Database Class: <B>ColWidth</B> +<P> +Default column width, interpreted as characters in +the default font when the number is positive, or +pixels if it is negative. Defaults to 10. +<P> +Command-Line Name:<B>-command</B><BR> + +Database Name: <B>command</B><BR> + +Database Class: <B>Command</B> +<P> +Specified a command to use as a procedural +interface to cell values. If <B>-usecommand</B> is true, +this command will be used instead of any reference +to the <B>-variable</B> array. When retrieving cell values, +the return value of the command is used as the +value for the cell. It uses the %-substition model +described in COMMAND SUBSTITUTION below. +<P> +Command-Line Name:<B>-drawmode</B><BR> + +Database Name: <B>drawMode</B><BR> + +Database Class: <B>DrawMode</B> +<P> +Sets the table drawing mode to one of the following +options: +<P> +<B>slow</B> The table is drawn to an offscreen pixmap +using the Tk bordering functions (doublebuffering). +This means there will be no +flashing, but this mode is slow for larger +tables. +<P> +<B>compatible</B><BR> + +The table is drawn directly to the screen +using the Tk border functions. It is +faster, but the screen may flash on update. +This is the default. +<P> +<B>fast</B> The table is drawn directly to the screen +and the borders are done with fast X calls, +so they are always one pixel wide only. As +a side effect, it restricts <B>-borderwidth</B> to +a range of 0 or 1. This mode provides best +performance for large tables, but can flash +on redraw and is not 100% Tk compatible on +the border mode. +<P> +<B>single</B> The table is drawn to the screen as in fast +mode, but only single pixel lines are drawn +(not square borders). +<P> +Command-Line Name:<B>-flashmode</B><BR> + +Database Name: <B>flashMode</B><BR> + +Database Class: <B>FlashMode</B> +<P> +A boolean value which specifies whether cells +should flash when their value changes. The table +tag <B>flash</B> will be applied to these cells for the +duration specified by <B>-flashtime</B>. Defaults to 0. +<P> +Command-Line Name:<B>-flashtime</B><BR> + +Database Name: <B>flashTime</B><BR> + +Database Class: <B>FlashTime</B> +<P> +The amount of time, in 1/4 second increments, for +which a cell should flash when its value has +changed. <B>-flashmode</B> must be on. Defaults to 2. +<P> +Command-Line Name:<B>-height</B><BR> + +Database Name: <B>height</B><BR> + +Database Class: <B>Height</B> +<P> +Specifies the desired height for the window, in +rows. If zero or less, then the desired height for +the window is made just large enough to hold all +the rows in the table. The height can be further +limited by <B>-maxheight</B>. +<P> +Command-Line Name:<B>-invertselected</B><BR> + +Database Name: <B>invertSelected</B><BR> + +Database Class: <B>InvertSelected</B> +<P> +Specifies whether the foreground and background of +an item should simply have their values swapped +instead of merging the <I>sel</I> tag options when the +cell is selected. Defaults to 0 (merge <I>sel</I> tag). +<P> +Command-Line Name:<B>-ipadx</B><BR> + +Database Name: <B>ipadX</B><BR> + +Database Class: <B>Pad</B> +<P> +A pixel value specifying the internal offset X +padding for text in a cell. This value does not +grow the size of the cell, it just causes the text +to be drawn further from the cell border. It only +affects one side (depending on anchor). Defaults +to 0. See <B>-padx</B> for an alternate padding style. +<P> +Command-Line Name:<B>-ipady</B><BR> + +Database Name: <B>ipadY</B><BR> + +Database Class: <B>Pad</B> +<P> +A pixel value specifying the internal offset Y +padding for text in a cell. This value does not +grow the size of the cell, it just causes the text +to be drawn further from the cell border. It only +affects one side (depending on anchor). Defaults +to 0. See <B>-pady</B> for an alternate padding style. +<P> +Command-Line Name:<B>-maxheight</B><BR> + +Database Name: <B>maxHeight</B><BR> + +Database Class: <B>MaxHeight</B> +<P> +The max height in pixels that the window will +request. Defaults to 600. +<P> +Command-Line Name:<B>-maxwidth</B><BR> + +Database Name: <B>maxWidth</B><BR> + +Database Class: <B>MaxWidth</B> +<P> +The max width in pixels that the window will +request. Defaults to 800. +<P> +Command-Line Name:<B>-multiline</B><BR> + +Database Name: <B>multiline</B><BR> + +Database Class: <B>Multiline</B> +<P> +Specifies the default setting for the multiline tag +option. Defaults to 1. +<P> +Command-Line Name:<B>-padx</B><BR> + +Database Name: <B>padX</B><BR> + +Database Class: <B>Pad</B> +<P> +A pixel value specifying the offset X padding for a +cell. This value causes the default size of the +cell to increase by two times the value (one for +each side), unless a specific pixel size is chosen +for the cell with the <B>width</B> command. This will +force an empty area on the left and right of each +cell edge. This padding affects all types of data +in the cell. Defaults to 0. See <B>-ipadx</B> for an +alternate padding style. +<P> +Command-Line Name:<B>-pady</B><BR> + +Database Name: <B>padY</B><BR> + +Database Class: <B>Pad</B> +<P> +A pixel value specifying the offset Y padding for a +cell. This value causes the default size of the +cell to increase by two times the value (one for +each side), unless a specific pixel size is chosen +for the cell with the <B>height</B> command. This will +force an empty area on the top and bottom of each +cell edge. This padding affects all types of data +in the cell. Defaults to 0. See <B>-ipadx</B> for an +alternate padding style. +<P> +Command-Line Name:<B>-resizeborders</B><BR> + +Database Name: <B>resizeBorders</B><BR> + +Database Class: <B>ResizeBorders</B> +<P> +Specifies what kind of interactive border resizing +to allow, must be one of row, col, both (default) +or none. +<P> +Command-Line Name:<B>-rowheight</B><BR> + +Database Name: <B>rowHeight</B><BR> + +Database Class: <B>RowHeight</B> +<P> +Default row height, interpreted as lines in the +default font when the number is positive, or pixels +if it is negative. Defaults to 1. +<P> +Command-Line Name:<B>-roworigin</B><BR> + +Database Name: <B>rowOrigin</B><BR> + +Database Class: <B>Origin</B> +<P> +Specifies what row index to interpret as the topmost +row in the table. This value is used for user +indices in the table. Defaults to 0. +<P> +Command-Line Name:<B>-rows</B><BR> + +Database Name: <B>rows</B><BR> + +Database Class: <B>Rows</B> +<P> +Number of rows in the table. Defaults to 10. +<P> +Command-Line Name:<B>-rowseparator</B><BR> + +Database Name: <B>rowSeparator</B><BR> + +Database Class: <B>Separator</B> +<P> +Specifies a separator character that will be interpreted +as the row separator when cutting or pasting +data in a table. By default, rows are separated as +tcl lists. +<P> +Command-Line Name:<B>-rowstretchmode</B><BR> + +Database Name: <B>rowStretchMode</B><BR> + +Database Class: <B>StretchMode</B> +<P> +Specifies the stretch modes for rows to fill extra +allocated window space. See <B>-colstretchmode</B> for +valid options. +<P> +Command-Line Name:<B>-rowtagcommand</B><BR> + +Database Name: <B>rowTagCommand</B><BR> + +Database Class: <B>TagCommand</B> +<P> +Provides the name of a procedure that can evaluated +by the widget to determine the tag to be used for a +given row. The procedure must be defined by the +user to accept a single argument (the row number), +and return a tag name or null string. This operates +in a similar manner as <B>-coltagcommand</B>, except +that it applies to row tags. +<P> +Command-Line Name:<B>-selectioncommand</B> <B>or</B> <B>-selcmd</B> +Database Name: <B>selectionCommand</B><BR> + +Database Class: <B>SelectionCommand</B> +<P> +Specifies a command to evaluate when the selection +is retrieved from a table via the selection mechanism +(ie: evaluating «<B>selection</B> <B>get</B>"). The return +value from this command will become the string +passed on by the selection mechanism. It uses the +%-substition model described in COMMAND SUBSTITUTION +below. If an error occurs, a Tcl background +error is generated and nothing is returned. +<P> +Command-Line Name:<B>-selectmode</B><BR> + +Database Name: <B>selectMode</B><BR> + +Database Class: <B>SelectMode</B> +<P> +Specifies one of several styles for manipulating +the selection. The value of the option may be +arbitrary, but the default bindings expect it to be +either <B>single</B>, <B>browse</B>, <B>multiple</B>, or <B>extended</B>; the +default value is <B>browse</B>. These styles are like +those for the Tk listbox, except expanded for 2 +dimensions. +<P> +Command-Line Name:<B>-selecttitle</B><BR> + +Database Name: <B>selectTitles</B><BR> + +Database Class: <B>SelectTitles</B> +<P> +Specifies whether title cells should be allowed in +the selection. Defaults to 0 (disallowed). +<P> +Command-Line Name:<B>-selecttype</B><BR> + +Database Name: <B>selectType</B><BR> + +Database Class: <B>SelectType</B> +<P> +Specifies one of several types of selection for the +table. The value of the option may be one of <B>row</B>, +<B>col</B>, <B>cell</B>, or <B>both</B> (meaning <B>row</B> <B>&&</B> <B>col</B>); the +default value is <B>cell</B>. These types define whether +an entire row/col is affected when a cell's selection +is changed (set or clear). +<P> +Command-Line Name:<B>-sparsearray</B><BR> + +Database Name: <B>sparseArray</B><BR> + +Database Class: <B>SparseArray</B> +<P> +A boolean value that specifies whether an associated +Tcl array should be kept as a sparse array (1, +the default) or as a full array (0). If true, then +cell values that are empty will be deleted from the +array (taking less memory). If false, then all +values in the array will be maintained. +<P> +Command-Line Name:<B>-state</B><BR> + +Database Name: <B>state</B><BR> + +Database Class: <B>State</B> + +<DL> + +<DT>Specifies one of two states for the entry: </DT></DT> +<DD><B>normal</B> +or <B>disabled</B>. If the table is disabled then the +value may not be changed using widget commands and +no insertion cursor will be displayed, even if the +input focus is in the widget. Also, all insert or +delete methods will be ignored. Defaults to <B>normal</B>. +</DD> +</DL> +<P> +Command-Line Name:<B>-titlecols</B><BR> + +Database Name: <B>titleCols</B><BR> + +Database Class: <B>TitleCols</B> +<P> +Number of columns to use as a title area. Defaults +to 0. +<P> +Command-Line Name:<B>-titlerows</B><BR> + +Database Name: <B>titleRows</B><BR> + +Database Class: <B>TitleRows</B> +<P> +Number of rows to use as a title area. Defaults to +0. +<P> +Command-Line Name:<B>-usecommand</B><BR> + +Database Name: <B>useCommand</B><BR> + +Database Class: <B>UseCommand</B> +<P> +A boolean value which specifies whether to use the +<B>command</B> option. This value sets itself to zero if +<B>command</B> is used and returns an error. Defaults to +1 (will use <B>command</B> if specified). +<P> +Command-Line Name:<B>-validate</B><BR> + +Database Name: <B>validate</B><BR> + +Database Class: <B>Validate</B> +<P> +A boolean specifying whether validation should +occur for the active buffer. Defaults to 0. +<P> +Command-Line Name:<B>-validatecommand</B> <B>or</B> <B>-vcmd</B> +Database Name: <B>validateCommand</B><BR> + +Database Class: <B>ValidateCommand</B> +<P> +Specifies a command to execute when the active cell +is edited. This command is expected to return a +Tcl boolean. If it returns true, then it is +assumed the new value is OK, otherwise the new +value is rejected (the edition will not take +place). Errors in this command are handled in the +background. It uses the %-substition model +described in COMMAND SUBSTITUTION below. +<P> +Command-Line Name:<B>-variable</B><BR> + +Database Name: <B>variable</B><BR> + +Database Class: <B>Variable</B> +<P> +Global Tcl array variable to attach to the table's +C array. It will be created if it doesn't already +exist or is a simple variable. Keys used by the +table in the array are of the form <I>row</I>,<I>col</I> for +cells and the special key <I>active</I> which contains the +value of the active cell buffer. The Tcl array is +managed as a sparse array (the table doesn't +require all valid indices have values). No stored +value for an index is equivalent to the empty +string, and clearing a cell will remove that index +from the Tcl array, unless the <B>-sparsearray</B> options +is set to 0. +<P> +Command-Line Name:<B>-width</B><BR> + +Database Name: <B>width</B><BR> + +Database Class: <B>Width</B> +<P> +Specifies the desired width for the window, in +columns. If zero or less, then the desired width +for the window is made just large enough to hold +all the columns in the table. The width can be +further limited by <B>-maxwidth</B>. +<P> +Command-Line Name:<B>-wrap</B><BR> + +Database Name: <B>wrap</B><BR> + +Database Class: <B>Wrap</B> +<P> +Specifies the default wrap value for tags. +Defaults to 0.<BR> + +_________________________________________________________________ + +<H2><A NAME="sect4" HREF="#toc4"><B>Description</B></A></H2> + +<P> +The <B>table</B> command creates a 2-dimensional grid of cells. +The table can use a Tcl array variable or Tcl command for +data storage and retrieval. The widget has an active +cell, the contents of which can be edited (when the state +is normal). The widget supports a default style for the +cells and also multiple <I>tags</I>, which can be used to change +the style of a row, column or cell (see TAGS for details). +A cell <I>flash</I> can be set up so that changed cells will +change color for a specified amount of time ("blink"). +Cells can have embedded images or windows, as described in +TAGS and «EMBEDDED WINDOWS» respectively. +<P> +One or more cells may be selected as described below. If +a table is exporting its selection (see <B>-exportselection</B> +option), then it will observe the standard X11 protocols +for handling the selection. See THE SELECTION for +details. +<P> +It is not necessary for all the cells to be displayed in +the table window at once; commands described below may be +used to change the view in the window. Tables allow +scrolling in both directions using the standard <B>-xscrollcommand</B> +and <B>-yscrollcommand</B> options. They also support +scanning, as described below. +<P> +In order to obtain good performance, the table widget supports +multiple drawing modes, two of which are fully Tk +compatible. + +<H2><A NAME="sect5" HREF="#toc5"><B>Initialization</B></A></H2> + +<P> +When the <B>table</B> command is loaded into an interpreter, a +built-in Tcl command, <B>tkTableInit</B>, is evaluated. This +will search for the appropriate table binding init file to +load. The directories searched are those in <I>$tcl</I><B>_</B><I>pkgPath</I>, +both with Tktable(version) appended and without, +<I>$tk</I><B>_</B><I>library</I> and <I>[pwd]</I> (the current directory). You can +also define an <I>$env(TK</I><B>_</B><I>TABLE</I><B>_</B><I>LIBRARY)</I> to head this search +list. By default, the file searched for is called +<B>tkTable.tcl</B>, but this can be overridden by setting +<I>$env(TK</I><B>_</B><I>TABLE</I><B>_</B><I>LIBRARY</I><B>_</B><I>FILE)</I>. +<P> +This entire init script can be overridden by providing +your own <B>tkTableInit</B> procedure before the library is +loaded. Otherwise, the aforementioned +<I>env(TK</I><B>_</B><I>TABLE</I><B>_</B><I>LIBRARY)</I> variable will be set with the directory +in which <I>$env(TK</I><B>_</B><I>TABLE</I><B>_</B><I>LIBRARY</I><B>_</B><I>FILE)</I> was found. + +<H2><A NAME="sect6" HREF="#toc6"><B>Indices</B></A></H2> + +<P> +Many of the widget commands for tables take one or more +indices as arguments. An index specifies a particular +cell of the table, in any of the following ways: +<P> +<I>number,number</I><BR> + +Specifies the cell as a numerical index of +row,col which corresponds to the index of the +associated Tcl array, where <B>-roworigin,-colorigin</B> +corresponds to the first cell in the +table (0,0 by default). + +<DL> + +<DT><B>active</B> </DT></DT> +<DD> Indicates the cell that has the location cursor. +It is specified with the <B>activate</B> widget +command. +</DD> + +<DT><B>anchor</B> </DT></DT> +<DD> Indicates the anchor point for the selection, +which is set with the <B>selection</B> <B>anchor</B> widget +command. +</DD> +</DL> +<P> +<B>bottomright</B> Indicates the bottom-rightmost cell visible in +the table. + +<DL> + +<DT><B>end</B> </DT></DT> +<DD> Indicates the bottom right cell of the table. +</DD> + +<DT><B>origin</B> </DT></DT> +<DD> Indicates the top-leftmost editable cell of +the table, not necessarily in the display. +This takes into account the user specified +origin and title area. +</DD> + +<DT><B>topleft</B> </DT></DT> +<DD> Indicates the top-leftmost editable cell visible +in the table (this excludes title cells). +</DD> + +<DT><B>@</B><I>x</I><B>,</B><I>y</I> </DT></DT> +<DD> Indicates the cell that covers the point in +the table window specified by <I>x</I> and <I>y</I> (in +pixel coordinates). If no cell covers that +point, then the closest cell to that point is +used. +</DD> +</DL> +<P> +In the widget command descriptions below, arguments named +<I>index</I>, <I>first</I>, and <I>last</I> always contain text indices in one +of the above forms. + +<H2><A NAME="sect7" HREF="#toc7"><B>Tags</B></A></H2> + +<P> +A tag is a textual string that is associated with zero or +more rows, columns or cells in a table. Tags may contain +arbitrary characters, but it is probably best to avoid +using names which look like indices to reduce coding confusion. +There may be any number of tags in a table, but +each row, column or cell can only have one tag associated +with it at a time. There are several permanent tags in +each table that can be configured by the user and will +determine the attributes for special cells: + +<DL> + +<DT><B>active</B> </DT></DT> +<DD> This tag is given to the <I>active</I> cell +</DD> + +<DT><B>flash</B> </DT></DT> +<DD> If flash mode is on, this tag is given to +any recently edited cells. +</DD> + +<DT><B>sel</B> </DT></DT> +<DD> This tag is given to any selected cells. +</DD> + +<DT><B>title</B> </DT></DT> +<DD> This tag is given to any cells in the +title rows and columns. This tag has +<B>-state</B> <I>disabled</I> by default. +</DD> +</DL> +<P> +Tags control the way cells are displayed on the screen. +Where appropriate, the default for displaying cells is +determined by the options for the table widget. However, +display options may be associated with individual tags +using the ``<I>pathName</I> <B>tag</B> <B>configure</B>'' widget command. If a +cell, row or column has been tagged, then the display +options associated with the tag override the default display +style. The following options are currently supported +for tags: + +<DL> + +<DT><B>-anchor</B> <I>anchor</I></DT></DT> +<DD> +Anchor for item in the cell space. +</DD> + +<DT><B>-background</B> or <B>-bg</B> <I>color</I></DT></DT> +<DD> +Background color of the cell. +</DD> + +<DT><B>-borderwidth</B> or <B>-bd</B> <I>pixelList</I></DT></DT> +<DD> +Borderwidth of the cell, of the same format +for the table, but may also be empty to +inherit the default table borderwidth value +(the default). +</DD> + +<DT><B>-font</B> <I>fontName</I></DT></DT> +<DD> +Font for text in the cell. +</DD> + +<DT><B>-foreground</B> or <B>-fg</B> <I>color</I></DT></DT> +<DD> +Foreground color of the cell. +</DD> + +<DT><B>-justify</B> <I>justify</I></DT></DT> +<DD> +How to justify multi-line text in a cell. +It must be one of <B>left</B>, <B>right</B>, or <B>center</B>. +</DD> + +<DT><B>-image</B> <I>imageName</I></DT></DT> +<DD> +An image to display in the cell instead of +text. +</DD> + +<DT><B>-multiline</B> <I>boolean</I></DT></DT> +<DD> +Whether to display text with newlines on +multiple lines. +</DD> + +<DT><B>-relief</B> <I>relief</I></DT></DT> +<DD> +The relief for the cell. +</DD> + +<DT><B>-showtext</B> <I>boolean</I></DT></DT> +<DD> +Whether to show the text over an image. +</DD> + +<DT><B>-state</B> <I>state</I></DT></DT> +<DD> +The state of the cell, to allow for certain +cells to be disabled. This prevents the +cell from being edited by the <I>insert</I> or +<I>delete</I> methods, but a direct <I>set</I> will not be +prevented. +</DD> + +<DT><B>-wrap</B> <I>boolean</I></DT></DT> +<DD> +Whether characters should wrap in a cell +that is not wide enough. +</DD> +</DL> +<P> +A priority order is defined among tags based on creation +order (first created tag has highest default priority), +and this order is used in implementing some of the +tag-related functions described below. When a cell is +displayed, its properties are determined by the tags which +are assigned to it. The priority of a tag can be modified +by the ``<I>pathName</I> <B>tag</B> <B>lower</B>'' and ``<I>pathName</I> <B>tag</B> <B>raise</B>'' +widget commands. +<P> +If a cell has several tags associated with it that define +the same display options (eg - a <B>title</B> cell with specific +<B>row</B> and <B>cell</B> tags), then the options of the highest priority +tag are used. If a particular display option hasn't +been specified for a particular tag, or if it is specified +as an empty string, then that option will not be used; the +next-highest-priority tag's option will be used instead. +If no tag specifies a particular display option, then the +default style for the widget will be used. +<P> +Images are used for display purposes only. Editing in +that cell will still be enabled and any querying of the +cell will show the text value of the cell, regardless of +the value of <B>-showtext</B>. + +<H2><A NAME="sect8" HREF="#toc8"><B>Embedded</B> <B>Windows</B></A></H2> + +<P> +There may be any number of embedded windows in a table +widget (one per cell), and any widget may be used as an +embedded window (subject to the usual rules for geometry +management, which require the table window to be the parent +of the embedded window or a descendant of its parent). +The embedded window's position on the screen will be +updated as the table is modified or scrolled, and it will +be mapped and unmapped as it moves into and out of the +visible area of the table widget. Each embedded window +occupies one cell's worth of space in the table widget, +and it is referred to by the index of the cell in the +table. Windows associated with the table widget are +destroyed when the table widget is destroyed. +<P> +Windows are used for display purposes only. A value still +exists for that cell, but will not be shown unless the +window is deleted in some way. If the window is destroyed +or lost by the table widget to another geometry manager, +then any data associated with it is lost (the cell it +occupied will no longer appear in <B>window</B> <B>names</B>). +<P> +When an embedded window is added to a table widget with +the window configure widget command, several configuration +options may be associated with it. These options may be +modified with later calls to the window configure widget +command. The following options are currently supported: + +<DL> + +<DT><B>-create</B> <I>script</I></DT></DT> +<DD> +NOT CURRENTLY SUPPORTED. Specifies a Tcl +script that may be evaluated to create the +window for the annotation. If no -window +option has been specified for this cell then +this script will be evaluated when the cell +is about to be displayed on the screen. +Script must create a window for the cell and +return the name of that window as its +result. If the cell's window should ever be +deleted, the script will be evaluated again +the next time the cell is displayed. +</DD> + +<DT><B>-background</B> or <B>-bg</B> <I>color</I></DT></DT> +<DD> +Background color of the cell. If not specified, +it uses the table's default background. +</DD> + +<DT><B>-borderwidth</B> or <B>-bd</B> <I>pixelList</I></DT></DT> +<DD> +Borderwidth of the cell, of the same format +for the table, but may also be empty to +inherit the default table borderwidth value +(the default). +</DD> + +<DT><B>-padx</B> <I>pixels</I></DT></DT> +<DD> +As defined in the Tk options man page. +</DD> + +<DT><B>-pady</B> <I>pixels</I></DT></DT> +<DD> +As defined in the Tk options man page. +</DD> + +<DT><B>-relief</B> <I>relief</I></DT></DT> +<DD> +The relief to use for the cell in which the +window lies. If not specified, it uses the +table's default relief. +</DD> + +<DT><B>-sticky</B> <I>sticky</I></DT></DT> +<DD> +Stickiness of the window inside the cell, as +defined by the <B>grid</B> command. +</DD> + +<DT><B>-window</B> <I>pathName</I></DT></DT> +<DD> +Specifies the name of a window to display in +the annotation. It must exist before being +specified here. +</DD> +</DL> + +<H2><A NAME="sect9" HREF="#toc9"><B>the</B> <B>Selection</B></A></H2> + +<P> +Table selections are available as type STRING. By +default, the value of the selection will be the values of +the selected cells in nested Tcl list form where each row +is a list and each column is an element of a row list. +You can change the way this value is interpreted by setting +the <B>-rowseparator</B> and <B>-colseparator</B> options. For +example, default Excel format would be to set <B>-rowseparator</B> +to «\n» and <B>-colseparator</B> to «\t". Changing these +values affects both how the table sends out the selection +and reads in pasted data, ensuring that the table should +always be able to cut and paste to itself. It is possible +to change how pastes are handled by editing the table +library procedure <B>tk_tablePasteHandler</B>. This might be +necessary if <B>-selectioncommand</B> is set. + +<H2><A NAME="sect10" HREF="#toc10"><B>Row/Col</B> <B>Spanning</B></A></H2> + +<P> +Individual cells can span multiple rows and/or columns. +This is done via the <B>spans</B> command (see below for exact +arguments). Cells in the title area that span are not +permitted to span beyond the title area, and will be constrained +accordingly. If the title area shrinks during a +configure, sanity checking will occur to ensure the above. +You may set spans on regular cells that extend beyond the +defined row/col area. These spans will not be constrained, +so that when the defined row/col area expands, +the span will expand with it. +<P> +When setting a span, checks are made as to whether the +span would overlap an already spanning or hidden cell. +This is an error and it not allowed. Spans can affect the +overall speed of table drawing, although not significantly. +If spans are not used, then there is no performance +loss. +<P> +Cells <I>hidden</I> by spanning cells still have valid data. +This will be seen during cut and paste operations that +involve hidden cells, or through direct access by a command +like <B>get</B> or <B>set</B>. +<P> +The drawing properties of spanning cells apply to only the +visual area of the cell. For example, if a cell is center +justified over 5 columns, then when viewing any portion of +those columns, it will appear centered in the visible +area. The non-visible column area will not be considered +in the centering calculations. + +<H2><A NAME="sect11" HREF="#toc11"><B>Command</B> <B>Substitution</B></A></H2> + +<P> +The various option based commands that the table supports +all support the familiar Tk %-substitution model (see <B>bind</B> +for more details). The following %-sequences are recognized +and substituted by the table widget: +<P> +<B>%c</B> For <B>SelectionCommand</B>, it is the maximum number of +columns in any row in the selection. Otherwise it is +the column of the triggered cell. + +<DL> + +<DT><B>%C</B> </DT></DT> +<DD>A convenience substitution for <I>%r</I>,<I>%c</I>. +</DD> + +<DT><B>%i</B> </DT></DT> +<DD>For <B>SelectionCommand</B>, it is the total number of cells +in the selection. For <B>Command</B>, it is 0 for a read +(get) and 1 for a write (set). Otherwise it is the +current cursor position in the cell. +</DD> + +<DT><B>%r</B> </DT></DT> +<DD>For <B>SelectionCommand</B>, it is the number of rows in the +selection. Otherwise it is the row of the triggered +cell. +</DD> +</DL> +<P> +<B>%s</B> For <B>ValidateCommand</B>, it is the current value of the +cell being validated. For <B>SelectionCommand</B>, it is +the default value of the selection. For <B>BrowseCommand</B>, +it is the index of the last active cell. For +<B>Command</B>, it is empty for reads (get) and the current +value of the cell for writes (set). + +<DL> + +<DT><B>%S</B> </DT></DT> +<DD>For <B>ValidateCommand</B>, it is the potential new value of +the cell being validated. For <B>BrowseCommand</B>, it is +the index of the new active cell. +</DD> +</DL> +<P> +<B>%W</B> The pathname to the window for which the command was +generated. + +<H2><A NAME="sect12" HREF="#toc12"><B>Widget</B> <B>Command</B></A></H2> + +<P> +The <B>table</B> command creates a new Tcl command whose name is +<I>pathName</I>. This command may be used to invoke various +operations on the widget. It has the following general +form:<BR> + +<I>pathName</I> <I>option</I> ?<I>arg</I> <I>arg</I> <I>...</I>?<BR> + +<I>Option</I> and the <I>arg</I>s determine the exact behavior of the +command. +<P> +The following commands are possible for <B>table</B> widgets: +<P> +<I>pathName</I> <B>activate</B> <I>index</I><BR> + +Sets the active cell to the one indicated by <I>index</I>. +<P> +<I>pathName</I> <B>bbox</B> <I>first</I> ?<I>last</I>?<BR> + +It returns the bounding box for the specified cell +(range) as a 4-tuple of x, y, width and height in +pixels. It clips the box to the visible portion, +if any, otherwise an empty string is returned. +<P> +<I>pathName</I> <B>border</B> <I>option</I> <I>args</I><BR> + +This command is a voodoo hack to implement border +sizing for tables. This is normally called through +bindings, with the following as valid options: +<P> +<I>pathName</I> <B>border</B> <B>mark</B> <I>x</I> <I>y</I> ?<I>row|col</I>? +Records <I>x</I> and <I>y</I> and the row and/or column +border under that point in the table window, +if any; used in conjunction with later <B>border</B> +<B>dragto</B> commands. Typically this command +is associated with a mouse button press in +the widget. If <I>row</I> or <I>col</I> is not specified, +it returns a tuple of both border indices +(an empty item means no border). Otherwise, +just the specified item is returned. +<P> +<I>pathName</I> <B>border</B> <B>dragto</B> <I>x</I> <I>y</I><BR> + +This command computes the difference between +its <I>x</I> and <I>y</I> arguments and the <I>x</I> and <I>y</I> arguments +to the last <B>border</B> <B>mark</B> command for +the widget. It then adjusts the previously +marked border by the difference. This command +is typically associated with mouse +motion events in the widget, to produce the +effect of interactive border resizing. +<P> +<I>pathName</I> <B>cget</B> <I>option</I><BR> + +Returns the current value of the configuration +option given by <I>option</I>. <I>Option</I> may have any of the +values accepted by the <B>table</B> command. +<P> +<I>pathName</I> <B>clear</B> <I>option</I> ?<I>first</I>? ?<I>last</I>?<BR> + +This command is a convenience routine to clear certain +state information managed by the table. <I>first</I> +and <I>last</I> represent valid table indices. If neither +are specified, then the command operates on the +whole table. The following options are recognized: +<P> +<I>pathName</I> <B>clear</B> <B>cache</B> ?<I>first</I>? ?<I>last</I>? +Clears the specified section of the cache, +if the table has been keeping one. +<P> +<I>pathName</I> <B>clear</B> <B>sizes</B> ?<I>first</I>? ?<I>last</I>? +Clears the specified row and column areas of +specific height/width dimensions. When just +one index is specified, for example <B>2,0</B>, +that is interpreted as row 2 <B>and</B> column 0. +<P> +<I>pathName</I> <B>clear</B> <B>tags</B> ?<I>first</I>? ?<I>last</I>? +Clears the specified area of tags (all row, +column and cell tags). +<P> +<I>pathName</I> <B>clear</B> <B>all</B> ?<I>first</I>? ?<I>last</I>? +Performs all of the above clear functions on +the specified area. +<P> +<I>pathName</I> <B>configure</B> ?<I>option</I>? ?<I>value</I> <I>option</I> <I>value</I> <I>...</I>? +Query or modify the configuration options of the +widget. If no <I>option</I> is specified, returns a list +describing all of the available options for <I>path</I><B>_N</B><I>ame</I> +(see <B>Tk_ConfigureInfo</B> for information on the +format of this list). If <I>option</I> is specified with +no <I>value</I>, then the command returns a list describing +the one named option (this list will be identical +to the corresponding sublist of the value +returned if no <I>option</I> is specified). If one or +more <I>option-value</I> pairs are specified, then the +command modifies the given widget option(s) to have +the given value(s); in this case the command +returns an empty string. <I>Option</I> may have any of +the values accepted by the <B>table</B> command. +<P> +<I>pathName</I> <B>curselection</B> ?<I>value</I>?<BR> + +With no arguments, it returns the sorted indices of +the currently selected cells. Otherwise it sets +all the selected cells to the given value. The set +has no effect if there is no associated Tcl array +or the state is disabled. +<P> +<I>pathName</I> <B>curvalue</B> ?<I>value</I>?<BR> + +If no value is given, the value of the cell being +edited (indexed by <B>active</B>) is returned, else it is +set to the given value. +<P> +<I>pathName</I> <B>delete</B> <I>option</I> <I>arg</I> ?<I>arg</I>?<BR> + +This command is used to delete various things in a +table. It has several forms, depending on the +<I>option</I>: +<I>pathName</I> <B>delete</B> <B>active</B> <I>index</I> ?<I>index</I>? +Deletes text from the active cell. If only +one index is given, it deletes the character +after that index, otherwise it deletes from +the first index to the second. <I>index</I> can be +a number, <B>insert</B> or <B>end</B>. +<P> +<I>pathName</I> <B>delete</B> <B>cols</B> ?<I>switches</I>? <I>index</I> ?<I>count</I>? +Deletes <I>count</I> cols starting at (and including) +col <I>index</I>. The <I>index</I> will be constrained +to the limits of the tables. If +<I>count</I> is negative, it deletes cols to the +left. Otherwise it deletes cols to the +right. <I>count</I> defaults to 1 (meaning just +the column specified). At the moment, spans +are not adjusted with this action. Optional +switches are: + +<DL> + +<DT><B>-holddimensions</B></DT></DT> +<DD> +Causes the table cols to be unaffected +by the deletion (empty cols +may appear). By default the dimensions +are adjusted by <B>count</B>. +</DD> + +<DT><B>-holdselection</B></DT></DT> +<DD> +Causes the selection to be maintained +on the absolute cells values. +Otherwise, the selection will be +cleared.. +</DD> + +<DT><B>-holdtags</B></DT></DT> +<DD> +Causes the tags specified by the <I>tag</I> +method to not move along with the +data. Also prevents specific widths +set by the <I>width</I> method from being +adjusted. By default, these tags +are properly adjusted. +</DD> + +<DT><B>-holdwindows</B></DT></DT> +<DD> +Causes the embedded windows created +with the <I>window</I> method to not move +along with the data. By default, +these windows are properly adjusted. +</DD> + +<DT><B>-keeptitles</B></DT></DT> +<DD> +Prevents title area cells from being +changed. Otherwise they are treated +just like regular cells and will +move as specified. +</DD> + +<DT><B>--</B> </DT></DT> +<DD> Signifies the end of the switches. +</DD> +</DL> +<P> +<I>pathName</I> <B>delete</B> <B>rows</B> ?<I>switches</I>? <I>index</I> ?<I>count</I>? +Deletes <B>count</B> rows starting at (and +including) row <B>index</B>. If <B>count</B> is negative, +it deletes rows going up. Otherwise it +deletes rows going down. The selection will +be cleared. The switches are the same as +those for column deletion. +<P> +<I>pathName</I> <B>get</B> <I>first</I> ?<I>last</I>?<BR> + +Returns the value of the cells specified by the +table indices <I>first</I> and (optionally) <I>last</I> in a +list. +<P> +<I>pathName</I> <B>height</B> ?<I>row</I>? ?<I>value</I> <I>row</I> <I>value</I> <I>...</I>? +If no <I>row</I> is specified, returns a list describing +all rows for which a height has been set. If <B>row</B> +is specified with no value, it prints out the +height of that row in characters (positive number) +or pixels (negative number). If one or more +<I>row-value</I> pairs are specified, then it sets each +row to be that height in lines (positive number) or +pixels (negative number). If <I>value</I> is <I>default</I>, +then the row uses the default height, specified by +<B>-rowheight</B>. +<P> +<I>pathName</I> <B>hidden</B> ?<I>index</I>? ?<I>index</I> <I>...</I>?<BR> + +When called without args, it returns all the <I>hidden</I> +cells (those cells covered by a spanning cell). If +one index is specified, it returns the spanning +cell covering that index, if any. If multiple +indices are specified, it returns 1 if all indices +are hidden cells, 0 otherwise. +<P> +<I>pathName</I> <B>icursor</B> ?<I>arg</I>?<BR> + +With no arguments, prints out the location of the +insertion cursor in the active cell. With one +argument, sets the cursor to that point in the +string. 0 is before the first character, you can +also use <B>insert</B> or <B>end</B> for the current insertion +point or the end of the text. If there is no +active cell, or the cell or table is disabled, this +will return -1. +<P> +<I>pathName</I> <B>index</B> <I>index</I> ?<I>row|col</I>?<BR> + +Returns the integer cell coordinate that corresponds +to <I>index</I> in the form row,col. If <B>row</B> or <B>col</B> +is specified, then only the row or column index is +returned. +<P> +<I>pathName</I> <B>insert</B> <I>option</I> <I>arg</I> <I>arg</I><BR> + +This command is used to into various things into a +table. It has several forms, depending on the +<I>option</I>: +<P> +<I>pathName</I> <B>insert</B> <B>active</B> <I>index</I> <I>value</I> +The <I>value</I> is a text string which is inserted +at the <I>index</I> postion of the active cell. +The cursor is then positioned after the new +text. <I>index</I> can be a number, <B>insert</B> or <B>end</B>. +<P> +<I>pathName</I> <B>insert</B> <B>cols</B> ?<I>switches</I>? <I>index</I> ?<I>count</I>? +Inserts <B>count</B> cols starting at col <B>index</B>. +If <B>count</B> is negative, it inserts before the +specified col. Otherwise it inserts after +the specified col. The selection will be +cleared. The switches are the same as those +for column deletion. +<P> +<I>pathName</I> <B>insert</B> <B>rows</B> ?<I>switches</I>? <I>index</I> ?<I>count</I>? +Inserts <B>count</B> rows starting at row <B>index</B>. +If <B>count</B> is negative, it inserts before the +specified row. Otherwise it inserts after +the specified row. The selection will be +cleared. The switches are the same as those +for column deletion. +<P> +<I>pathName</I> <B>reread</B><BR> + +Rereads the old contents of the cell back into the +editing buffer. Useful for a key binding when +<Escape> is pressed to abort the edit (a default +binding). +<P> +<I>pathName</I> <B>scan</B> <I>option</I> <I>args</I><BR> + +This command is used to implement scanning on +tables. It has two forms, depending on <I>option</I>: +<P> +<I>pathName</I> <B>scan</B> <B>mark</B> <I>x</I> <I>y</I><BR> + +Records <I>x</I> and <I>y</I> and the current view in the +table window; used in conjunction with +later <B>scan</B> <B>dragto</B> commands. Typically this +command is associated with a mouse button +press in the widget. It returns an empty +string. +<P> +<I>pathName</I> <B>scan</B> <B>dragto</B> <I>x</I> <I>y</I>.<BR> + +This command computes the difference between +its <I>x</I> and <I>y</I> arguments and the <I>x</I> and <I>y</I> arguments +to the last <B>scan</B> <B>mark</B> command for the +widget. It then adjusts the view by 5 times +the difference in coordinates. This command +is typically associated with mouse motion +events in the widget, to produce the effect +of dragging the list at high speed through +the window. The return value is an empty +string. +<P> +<I>pathName</I> <B>see</B> <I>index</I><BR> + +Adjust the view in the table so that the cell given +by <I>index</I> is positioned as the cell one off from top +left (excluding title rows and columns) if the cell +is not currently visible on the screen. The actual +cell may be different to keep the screen full. +<P> +<I>pathName</I> <B>selection</B> <I>option</I> <I>arg</I><BR> + +This command is used to adjust the selection within +a table. It has several forms, depending on +<I>option</I>: +<P> +<I>pathName</I> <B>selection</B> <B>anchor</B> <I>index</I><BR> + +Sets the selection anchor to the cell given +by <I>index</I>. The selection anchor is the end +of the selection that is fixed while dragging +out a selection with the mouse. The +index <B>anchor</B> may be used to refer to the +anchor cell. +<P> +<I>pathName</I> <B>selection</B> <B>clear</B> <I>first</I> ?<I>last</I>? +If any of the cells between <I>first</I> and <I>last</I> +(inclusive) are selected, they are deselected. +The selection state is not changed +for cells outside this range. <I>first</I> may be +specified as <B>all</B> to remove the selection +from all cells. +<P> +<I>pathName</I> <B>selection</B> <B>includes</B> <I>index</I> +Returns 1 if the cell indicated by <I>index</I> is +currently selected, 0 if it isn't. +<P> +<I>pathName</I> <B>selection</B> <B>set</B> <I>first</I> ?<I>last</I>? +Selects all of the cells in the range +between <I>first</I> and <I>last</I>, inclusive, without +affecting the selection state of cells outside +that range. +<P> +<I>pathName</I> <B>set</B> ?<I>row|col</I>? <I>index</I> ?<I>value</I>? ?<I>index</I> <I>value</I> <I>...</I>? +Sets the specified index to the associated value. +Table validation will not be triggered via this +method. If <B>row</B> or <B>col</B> precedes the list of +index/value pairs, then the value is assumed to be +a Tcl list whose values will be split and set into +the subsequent columns (if <B>row</B> is specified) or +rows (for <B>col</B>). For example, <B>set</B> <B>row</B> <B>2,3</B> <B>{2,3</B> <B>2,4</B> +<B>2,5}</B> will set 3 cells, from 2,3 to 2,5. The setting +of cells is silently bounded by the known +table dimensions. +<P> +<I>pathName</I> <B>spans</B> ?<I>index</I>? ?<I>rows,cols</I> <I>index</I> <I>rows,cols</I> <I>...</I>? +This command is used to manipulate row/col spans. +When called with no arguments, all known spans are +returned as a list of tuples of the form {index +span}. When called with only the <I>index</I>, the span +for that <I>index</I> only is returned, if any. Otherwise +an even number of <I>index</I> <I>rows,cols</I> pairs are used to +set spans. A span starts at the <I>index</I> and +continues for the specified number of rows and +cols. Negative spans are not supported. A span of +0,0 unsets any span on that cell. See EXAMPLES for +more info. +<P> +<I>pathName</I> <B>tag</B> option ?<I>arg</I> <I>arg</I> <I>...</I>?<BR> + +This command is used to manipulate tags. The exact +behavior of the command depends on the <I>option</I> argument +that follows the <B>tag</B> argument. <I>cget</I>, <I>cell</I>, +and <I>row|col</I> complain about unknown tag names. The +following forms of the command are currently supported: +<P> +<I>pathName</I> <B>tag</B> <B>cell</B> <I>tagName</I> <I>?index</I> <I>...?</I> +With no arguments, prints out the list of +cells that use the <I>tag</I>. Otherwise it sets +the specified cells to use the named tag, +replacing any tag that may have been set +using this method before. If <I>tagName</I> is {}, +the cells are reset to the default <I>tag</I>. +Tags added during -*tagcommand evaluation do +not register here. If <I>tagName</I> does not +exist, it will be created with the default +options. +<P> +<I>pathName</I> <B>tag</B> <B>cget</B> <I>tagName</I> <I>option</I> +This command returns the current value of +the option named <I>option</I> associated with the +tag given by <I>tagName</I>. <I>Option</I> may have any +of the values accepted by the <B>tag</B> <B>configure</B> +widget command. +<P> +<I>pathName</I> <B>tag</B> <B>col</B> <I>tagName</I> <I>?col</I> <I>...?</I> +With no arguments, prints out the list of +cols that use the <I>tag</I>. Otherwise it sets +the specified columns to use the named tag, +replacing any tag that may have been set +using this method before. If <I>tagName</I> is {}, +the cols are reset to the default <I>tag</I>. Tags +added during -coltagcommand evaluation do +not register here. If <I>tagName</I> does not +exist, it will be created with the default +options. +<P> +<I>pathName</I> <B>tag</B> <B>configure</B> <I>tagName</I> ?<I>option</I>? ?<I>value</I>? +?<I>option</I> <I>value</I> <I>...</I>?<BR> + +This command is similar to the <B>configure</B> +widget command except that it modifies +options associated with the tag given by +<I>tagName</I> instead of modifying options for the +overall table widget. If no <I>option</I> is specified, +the command returns a list describing +all of the available options for <I>tagName</I> +(see <B>Tk_ConfigureInfo</B> for information on the +format of this list). If <I>option</I> is specified +with no <I>value</I>, then the command returns +a list describing the one named option (this +list will be identical to the corresponding +sublist of the value returned if no <I>option</I> +is specified). If one or more <I>option-value</I> +pairs are specified, then the command modifies +the given option(s) to have the given +value(s) in <I>tagName</I>; in this case the command +returns an empty string. See TAGS +above for details on the options available +for tags. +<P> +<I>pathName</I> <B>tag</B> <B>delete</B> <I>tagName</I><BR> + +Deletes a tag. No error if the tag does not +exist. +<P> +<I>pathName</I> <B>tag</B> <B>exists</B> <I>tagName</I><BR> + +Returns 1 if the named tag exists, 0 otherwise. +<P> +<I>pathName</I> <B>tag</B> <B>includes</B> <I>tagName</I> <I>index</I> +Returns 1 if the specified index has the +named tag, 0 otherwise. +<P> +<I>pathName</I> <B>tag</B> <B>lower</B> <I>tagName</I> ?<I>belowThis</I>? +Lower the priority of the named tag. If +<I>belowThis</I> is not specified, then the tag's +priority is lowered to the bottom, otherwise +it is lowered to one below <I>belowThis</I>. +<P> +<I>pathName</I> <B>tag</B> <B>names</B> ?<I>pattern</I>?<BR> + +If no pattern is specified, shows the names +of all defined tags. Otherwise the <I>pattern</I> +is used as a glob pattern to show only tags +matching that pattern. Tag names are +returned in priority order (highest priority +tag first). +<P> +<I>pathName</I> <B>tag</B> <B>raise</B> <I>tagName</I> ?<I>aboveThis</I>? +Raise the priority of the named tag. If +<I>aboveThis</I> is not specified, then the tag's +priority is raised to the top, otherwise it +is raised to one above <I>aboveThis</I>. +<P> +<I>pathName</I> <B>tag</B> <B>row</B> <I>tagName</I> ?<I>row</I> <I>...</I>? +With no arguments, prints out the list of +rows that use the <I>tag</I>. Otherwise it sets +the specified columns to use the named tag, +replacing any tag that may have been set +using this method before. If <I>tagName</I> is {}, +the rows are reset to use the default tag. +Tags added during -rowtagcommand evaluation +do not register here. If <I>tagName</I> does not +exist, it will be created with the default +options. +<P> +<I>pathName</I> <B>validate</B> <I>index</I><BR> + +Explicitly validates the specified index based on +the current <B>-validatecommand</B> and returns 0 or 1 +based on whether the cell was validated. +<P> +<I>pathName</I> <B>width</B> ?<I>col</I>? ?<I>value</I> <I>col</I> <I>value</I> <I>...</I>? +If no <I>col</I> is specified, returns a list describing +all cols for which a width has been set. If <B>col</B> is +specified with no value, it prints out the width of +that col in characters (positive number) or pixels +(negative number). If one or more <I>col-value</I> pairs +are specified, then it sets each col to be that +width in characters (positive number) or pixels +(negative number). If <I>value</I> is <I>default</I>, then the +col uses the default width, specified by <B>-colwidth</B>. +<P> +<I>pathName</I> <B>window</B> option ?<I>arg</I> <I>arg</I> <I>...</I>?<BR> + +This command is used to manipulate embedded windows. +The exact behavior of the command depends on +the <I>option</I> argument that follows the <B>window</B> argument. +The following forms of the command are currently +supported: +<P> +<I>pathName</I> <B>window</B> <B>cget</B> <I>index</I> <I>option</I> +This command returns the current value of +the option named <I>option</I> associated with the +window given by <I>index</I>. <I>Option</I> may have any +of the values accepted by the <B>window</B> <B>configure</B> +widget command. +<P> +<I>pathName</I> <B>window</B> <B>configure</B> <I>index</I> ?<I>option</I>? ?<I>value</I>? +?<I>option</I> <I>value</I> <I>...</I>?<BR> + +This command is similar to the <B>configure</B> +widget command except that it modifies +options associated with the embedded window +given by <I>index</I> instead of modifying options +for the overall table widget. If no <I>option</I> +is specified, the command returns a list +describing all of the available options for +<I>index</I> (see <B>Tk_ConfigureInfo</B> for information +on the format of this list). If <I>option</I> is +specified with no <I>value</I>, then the command +returns a list describing the one named +option (this list will be identical to the +corresponding sublist of the value returned +if no <I>option</I> is specified). If one or more +<I>option-value</I> pairs are specified, then the +command modifies the given option(s) to have +the given value(s) in <I>index</I>; in this case +the command returns an empty string. See +EMBEDDED WINDOWS above for details on the +options available for windows. +<P> +<I>pathName</I> <B>window</B> <B>delete</B> <I>index</I> ?<I>index</I> <I>...</I>? +Deletes an embedded window from the table. +The associated window will also be deleted. +<P> +<I>pathName</I> <B>window</B> <B>move</B> <I>indexFrom</I> <I>indexTo</I> +Moves an embedded window from one cell to +another. If a window already exists in the +target cell, it will be deleted. +<P> +<I>pathName</I> <B>window</B> <B>names</B> ?<I>pattern</I>?<BR> + +If no pattern is specified, shows the cells +of all embedded windows. Otherwise the <I>pat</I><B>_</B>t<I>ern</I> +is used as a glob pattern to show only +cells matching that pattern. +<P> +<I>pathName</I> <B>xview</B> <I>args</I><BR> + +This command is used to query and change the horizontal +position of the information in the widget's +window. It can take any of the following forms: +<P> +<I>pathName</I> <B>xview</B><BR> + +Returns a list containing two elements. +Each element is a real fraction between 0 +and 1; together they describe the horizontal +span that is visible in the window. For +example, if the first element is .2 and the +second element is .6, 20% of the table's +text is off-screen to the left, the middle +40% is visible in the window, and 40% of the +text is off-screen to the right. These are +the same values passed to scrollbars via the +<B>-xscrollcommand</B> option. +<P> +<I>pathName</I> <B>xview</B> <I>index</I><BR> + +Adjusts the view in the window so that the +column given by <I>index</I> is displayed at the +left edge of the window. +<P> +<I>pathName</I> <B>xview</B> <B>moveto</B> <I>fraction</I><BR> + +Adjusts the view in the window so that <I>frac</I><B>_</B>t<I>ion</I> +of the total width of the table text is +off-screen to the left. <I>fraction</I> must be a +fraction between 0 and 1. +<P> +<I>pathName</I> <B>xview</B> <B>scroll</B> <I>number</I> <I>what</I> +This command shifts the view in the window +left or right according to <I>number</I> and <I>what</I>. +<I>Number</I> must be an integer. <I>What</I> must be +either <B>units</B> or <B>pages</B> or an abbreviation of +one of these. If <I>what</I> is <B>units</B>, the view +adjusts left or right by <I>number</I> character +units (the width of the <B>0</B> character) on the +display; if it is <B>pages</B> then the view +adjusts by <I>number</I> screenfuls. If <I>number</I> is +negative then characters farther to the left +become visible; if it is positive then +characters farther to the right become visible. +<P> +<I>pathName</I> <B>yview</B> <I>?args</I>?<BR> + +This command is used to query and change the vertical +position of the text in the widget's window. +It can take any of the following forms: +<P> +<I>pathName</I> <B>yview</B><BR> + +Returns a list containing two elements, both +of which are real fractions between 0 and 1. +The first element gives the position of the +table element at the top of the window, relative +to the table as a whole (0.5 means it +is halfway through the table, for example). +The second element gives the position of the +table element just after the last one in the +window, relative to the table as a whole. +These are the same values passed to scrollbars +via the <B>-yscrollcommand</B> option. +<P> +<I>pathName</I> <B>yview</B> <I>index</I><BR> + +Adjusts the view in the window so that the +row given by <I>index</I> is displayed at the top +of the window. +<P> +<I>pathName</I> <B>yview</B> <B>moveto</B> <I>fraction</I><BR> + +Adjusts the view in the window so that the +element given by <I>fraction</I> appears at the top +of the window. <I>Fraction</I> is a fraction +between 0 and 1; 0 indicates the first element +in the table, 0.33 indicates the element +one-third the way through the table, +and so on. +<P> +<I>pathName</I> <B>yview</B> <B>scroll</B> <I>number</I> <I>what</I> +This command adjusts the view in the window +up or down according to <I>number</I> and <I>what</I>. +<I>Number</I> must be an integer. <I>What</I> must be +either <B>units</B> or <B>pages</B>. If <I>what</I> is <B>units</B>, +the view adjusts up or down by <I>number</I> lines; +if it is <B>pages</B> then the view adjusts by <I>num</I><B>_</B>b<I>er</I> +screenfuls. If <I>number</I> is negative then +earlier elements become visible; if it is +positive then later elements become visible. + +<H2><A NAME="sect13" HREF="#toc13"><B>Default</B> <B>Bindings</B></A></H2> + +<P> +The initialization creates class bindings that give the +following default behaviour: + +<DL> + +<DT>[1] </DT></DT> +<DD> Clicking Button-1 in a cell activates that cell. +Clicking into an already active cell moves the +insertion cursor to the character nearest the +mouse. +</DD> + +<DT>[2] </DT></DT> +<DD> Moving the mouse while Button-1 is pressed will +stroke out a selection area. Exiting while Button-1 +is pressed causing scanning to occur on the +table along with selection. +</DD> + +<DT>[3] </DT></DT> +<DD> Moving the mouse while Button-2 is pressed causes +scanning to occur without any selection. +</DD> + +<DT>[4] </DT></DT> +<DD> Home moves the table to have the origin in view. +</DD> + +<DT>[5] </DT></DT> +<DD> End moves the table to have the <B>end</B> cell in view. +</DD> + +<DT>[6] </DT></DT> +<DD> Control-Home moves the table to the origin and +activates that cell. +</DD> + +<DT>[7] </DT></DT> +<DD> Control-End moves the table to the end and activates +that cell. +</DD> + +<DT>[8] </DT></DT> +<DD> Shift-Control-Home extends the selection to the +origin. +</DD> + +<DT>[9] </DT></DT> +<DD> Shift-Control-End extends the selection to the end. +</DD> + +<DT>[10] </DT></DT> +<DD>The left, right, up and down arrows move the active +cell. +</DD> +</DL> +<P> +[11] Shift-<arrow> extends the selection in that direction. +<P> +[12] Control-leftarrow and Control-rightarrow move the +insertion cursor within the cell. + +<DL> + +<DT>[13] </DT></DT> +<DD>Control-slash selects all the cells. +</DD> +</DL> +<P> +[14] Control-backslash clears selection from all the +cells. +<P> +[15] Backspace deletes the character before the insertion +cursor in the active cell. +<P> +[16] Delete deletes the character after the insertion +cursor in the active cell. +<P> +[17] Escape rereads the value of the active cell from +the specified data source, discarding any edits +that have may been performed on the cell. +<P> +[18] Control-a moves the insertion cursor to the beginning +of the active cell. +<P> +[19] Control-e moves the insertion cursor to the end of +the active cell. +<P> +[20] Control-minus and Control-equals decrease and +increase the width of the column with the active +cell in it. +<P> +[21] Moving the mouse while Button-3 (the right button +on Windows) is pressed while you are over a border +will cause interactive resizing of that row and/or +column to occur, based on the value of <B>-resizeborders</B>. +<P> +Some bindings may have slightly different behavior dependent +on the <B>-selectionmode</B> of the widget. +<P> +If the widget is disabled using the <B>-state</B> option, then +its view can still be adjusted and cells can still be +selected, but no insertion cursor will be displayed and no +cell modifications will take place. +<P> +The behavior of tables can be changed by defining new +bindings for individual widgets or by redefining the class +bindings. The default bindings are either compiled in or +read from a file expected to correspond to: «[lindex +$tcl_pkgPath 0]/Tktable<version>/tkTable.tcl". + +<H2><A NAME="sect14" HREF="#toc14"><B>Performance</B> <B>Issues</B></A></H2> + +<P> +The number of rows and columns or a table widget should +not significantly affect the speed of redraw. Recalculation +and redraw of table parameters and cells is +restricted as much as possible. +<P> +The display cell with the insert cursor is redrawn each +time the cursor blinks, which causes a steady stream of +graphics traffic. Set the <B>-insertofftime</B> option to 0 +avoid this. The use of a <B>-command</B> with the table without +a cache can cause significant slow-down, as the command is +called once for each request of a cell value. + +<H2><A NAME="sect15" HREF="#toc15"><B>Examples</B></A></H2> + +<P> +Set the topleft title area to be one spanning cell. This +overestimates both row and column span by one, but the +command does all the constraining for us. +$table span [$table cget -roworigin],[$table cget -colorigin] [$table cget -titlerows],[$table cget -titlecols] +Force a table window refresh (useful for the slight chance +that a bug in the table is not causing proper refresh): +$table configure -padx [$table cget -padx] + +<H2><A NAME="sect16" HREF="#toc16"><B>Keywords</B></A></H2> + +<P> +table, widget, extension +<P> + +<HR><P> +<A NAME="toc"><B>Table of Contents</B></A><P> +<UL> +<LI><A NAME="toc0" HREF="#sect0">Name</A></LI> +<LI><A NAME="toc1" HREF="#sect1">Synopsis</A></LI> +<LI><A NAME="toc2" HREF="#sect2">Standard Options</A></LI> +<LI><A NAME="toc3" HREF="#sect3">Widget-specific Options</A></LI> +<LI><A NAME="toc4" HREF="#sect4">Description</A></LI> +<LI><A NAME="toc5" HREF="#sect5">Initialization</A></LI> +<LI><A NAME="toc6" HREF="#sect6">Indices</A></LI> +<LI><A NAME="toc7" HREF="#sect7">Tags</A></LI> +<LI><A NAME="toc8" HREF="#sect8">Embedded Windows</A></LI> +<LI><A NAME="toc9" HREF="#sect9">the Selection</A></LI> +<LI><A NAME="toc10" HREF="#sect10">Row/Col Spanning</A></LI> +<LI><A NAME="toc11" HREF="#sect11">Command Substitution</A></LI> +<LI><A NAME="toc12" HREF="#sect12">Widget Command</A></LI> +<LI><A NAME="toc13" HREF="#sect13">Default Bindings</A></LI> +<LI><A NAME="toc14" HREF="#sect14">Performance Issues</A></LI> +<LI><A NAME="toc15" HREF="#sect15">Examples</A></LI> +<LI><A NAME="toc16" HREF="#sect16">Keywords</A></LI> +</UL> +</BODY></HTML> diff --git a/libgui/library/Makefile.in b/libgui/library/Makefile.in index 01461dc4f73..025fe879164 100644 --- a/libgui/library/Makefile.in +++ b/libgui/library/Makefile.in @@ -59,6 +59,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : host_alias = @host_alias@ host_triplet = @host@ +AR = @AR@ BFDHDIR = @BFDHDIR@ BFDLIB = @BFDLIB@ CC = @CC@ @@ -84,7 +85,6 @@ ITCLLIB = @ITCLLIB@ ITCLMKIDX = @ITCLMKIDX@ ITCLSH = @ITCLSH@ ITCL_BUILD_LIB_SPEC = @ITCL_BUILD_LIB_SPEC@ -ITCL_DIR = @ITCL_DIR@ ITCL_LIB_FILE = @ITCL_LIB_FILE@ ITCL_LIB_FULL_PATH = @ITCL_LIB_FULL_PATH@ ITK_BUILD_LIB_SPEC = @ITK_BUILD_LIB_SPEC@ @@ -109,6 +109,7 @@ SIMHDIR = @SIMHDIR@ SIMLIB = @SIMLIB@ TCLCONFIG = @TCLCONFIG@ TCLHDIR = @TCLHDIR@ +TCL_BIN_DIR = @TCL_BIN_DIR@ TCL_BUILD_LIB_SPEC = @TCL_BUILD_LIB_SPEC@ TCL_CFLAGS = @TCL_CFLAGS@ TCL_DEFS = @TCL_DEFS@ @@ -155,15 +156,12 @@ PACKAGES = combobox.tcl guidir = $(datadir)/cygnus/gui gui_DATA = tclIndex pkgIndex.tcl $(TCL) $(PACKAGES) -@TCL_SHARED_TRUE@SET_LIB_PATH = \ -@TCL_SHARED_TRUE@$(RPATH_ENVVAR)=$$here/../../tcl/unix:$$here/../../itcl/itcl/unix:$$$(RPATH_ENVVAR); export $(RPATH_ENVVAR); -@TCL_SHARED_FALSE@SET_LIB_PATH = \ +@TCL_SHARED_TRUE@SET_LIB_PATH = @TCL_SHARED_TRUE@$(RPATH_ENVVAR)=$$here/../../tcl/unix:$$here/../../itcl/itcl/unix:$$$(RPATH_ENVVAR); export $(RPATH_ENVVAR); +@TCL_SHARED_FALSE@SET_LIB_PATH = WISH = wish -@CROSS_COMPILING_TRUE@ITCL_SH = \ -@CROSS_COMPILING_TRUE@itclsh -@CROSS_COMPILING_FALSE@ITCL_SH = \ -@CROSS_COMPILING_FALSE@$$here/../../itcl/itcl/unix/itclsh$(EXEEXT) +@CROSS_COMPILING_TRUE@ITCL_SH = @CROSS_COMPILING_TRUE@itclsh +@CROSS_COMPILING_FALSE@ITCL_SH = @CROSS_COMPILING_FALSE@$$here/../../itcl/itcl/unix/itclsh$(EXEEXT) ETAGS_ARGS = --lang=none --regex='/[ \t]*\(proc\|method\|itcl_class\)[ \t]+\([^ \t]+\)/\1/' $(TCL) --lang=auto mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs @@ -176,7 +174,7 @@ DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) -TAR = tar +TAR = gtar GZIP_ENV = --best all: all-redirect .SUFFIXES: @@ -322,7 +320,7 @@ tclIndex: $(TCL) here=`pwd`; \ $(SET_LIB_PATH) \ cd $(srcdir) && \ - echo " auto_mkindex `pwd` $(TCL)" | $(ITCL_SH) + echo "auto_mkindex $(LIBGUI_LIBRARY_DIR) $(TCL)" | @ITCL_SH@ pkgIndex.tcl: @MAINT@ $(PACKAGES) here=`pwd`; \ diff --git a/libgui/src/Makefile.in b/libgui/src/Makefile.in index 637fa24f5d8..63e73211fdc 100644 --- a/libgui/src/Makefile.in +++ b/libgui/src/Makefile.in @@ -60,6 +60,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : host_alias = @host_alias@ host_triplet = @host@ +AR = @AR@ BFDHDIR = @BFDHDIR@ BFDLIB = @BFDLIB@ CC = @CC@ @@ -85,7 +86,6 @@ ITCLLIB = @ITCLLIB@ ITCLMKIDX = @ITCLMKIDX@ ITCLSH = @ITCLSH@ ITCL_BUILD_LIB_SPEC = @ITCL_BUILD_LIB_SPEC@ -ITCL_DIR = @ITCL_DIR@ ITCL_LIB_FILE = @ITCL_LIB_FILE@ ITCL_LIB_FULL_PATH = @ITCL_LIB_FULL_PATH@ ITCL_SH = @ITCL_SH@ @@ -110,6 +110,7 @@ SIMHDIR = @SIMHDIR@ SIMLIB = @SIMLIB@ TCLCONFIG = @TCLCONFIG@ TCLHDIR = @TCLHDIR@ +TCL_BIN_DIR = @TCL_BIN_DIR@ TCL_BUILD_LIB_SPEC = @TCL_BUILD_LIB_SPEC@ TCL_CFLAGS = @TCL_CFLAGS@ TCL_DEFS = @TCL_DEFS@ @@ -145,8 +146,7 @@ AUTOMAKE_OPTIONS = cygnus noinst_LIBRARIES = libgui.a -@INSTALL_LIBGUI_TRUE@include_HEADERS = \ -@INSTALL_LIBGUI_TRUE@\ +@INSTALL_LIBGUI_TRUE@include_HEADERS = @INSTALL_LIBGUI_TRUE@\ @INSTALL_LIBGUI_TRUE@ guitcl.h subcommand.h TBL_VERSION = 2.1 @@ -198,7 +198,6 @@ tclwinpath.$(OBJEXT) tclmsgbox.$(OBJEXT) tclcursor.$(OBJEXT) \ tkTable.$(OBJEXT) tkTableCmd.$(OBJEXT) tkTableCell.$(OBJEXT) \ tkTableTag.$(OBJEXT) tkTableWin.$(OBJEXT) tkWinPrintText.$(OBJEXT) \ tkWinPrintCanvas.$(OBJEXT) tkWarpPointer.$(OBJEXT) -AR = ar CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) @@ -210,7 +209,7 @@ DIST_COMMON = Makefile.am Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) -TAR = tar +TAR = gtar GZIP_ENV = --best SOURCES = $(libgui_a_SOURCES) OBJECTS = $(libgui_a_OBJECTS) diff --git a/libgui/src/subcommand.c b/libgui/src/subcommand.c index 29e7ea12f18..2ec51d339e6 100644 --- a/libgui/src/subcommand.c +++ b/libgui/src/subcommand.c @@ -26,7 +26,7 @@ subcommand_deleted (ClientData cd) if (data->delete) (*data->delete) (data->subdata); - Tcl_Free ((char *) data); + ckfree ((char *) data); } /* This function implements any Tcl command registered as having @@ -113,7 +113,7 @@ ide_create_command_with_subcommands (Tcl_Interp *interp, char *name, } } - data = (struct subcommand_clientdata *) Tcl_Alloc (sizeof *data); + data = (struct subcommand_clientdata *) ckalloc (sizeof *data); data->commands = table; data->subdata = subdata; data->delete = delete; diff --git a/libgui/src/tclgetdir.c b/libgui/src/tclgetdir.c index 7d70aef0012..f3b662f0dec 100644 --- a/libgui/src/tclgetdir.c +++ b/libgui/src/tclgetdir.c @@ -237,7 +237,7 @@ get_directory_command (ClientData cd, Tcl_Interp *interp, int argc, re-eval. This is a lot less efficient, but it doesn't really matter. */ - new_args = (char **) Tcl_Alloc ((argc + 2) * sizeof (char *)); + new_args = (char **) ckalloc ((argc + 2) * sizeof (char *)); new_args[0] = "tk_getOpenFile"; new_args[1] = "-choosedir"; @@ -249,8 +249,8 @@ get_directory_command (ClientData cd, Tcl_Interp *interp, int argc, merge = Tcl_Merge (argc + 2, new_args); result = Tcl_GlobalEval (interp, merge); - Tcl_Free (merge); - Tcl_Free ((char *) new_args); + ckfree (merge); + ckfree ((char *) new_args); return result; } diff --git a/libgui/src/tclhelp.c b/libgui/src/tclhelp.c index 199cff77d2e..d3f057a145e 100644 --- a/libgui/src/tclhelp.c +++ b/libgui/src/tclhelp.c @@ -109,12 +109,12 @@ help_command_deleted (ClientData cd) Tcl_DeleteExitHandler (help_command_atexit, cd); if (hdata->filename != NULL) - free (hdata->filename); + ckfree (hdata->filename); if (hdata->header_filename != NULL) - free (hdata->header_filename); + ckfree (hdata->header_filename); if (hdata->hash_initialized) Tcl_DeleteHashTable (&hdata->topic_hash); - Tcl_Free ((char *) hdata); + ckfree ((char *) hdata); } /* Initialize the help system: choose a window, and set up the topic @@ -223,8 +223,10 @@ help_initialize_command (ClientData cd, Tcl_Interp *interp, int argc, { struct help_command_data *hdata = (struct help_command_data *) cd; - hdata->filename = strdup (argv[2]); - hdata->header_filename = strdup (argv[3]); + hdata->filename = ckalloc (strlen (argv[2]) + 1); + strcpy (hdata->filename, argv[2]); + hdata->header_filename = ckalloc (strlen (argv[3]) + 1); + strcpy (hdata->header_filename, argv[3]); return TCL_OK; } @@ -301,7 +303,8 @@ help_display_file_command (ClientData cd, Tcl_Interp *interp, int argc, char **a { struct help_command_data *hdata = (struct help_command_data *) cd; FILE *e; - DWORD topic_id = 0; /* default topic id is 0 which brings up the find dialog */ + int id = 0; + DWORD topic_id; /* default topic id is 0 which brings up the find dialog */ /* We call Help initialize just to make sure the window handle is setup */ /* We don't care about the finding the main help file and checking the */ @@ -322,10 +325,11 @@ help_display_file_command (ClientData cd, Tcl_Interp *interp, int argc, char **a fclose (e); if (argc > 3) { - if ( Tcl_GetInt (interp, argv[3], &topic_id) != TCL_OK ) + if ( Tcl_GetInt (interp, argv[3], &id) != TCL_OK ) return TCL_ERROR; } + topic_id = (DWORD) id; if (! WinHelp (hdata->window, argv[2], HELP_CONTEXT, topic_id)) { char buf[200]; @@ -346,7 +350,7 @@ hdata_initialize () { struct help_command_data *hdata; - hdata = (struct help_command_data *) Tcl_Alloc (sizeof *hdata); + hdata = (struct help_command_data *) ckalloc (sizeof *hdata); hdata->filename = NULL; hdata->header_filename = NULL; @@ -387,14 +391,16 @@ help_command_deleted (ClientData cd) struct help_command_data *hdata = (struct help_command_data *) cd; if (hdata->filename != NULL) - free (hdata->filename); + ckfree (hdata->filename); if (hdata->header_filename != NULL) - free (hdata->header_filename); + ckfree (hdata->header_filename); + if (hdata->help_dir != NULL) + ckfree (hdata->help_dir); if (hdata->hash_initialized) Tcl_DeleteHashTable (&hdata->topic_hash); if (hdata->memory_block != NULL) - free (hdata->memory_block); - Tcl_Free ((char *) hdata); + ckfree (hdata->memory_block); + ckfree ((char *) hdata); } /* Implement the ide_help initialize command. */ @@ -405,9 +411,12 @@ help_initialize_command (ClientData cd, Tcl_Interp *interp, int argc, { struct help_command_data *hdata = (struct help_command_data *) cd; - hdata->filename = strdup (argv[2]); - hdata->header_filename = strdup (argv[3]); - hdata->help_dir = strdup (argv[4]); + hdata->filename = ckalloc (strlen (argv[2]) + 1); + strcpy (hdata->filename, argv[2]); + hdata->header_filename = ckalloc (strlen (argv[3]) + 1); + strcpy (hdata->header_filename, argv[3]); + hdata->help_dir = ckalloc (strlen (argv[4]) + 1); + strcpy (hdata->help_dir, argv[4]); return TCL_OK; } @@ -427,7 +436,7 @@ help_initialize (Tcl_Interp *interp, struct help_command_data *hdata) FILE *e; char buf[200], *block_start; - block_start = hdata->memory_block = malloc(6000); + block_start = hdata->memory_block = ckalloc(6000); e = fopen (hdata->header_filename, "r"); if (e == NULL) @@ -560,7 +569,7 @@ hdata_initialize () { struct help_command_data *hdata; - hdata = (struct help_command_data *) Tcl_Alloc (sizeof *hdata); + hdata = (struct help_command_data *) ckalloc (sizeof *hdata); hdata->filename = NULL; hdata->help_dir = NULL; diff --git a/libgui/src/tclmain.c b/libgui/src/tclmain.c index 1a962544998..28c2b8eb336 100644 --- a/libgui/src/tclmain.c +++ b/libgui/src/tclmain.c @@ -47,7 +47,7 @@ ide_main (int argc, char *argv[], Tcl_AppInitProc *appInitProc) args = Tcl_Merge (argc - 1, argv + 1); Tcl_SetVar (interp, "argv", args, TCL_GLOBAL_ONLY); - Tcl_Free (args); + ckfree (args); sprintf (buf, "%d", argc-1); Tcl_SetVar (interp, "argc", buf, TCL_GLOBAL_ONLY); diff --git a/libgui/src/tclmsgbox.c b/libgui/src/tclmsgbox.c index 8db081fb2a6..918363be0ae 100644 --- a/libgui/src/tclmsgbox.c +++ b/libgui/src/tclmsgbox.c @@ -155,7 +155,7 @@ msgbox_wndproc (HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) return DefWindowProc (hwnd, message, wparam, lparam); /* Queue up a Tcl event. */ - me = (struct msgbox_event *) Tcl_Alloc (sizeof *me); + me = (struct msgbox_event *) ckalloc (sizeof *me); me->header.proc = msgbox_eventproc; me->md = (struct msgbox_data *) lparam; Tcl_QueueEvent ((Tcl_Event *) me, TCL_QUEUE_TAIL); @@ -202,10 +202,10 @@ msgbox_eventproc (Tcl_Event *event, int flags) /* We are now done with the msgbox_data structure, so we can free the fields and the structure itself. */ - Tcl_Free (me->md->code); - Tcl_Free (me->md->message); - Tcl_Free (me->md->title); - Tcl_Free ((char *) me->md); + ckfree (me->md->code); + ckfree (me->md->message); + ckfree (me->md->title); + ckfree ((char *) me->md); if (ret != TCL_OK) Tcl_BackgroundError (me->md->interp); @@ -401,15 +401,15 @@ msgbox_internal (ClientData clientData, Tcl_Interp *interp, int argc, msgbox_init (); - md = (struct msgbox_data *) Tcl_Alloc (sizeof *md); + md = (struct msgbox_data *) ckalloc (sizeof *md); md->interp = interp; - md->code = Tcl_Alloc (strlen (code) + 1); + md->code = ckalloc (strlen (code) + 1); strcpy (md->code, code); md->hidden_hwnd = hidden_hwnd; md->hwnd = hWnd; - md->message = Tcl_Alloc (strlen (message) + 1); + md->message = ckalloc (strlen (message) + 1); strcpy (md->message, message); - md->title = Tcl_Alloc (strlen (title) + 1); + md->title = ckalloc (strlen (title) + 1); strcpy (md->title, title); md->flags = flags | modal; diff --git a/libgui/src/tclsizebox.c b/libgui/src/tclsizebox.c index 9a8d30559bf..c10e2e3f9c8 100644 --- a/libgui/src/tclsizebox.c +++ b/libgui/src/tclsizebox.c @@ -112,7 +112,7 @@ sizebox_event_proc (ClientData cd, XEvent *event_ptr) su = (struct sizebox_userdata *) GetWindowLong (hwnd, GWL_USERDATA); SetWindowLong (hwnd, GWL_USERDATA, 0); SetWindowLong (hwnd, GWL_WNDPROC, (LONG) su->wndproc); - Tcl_Free ((char *) su); + ckfree ((char *) su); DestroyWindow (hwnd); } } @@ -149,7 +149,7 @@ sizebox_create (Tk_Window tkwin, Window parent, ClientData cd) pt.x, pt.y, Tk_Width (tkwin), Tk_Height (tkwin), parhwnd, NULL, Tk_GetHINSTANCE (), NULL); - su = (struct sizebox_userdata *) Tcl_Alloc (sizeof *su); + su = (struct sizebox_userdata *) ckalloc (sizeof *su); su->tkwin = tkwin; su->wndproc = (WNDPROC) GetWindowLong (hwnd, GWL_WNDPROC); SetWindowLong (hwnd, GWL_USERDATA, (LONG) su); diff --git a/libgui/src/tclwinmode.c b/libgui/src/tclwinmode.c index 958d5c9c607..69c6c8082ef 100644 --- a/libgui/src/tclwinmode.c +++ b/libgui/src/tclwinmode.c @@ -61,11 +61,11 @@ seterrormode_command (ClientData cd, Tcl_Interp *interp, { Tcl_AppendResult (interp, "unrecognized key \"", list[i], "\"", (char *) NULL); - Tcl_Free ((char *) list); + ckfree ((char *) list); return TCL_ERROR; } } - Tcl_Free ((char *) list); + ckfree ((char *) list); val = SetErrorMode (val); diff --git a/libgui/src/tclwinpath.c b/libgui/src/tclwinpath.c index 2f9d5bdb612..ce75ab0dd7f 100644 --- a/libgui/src/tclwinpath.c +++ b/libgui/src/tclwinpath.c @@ -133,7 +133,7 @@ path_posix_to_win32_path_list (ClientData cd, Tcl_Interp *interp, int argc, char *buf; size = cygwin32_posix_to_win32_path_list_buf_size (argv[2]); - buf = Tcl_Alloc (size); + buf = ckalloc (size); cygwin32_posix_to_win32_path_list (argv[2], buf); Tcl_SetResult (interp, buf, TCL_DYNAMIC); return TCL_OK; @@ -149,7 +149,7 @@ path_win32_to_posix_path_list (ClientData cd, Tcl_Interp *interp, int argc, char *buf; size = cygwin32_win32_to_posix_path_list_buf_size (argv[2]); - buf = Tcl_Alloc (size); + buf = ckalloc (size); cygwin32_win32_to_posix_path_list (argv[2], buf); Tcl_SetResult (interp, buf, TCL_DYNAMIC); return TCL_OK; diff --git a/libgui/src/tclwinprint.c b/libgui/src/tclwinprint.c index 221cc14bf77..02843493511 100644 --- a/libgui/src/tclwinprint.c +++ b/libgui/src/tclwinprint.c @@ -126,10 +126,10 @@ winprint_command_deleted (ClientData cd) { /* FIXME: I don't know if we are supposed to free the hDevMode and hDevNames fields. */ - Tcl_Free ((char *) wd->page_setup); + ckfree ((char *) wd->page_setup); } - Tcl_Free ((char *) wd); + ckfree ((char *) wd); } /* Implement ide_winprint page_setup. */ @@ -216,7 +216,7 @@ winprint_page_setup_command (ClientData cd, Tcl_Interp *interp, int argc, } if (wd->page_setup == NULL) - wd->page_setup = (PAGESETUPDLG *) Tcl_Alloc (sizeof (PAGESETUPDLG)); + wd->page_setup = (PAGESETUPDLG *) ckalloc (sizeof (PAGESETUPDLG)); *wd->page_setup = psd; @@ -916,7 +916,7 @@ ide_create_winprint_command (Tcl_Interp *interp) { struct winprint_data *wd; - wd = (struct winprint_data *) Tcl_Alloc (sizeof *wd); + wd = (struct winprint_data *) ckalloc (sizeof *wd); wd->page_setup = NULL; wd->aborted = 0; diff --git a/libgui/src/tkCanvEdge.c b/libgui/src/tkCanvEdge.c index aa66702d768..a7977f0f904 100644 --- a/libgui/src/tkCanvEdge.c +++ b/libgui/src/tkCanvEdge.c @@ -179,8 +179,14 @@ static void TranslateEdge _ANSI_ARGS_((Tk_Canvas canvas, static Tk_CustomOption arrowShapeOption = { ParseArrowShape, PrintArrowShape, (ClientData) NULL}; -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, - Tk_CanvasTagsPrintProc, (ClientData) NULL}; +/* + * The callbacks for tagsOption are initialized in ConfigureEdge() + */ + +static Tk_CustomOption tagsOption = +{ (Tk_OptionParseProc *) NULL, + (Tk_OptionPrintProc *) NULL, + (ClientData) NULL}; static Tk_ConfigSpec configSpecs[] = { {TK_CONFIG_UID, "-arrow", (char *) NULL, (char *) NULL, @@ -531,6 +537,17 @@ ConfigureEdge(interp, canvas, itemPtr, argc, argv, flags) tkwin = Tk_CanvasTkwin(canvas); bgBorder = ((TkCanvas *) canvas)->bgBorder; + /* + * Init callbacks in tagsOption before accessing configSpecs. + * This init can't be done statically when using Windows gcc + * since these symbols are imported from the Tk dll. + */ + + if (tagsOption.parseProc == NULL) { + tagsOption.parseProc = Tk_CanvasTagsParseProc; + tagsOption.printProc = Tk_CanvasTagsPrintProc; + } + if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv, (char *) edgePtr, flags) != TCL_OK) { diff --git a/libgui/src/tkGraphCanvas.c b/libgui/src/tkGraphCanvas.c index c6ed1e71eef..eff3c6d8540 100644 --- a/libgui/src/tkGraphCanvas.c +++ b/libgui/src/tkGraphCanvas.c @@ -259,7 +259,8 @@ GetEdgeNodes(interp,canvasPtr,i,fp,tp) &argc, &argv) != TCL_OK) { return TCL_ERROR; } - *fp = strdup(argv[4]); + *fp = ckalloc (strlen (argv[4]) + 1); + strcpy(*fp, argv[4]); ckfree((char*)argv); /* Read the to node id of this edge. */ Tk_ConfigureInfo(interp, canvasPtr->tkwin, @@ -269,7 +270,8 @@ GetEdgeNodes(interp,canvasPtr,i,fp,tp) &argc, &argv) != TCL_OK) { return TCL_ERROR; } - *tp = strdup(argv[4]); + *tp = ckalloc(strlen (argv[4]) + 1); + strcpy(*tp, argv[4]); ckfree((char*)argv); Tcl_ResetResult(interp); return TCL_OK; diff --git a/libgui/src/tkTable.tcl.h b/libgui/src/tkTable.tcl.h new file mode 100644 index 00000000000..614106e98b5 --- /dev/null +++ b/libgui/src/tkTable.tcl.h @@ -0,0 +1,366 @@ +"proc tkTableClipboardKeysyms {copy cut paste} {\n" +" bind Table <$copy> {tk_tableCopy %W}\n" +" bind Table <$cut> {tk_tableCut %W}\n" +" bind Table <$paste> {tk_tablePaste %W}\n" +"}\n" +"bind Table <3> {\n" +" ## You might want to check for row returned if you want to\n" +" ## restrict the resizing of certain rows\n" +" %W border mark %x %y\n" +"}\n" +"bind Table <B3-Motion> { %W border dragto %x %y }\n" +"bind Table <1> {\n" +" if {[winfo exists %W]} {\n" +" tkTableBeginSelect %W [%W index @%x,%y]\n" +" focus %W\n" +" }\n" +"}\n" +"bind Table <B1-Motion> {\n" +" array set tkPriv {x %x y %y}\n" +" tkTableMotion %W [%W index @%x,%y]\n" +"}\n" +"bind Table <Double-1> {\n" +" # empty\n" +"}\n" +"bind Table <ButtonRelease-1> {\n" +" if {[winfo exists %W]} {\n" +" tkCancelRepeat\n" +" %W activate @%x,%y\n" +" }\n" +"}\n" +"bind Table <Shift-1> {tkTableBeginExtend %W [%W index @%x,%y]}\n" +"bind Table <Control-1> {tkTableBeginToggle %W [%W index @%x,%y]}\n" +"bind Table <B1-Enter> {tkCancelRepeat}\n" +"bind Table <B1-Leave> {\n" +" array set tkPriv {x %x y %y}\n" +" tkTableAutoScan %W\n" +"}\n" +"bind Table <2> {\n" +" %W scan mark %x %y\n" +" array set tkPriv {x %x y %y}\n" +" set tkPriv(mouseMoved) 0\n" +"}\n" +"bind Table <B2-Motion> {\n" +" if {(%x != $tkPriv(x)) || (%y != $tkPriv(y))} { set tkPriv(mouseMoved) 1 }\n" +" if $tkPriv(mouseMoved) { %W scan dragto %x %y }\n" +"}\n" +"bind Table <ButtonRelease-2> {\n" +" if {!$tkPriv(mouseMoved)} { tk_tablePaste %W [%W index @%x,%y] }\n" +"}\n" +"if {[string comp {} [info command event]]} {\n" +" tkTableClipboardKeysyms <Copy> <Cut> <Paste>\n" +"} else {\n" +" tkTableClipboardKeysyms Control-c Control-x Control-v\n" +"}\n" +"bind Table <Any-Tab> {\n" +" # empty to allow Tk focus movement\n" +"}\n" +"bind Table <FocusOut> {\n" +" catch {%W activate active}\n" +"}\n" +"bind Table <Shift-Up> {tkTableExtendSelect %W -1 0}\n" +"bind Table <Shift-Down> {tkTableExtendSelect %W 1 0}\n" +"bind Table <Shift-Left> {tkTableExtendSelect %W 0 -1}\n" +"bind Table <Shift-Right> {tkTableExtendSelect %W 0 1}\n" +"bind Table <Prior> {%W yview scroll -1 pages; %W activate @0,0}\n" +"bind Table <Next> {%W yview scroll 1 pages; %W activate @0,0}\n" +"bind Table <Control-Prior> {%W xview scroll -1 pages}\n" +"bind Table <Control-Next> {%W xview scroll 1 pages}\n" +"bind Table <Home> {%W see origin}\n" +"bind Table <End> {%W see end}\n" +"bind Table <Control-Home> {\n" +" %W selection clear all\n" +" %W activate origin\n" +" %W selection set active\n" +" %W see active\n" +"}\n" +"bind Table <Control-End> {\n" +" %W selection clear all\n" +" %W activate end\n" +" %W selection set active\n" +" %W see active\n" +"}\n" +"bind Table <Shift-Control-Home> {tkTableDataExtend %W origin}\n" +"bind Table <Shift-Control-End> {tkTableDataExtend %W end}\n" +"bind Table <Select> {tkTableBeginSelect %W [%W index active]}\n" +"bind Table <Shift-Select> {tkTableBeginExtend %W [%W index active]}\n" +"bind Table <Control-slash> {tkTableSelectAll %W}\n" +"bind Table <Control-backslash> {\n" +" if {[string match browse [%W cget -selectmode]]} {%W selection clear all}\n" +"}\n" +"bind Table <Up> {tkTableMoveCell %W -1 0}\n" +"bind Table <Down> {tkTableMoveCell %W 1 0}\n" +"bind Table <Left> {tkTableMoveCell %W 0 -1}\n" +"bind Table <Right> {tkTableMoveCell %W 0 1}\n" +"bind Table <Any-KeyPress> {\n" +" if {[string compare {} %A]} { %W insert active insert %A }\n" +"}\n" +"bind Table <BackSpace> {\n" +" set tkPriv(junk) [%W icursor]\n" +" if {[string compare {} $tkPriv(junk)] && $tkPriv(junk)} {\n" +" %W delete active [expr {$tkPriv(junk)-1}]\n" +" }\n" +"}\n" +"bind Table <Delete> {%W delete active insert}\n" +"bind Table <Escape> {%W reread}\n" +"bind Table <Return> {\n" +" %W insert active insert \"\n\"\n" +"}\n" +"bind Table <Control-Left> {%W icursor [expr {[%W icursor]-1}]}\n" +"bind Table <Control-Right> {%W icursor [expr {[%W icursor]+1}]}\n" +"bind Table <Control-e> {%W icursor end}\n" +"bind Table <Control-a> {%W icursor 0}\n" +"bind Table <Control-k> {%W delete active insert end}\n" +"bind Table <Control-equal> {tkTableChangeWidth %W active 1}\n" +"bind Table <Control-minus> {tkTableChangeWidth %W active -1}\n" +"proc tkTableBeginSelect {w el} {\n" +" global tkPriv\n" +" if {[scan $el %d,%d r c] != 2} return\n" +" switch [$w cget -selectmode] {\n" +" multiple {\n" +" if {[$w tag includes title $el]} {\n" +" ## in the title area\n" +" if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {\n" +" ## We're in a column header\n" +" if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {\n" +" ## We're in the topleft title area\n" +" set inc topleft\n" +" set el2 end\n" +" } else {\n" +" set inc [$w index topleft row],$c\n" +" set el2 [$w index end row],$c\n" +" }\n" +" } else {\n" +" ## We're in a row header\n" +" set inc $r,[$w index topleft col]\n" +" set el2 $r,[$w index end col]\n" +" }\n" +" } else {\n" +" set inc $el\n" +" set el2 $el\n" +" }\n" +" if [$w selection includes $inc] {\n" +" $w selection clear $el $el2\n" +" } else {\n" +" $w selection set $el $el2\n" +" }\n" +" }\n" +" extended {\n" +" $w selection clear all\n" +" if {[$w tag includes title $el]} {\n" +" if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {\n" +" ## We're in a column header\n" +" if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {\n" +" $w selection set origin end\n" +" } else {\n" +" $w selection set $el [$w index end row],$c\n" +" }\n" +" } else {\n" +" ## We're in a row header\n" +" $w selection set $el $r,[$w index end col]\n" +" }\n" +" } else {\n" +" $w selection set $el\n" +" }\n" +" $w selection anchor $el\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" default {\n" +" if {![$w tag includes title $el]} {\n" +" $w selection clear all\n" +" $w selection set $el\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" $w selection anchor $el\n" +" }\n" +" }\n" +"}\n" +"proc tkTableMotion {w el} {\n" +" global tkPriv\n" +" if {![info exists tkPriv(tablePrev)]} {\n" +" set tkPriv(tablePrev) $el\n" +" return\n" +" }\n" +" if {[string match $tkPriv(tablePrev) $el]} return\n" +" switch [$w cget -selectmode] {\n" +" browse {\n" +" $w selection clear all\n" +" $w selection set $el\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" extended {\n" +" scan $tkPriv(tablePrev) %d,%d r c\n" +" scan $el %d,%d elr elc\n" +" if {[$w tag includes title $el]} {\n" +" if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {\n" +" ## We're in a column header\n" +" if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {\n" +" ## We're in the topleft title area\n" +" $w selection clear anchor end\n" +" } else {\n" +" $w selection clear anchor [$w index end row],$c\n" +" }\n" +" $w selection set anchor [$w index end row],$elc\n" +" } else {\n" +" ## We're in a row header\n" +" $w selection clear anchor $r,[$w index end col]\n" +" $w selection set anchor $elr,[$w index end col]\n" +" }\n" +" } else {\n" +" $w selection clear anchor $tkPriv(tablePrev)\n" +" $w selection set anchor $el\n" +" }\n" +" set tkPriv(tablePrev) $el\n" +" }\n" +" }\n" +"}\n" +"proc tkTableBeginExtend {w el} {\n" +" if {[string match extended [$w cget -selectmode]] &&\n" +" [$w selection includes anchor]} {\n" +" tkTableMotion $w $el\n" +" }\n" +"}\n" +"proc tkTableBeginToggle {w el} {\n" +" global tkPriv\n" +" if {[string match extended [$w cget -selectmode]]} {\n" +" set tkPriv(tablePrev) $el\n" +" $w selection anchor $el\n" +" if [$w selection includes $el] {\n" +" $w selection clear $el\n" +" } else {\n" +" $w selection set $el\n" +" }\n" +" }\n" +"}\n" +"proc tkTableAutoScan {w} {\n" +" global tkPriv\n" +" if {![winfo exists $w]} return\n" +" set x $tkPriv(x)\n" +" set y $tkPriv(y)\n" +" if {$y >= [winfo height $w]} {\n" +" $w yview scroll 1 units\n" +" } elseif {$y < 0} {\n" +" $w yview scroll -1 units\n" +" } elseif {$x >= [winfo width $w]} {\n" +" $w xview scroll 1 units\n" +" } elseif {$x < 0} {\n" +" $w xview scroll -1 units\n" +" } else {\n" +" return\n" +" }\n" +" tkTableMotion $w [$w index @$x,$y]\n" +" set tkPriv(afterId) [after 50 tkTableAutoScan $w]\n" +"}\n" +"proc tkTableMoveCell {w x y} {\n" +" global tkPriv\n" +" if {[catch {$w index active row} r]} return\n" +" set c [$w index active col]\n" +" $w activate [incr r $x],[incr c $y]\n" +" $w see active\n" +" switch [$w cget -selectmode] {\n" +" browse {\n" +" $w selection clear all\n" +" $w selection set active\n" +" }\n" +" extended {\n" +" $w selection clear all\n" +" $w selection set active\n" +" $w selection anchor active\n" +" set tkPriv(tablePrev) [$w index active]\n" +" }\n" +" }\n" +"}\n" +"proc tkTableExtendSelect {w x y} {\n" +" if {[string compare extended [$w cget -selectmode]] ||\n" +" [catch {$w index active row} r]} return\n" +" set c [$w index active col]\n" +" $w activate [incr r $x],[incr c $y]\n" +" $w see active\n" +" tkTableMotion $w [$w index active]\n" +"}\n" +"proc tkTableDataExtend {w el} {\n" +" set mode [$w cget -selectmode]\n" +" if {[string match extended $mode]} {\n" +" $w activate $el\n" +" $w see $el\n" +" if [$w selection includes anchor] {tkTableMotion $w $el}\n" +" } elseif {[string match multiple $mode]} {\n" +" $w activate $el\n" +" $w see $el\n" +" }\n" +"}\n" +"proc tkTableSelectAll {w} {\n" +" if {[regexp {^(single|browse)$} [$w cget -selectmode]]} {\n" +" $w selection clear all\n" +" $w selection set active\n" +" tkTableHandleType $w [$w index active]\n" +" } else {\n" +" $w selection set origin end\n" +" }\n" +"}\n" +"proc tkTableChangeWidth {w i a} {\n" +" set tmp [$w index $i col]\n" +" if {[set width [$w width $tmp]] >= 0} {\n" +" $w width $tmp [incr width $a]\n" +" } else {\n" +" $w width $tmp [incr width -$a]\n" +" }\n" +"}\n" +"proc tk_tableCopy w {\n" +" if {[selection own -displayof $w] == \"$w\"} {\n" +" clipboard clear -displayof $w\n" +" catch {clipboard append -displayof $w [selection get -displayof $w]}\n" +" }\n" +"}\n" +"proc tk_tableCut w {\n" +" if {[selection own -displayof $w] == \"$w\"} {\n" +" clipboard clear -displayof $w\n" +" catch {\n" +" clipboard append -displayof $w [selection get -displayof $w]\n" +" $w cursel set {}\n" +" $w selection clear all\n" +" }\n" +" }\n" +"}\n" +"proc tk_tablePaste {w {cell {}}} {\n" +" if {[string compare {} $cell]} {\n" +" if {[catch {selection get -displayof $w} data]} return\n" +" } else {\n" +" if {[catch {selection get -displayof $w -selection CLIPBOARD} data]} {\n" +" return\n" +" }\n" +" set cell active\n" +" }\n" +" tk_tablePasteHandler $w [$w index $cell] $data\n" +" if {[$w cget -state] == \"normal\"} {focus $w}\n" +"}\n" +"proc tk_tablePasteHandler {w cell data} {\n" +" set rows [expr {[$w cget -rows]-[$w cget -roworigin]}]\n" +" set cols [expr {[$w cget -cols]-[$w cget -colorigin]}]\n" +" set r [$w index $cell row]\n" +" set c [$w index $cell col]\n" +" set rsep [$w cget -rowseparator]\n" +" set csep [$w cget -colseparator]\n" +" ## Assume separate rows are split by row separator if specified\n" +" ## If you were to want multi-character row separators, you would need:\n" +" # regsub -all $rsep $data <newline> data\n" +" # set data [join $data <newline>]\n" +" if {[string comp {} $rsep]} { set data [split $data $rsep] }\n" +" set row $r\n" +" foreach line $data {\n" +" if {$row > $rows} break\n" +" set col $c\n" +" ## Assume separate cols are split by col separator if specified\n" +" ## Unless a -separator was specified\n" +" if {[string comp {} $csep]} { set line [split $line $csep] }\n" +" ## If you were to want multi-character col separators, you would need:\n" +" # regsub -all $csep $line <newline> line\n" +" # set line [join $line <newline>]\n" +" foreach item $line {\n" +" if {$col > $cols} break\n" +" $w set $row,$col $item\n" +" incr col\n" +" }\n" +" incr row\n" +" }\n" +"}\n" diff --git a/libgui/src/tkTableCellSort.c b/libgui/src/tkTableCellSort.c new file mode 100644 index 00000000000..7afc4d754a1 --- /dev/null +++ b/libgui/src/tkTableCellSort.c @@ -0,0 +1,400 @@ +/* + * tkTableCell.c -- + * + * This module implements cell sort functions for table + * widgets. The MergeSort algorithm and other aux sorting + * functions were taken from tclCmdIL.c lsort command: + + * tclCmdIL.c -- + * + * This file contains the top-level command routines for most of + * the Tcl built-in commands whose names begin with the letters + * I through L. It contains only commands in the generic core + * (i.e. those that don't depend much upon UNIX facilities). + * + * Copyright (c) 1987-1993 The Regents of the University of California. + * Copyright (c) 1993-1997 Lucent Technologies. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-1999 by Scriptics Corporation. + + * + * Copyright (c) 1998-1999 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include "tkTable.h" + +#ifndef UCHAR +#define UCHAR(c) ((unsigned char) (c)) +#endif + +/* + * During execution of the "lsort" command, structures of the following + * type are used to arrange the objects being sorted into a collection + * of linked lists. + */ + +typedef struct SortElement { + Tcl_Obj *objPtr; /* Object being sorted. */ + struct SortElement *nextPtr; /* Next element in the list, or + * NULL for end of list. */ +} SortElement; + +static int TableSortCompareProc _ANSI_ARGS_((CONST VOID *first, + CONST VOID *second)); +static SortElement * MergeSort _ANSI_ARGS_((SortElement *headPt)); +static SortElement * MergeLists _ANSI_ARGS_((SortElement *leftPtr, + SortElement *rightPtr)); +static int DictionaryCompare _ANSI_ARGS_((char *left, + char *right)); + +/* + *---------------------------------------------------------------------- + * + * TableSortCompareProc -- + * This procedure is invoked by qsort to determine the proper + * ordering between two elements. + * + * Results: + * < 0 means first is "smaller" than "second", > 0 means "first" + * is larger than "second", and 0 means they should be treated + * as equal. + * + * Side effects: + * None, unless a user-defined comparison command does something + * weird. + * + *---------------------------------------------------------------------- + */ +static int +TableSortCompareProc(first, second) + CONST VOID *first, *second; /* Elements to be compared. */ +{ + char *str1 = *((char **) first); + char *str2 = *((char **) second); + + return DictionaryCompare(str1, str2); +} + +/* + *---------------------------------------------------------------------- + * + * TableCellSort -- + * Sort a list of table cell elements (of form row,col) + * + * Results: + * Returns the sorted list of elements. Because Tcl_Merge allocs + * the space for result, it must later be Tcl_Free'd by caller. + * + * Side effects: + * Behaviour undefined for ill-formed input list of elements. + * + *---------------------------------------------------------------------- + */ +char * +TableCellSort(Table *tablePtr, char *str) +{ + int listArgc; + char **listArgv; + char *result; + + if (Tcl_SplitList(tablePtr->interp, str, &listArgc, &listArgv) != TCL_OK) { + return str; + } + /* Thread safety: qsort is reportedly not thread-safe... */ + qsort((VOID *) listArgv, (size_t) listArgc, sizeof (char *), + TableSortCompareProc); + result = Tcl_Merge(listArgc, listArgv); + ckfree((char *) listArgv); + return result; +} + +/* + *---------------------------------------------------------------------- + * + * DictionaryCompare - Not the Unicode version + * + * This function compares two strings as if they were being used in + * an index or card catalog. The case of alphabetic characters is + * ignored, except to break ties. Thus "B" comes before "b" but + * after "a". Also, integers embedded in the strings compare in + * numerical order. In other words, "x10y" comes after "x9y", not + * before it as it would when using strcmp(). + * + * Results: + * A negative result means that the first element comes before the + * second, and a positive result means that the second element + * should come first. A result of zero means the two elements + * are equal and it doesn't matter which comes first. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +DictionaryCompare(left, right) + char *left, *right; /* The strings to compare */ +{ + int diff, zeros; + int secondaryDiff = 0; + + while (1) { + if (isdigit(UCHAR(*right)) && isdigit(UCHAR(*left))) { + /* + * There are decimal numbers embedded in the two + * strings. Compare them as numbers, rather than + * strings. If one number has more leading zeros than + * the other, the number with more leading zeros sorts + * later, but only as a secondary choice. + */ + + zeros = 0; + while ((*right == '0') && (isdigit(UCHAR(right[1])))) { + right++; + zeros--; + } + while ((*left == '0') && (isdigit(UCHAR(left[1])))) { + left++; + zeros++; + } + if (secondaryDiff == 0) { + secondaryDiff = zeros; + } + + /* + * The code below compares the numbers in the two + * strings without ever converting them to integers. It + * does this by first comparing the lengths of the + * numbers and then comparing the digit values. + */ + + diff = 0; + while (1) { + if (diff == 0) { + diff = UCHAR(*left) - UCHAR(*right); + } + right++; + left++; + if (!isdigit(UCHAR(*right))) { + if (isdigit(UCHAR(*left))) { + return 1; + } else { + /* + * The two numbers have the same length. See + * if their values are different. + */ + + if (diff != 0) { + return diff; + } + break; + } + } else if (!isdigit(UCHAR(*left))) { + return -1; + } + } + continue; + } + diff = UCHAR(*left) - UCHAR(*right); + if (diff) { + if (isupper(UCHAR(*left)) && islower(UCHAR(*right))) { + diff = UCHAR(tolower(*left)) - UCHAR(*right); + if (diff) { + return diff; + } else if (secondaryDiff == 0) { + secondaryDiff = -1; + } + } else if (isupper(UCHAR(*right)) && islower(UCHAR(*left))) { + diff = UCHAR(*left) - UCHAR(tolower(UCHAR(*right))); + if (diff) { + return diff; + } else if (secondaryDiff == 0) { + secondaryDiff = 1; + } + } else { + return diff; + } + } + if (*left == 0) { + break; + } + left++; + right++; + } + if (diff == 0) { + diff = secondaryDiff; + } + return diff; +} + +/* + *---------------------------------------------------------------------- + * + * MergeLists - + * + * This procedure combines two sorted lists of SortElement structures + * into a single sorted list. + * + * Results: + * The unified list of SortElement structures. + * + * Side effects: + * None, unless a user-defined comparison command does something + * weird. + * + *---------------------------------------------------------------------- + */ + +static SortElement * +MergeLists(leftPtr, rightPtr) + SortElement *leftPtr; /* First list to be merged; may be + * NULL. */ + SortElement *rightPtr; /* Second list to be merged; may be + * NULL. */ +{ + SortElement *headPtr; + SortElement *tailPtr; + + if (leftPtr == NULL) { + return rightPtr; + } + if (rightPtr == NULL) { + return leftPtr; + } + if (DictionaryCompare(Tcl_GetString(leftPtr->objPtr), + Tcl_GetString(rightPtr->objPtr)) > 0) { + tailPtr = rightPtr; + rightPtr = rightPtr->nextPtr; + } else { + tailPtr = leftPtr; + leftPtr = leftPtr->nextPtr; + } + headPtr = tailPtr; + while ((leftPtr != NULL) && (rightPtr != NULL)) { + if (DictionaryCompare(Tcl_GetString(leftPtr->objPtr), + Tcl_GetString(rightPtr->objPtr)) > 0) { + tailPtr->nextPtr = rightPtr; + tailPtr = rightPtr; + rightPtr = rightPtr->nextPtr; + } else { + tailPtr->nextPtr = leftPtr; + tailPtr = leftPtr; + leftPtr = leftPtr->nextPtr; + } + } + if (leftPtr != NULL) { + tailPtr->nextPtr = leftPtr; + } else { + tailPtr->nextPtr = rightPtr; + } + return headPtr; +} + +/* + *---------------------------------------------------------------------- + * + * MergeSort - + * + * This procedure sorts a linked list of SortElement structures + * use the merge-sort algorithm. + * + * Results: + * A pointer to the head of the list after sorting is returned. + * + * Side effects: + * None, unless a user-defined comparison command does something + * weird. + * + *---------------------------------------------------------------------- + */ + +static SortElement * +MergeSort(headPtr) + SortElement *headPtr; /* First element on the list */ +{ + /* + * The subList array below holds pointers to temporary lists built + * during the merge sort. Element i of the array holds a list of + * length 2**i. + */ + +# define NUM_LISTS 30 + SortElement *subList[NUM_LISTS]; + SortElement *elementPtr; + int i; + + for(i = 0; i < NUM_LISTS; i++){ + subList[i] = NULL; + } + while (headPtr != NULL) { + elementPtr = headPtr; + headPtr = headPtr->nextPtr; + elementPtr->nextPtr = 0; + for (i = 0; (i < NUM_LISTS) && (subList[i] != NULL); i++){ + elementPtr = MergeLists(subList[i], elementPtr); + subList[i] = NULL; + } + if (i >= NUM_LISTS) { + i = NUM_LISTS-1; + } + subList[i] = elementPtr; + } + elementPtr = NULL; + for (i = 0; i < NUM_LISTS; i++){ + elementPtr = MergeLists(subList[i], elementPtr); + } + return elementPtr; +} + +#ifndef NO_SORT_CELLS +/* + *---------------------------------------------------------------------- + * + * TableCellSortObj -- + * Sorts a list of table cell elements (of form row,col) in place + * + * Results: + * Sorts list of elements in place. + * + * Side effects: + * Behaviour undefined for ill-formed input list of elements. + * + *---------------------------------------------------------------------- + */ +Tcl_Obj * +TableCellSortObj(Tcl_Interp *interp, Tcl_Obj *listObjPtr) +{ + int length, i; + Tcl_Obj *sortedObjPtr, **listObjPtrs; + SortElement *elementArray; + SortElement *elementPtr; + + if (Tcl_ListObjGetElements(interp, listObjPtr, + &length, &listObjPtrs) != TCL_OK) { + return NULL; + } + if (length <= 0) { + return listObjPtr; + } + + elementArray = (SortElement *) ckalloc(length * sizeof(SortElement)); + for (i=0; i < length; i++){ + elementArray[i].objPtr = listObjPtrs[i]; + elementArray[i].nextPtr = &elementArray[i+1]; + } + elementArray[length-1].nextPtr = NULL; + elementPtr = MergeSort(elementArray); + sortedObjPtr = Tcl_NewObj(); + for (; elementPtr != NULL; elementPtr = elementPtr->nextPtr){ + Tcl_ListObjAppendElement(NULL, sortedObjPtr, elementPtr->objPtr); + } + ckfree((char*) elementArray); + + return sortedObjPtr; +} +#endif diff --git a/libgui/src/tkTableCmds.c b/libgui/src/tkTableCmds.c new file mode 100644 index 00000000000..4fc7d3b374a --- /dev/null +++ b/libgui/src/tkTableCmds.c @@ -0,0 +1,1293 @@ +/* + * tkTableCmds.c -- + * + * This module implements general commands of a table widget, + * based on the major/minor command structure. + * + * Copyright (c) 1998-2000 Jeffrey Hobbs + * + * See the file "license.txt" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include "tkTable.h" + +/* + *-------------------------------------------------------------- + * + * Table_ActivateCmd -- + * This procedure is invoked to process the activate method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_ActivateCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int result = TCL_OK; + int row, col; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "index"); + return TCL_ERROR; + } else if (TableGetIndexObj(tablePtr, objv[2], &row, &col) != TCL_OK) { + return TCL_ERROR; + } else { + int x, y, w, dummy; + char buf1[INDEX_BUFSIZE], buf2[INDEX_BUFSIZE]; + + /* convert to valid active index in real coords */ + row -= tablePtr->rowOffset; + col -= tablePtr->colOffset; + /* we do this regardless, to avoid cell commit problems */ + if ((tablePtr->flags & HAS_ACTIVE) && + (tablePtr->flags & TEXT_CHANGED)) { + tablePtr->flags &= ~TEXT_CHANGED; + TableSetCellValue(tablePtr, + tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + tablePtr->activeBuf); + } + if (row != tablePtr->activeRow || col != tablePtr->activeCol) { + if (tablePtr->flags & HAS_ACTIVE) { + TableMakeArrayIndex(tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + buf1); + } else { + buf1[0] = '\0'; + } + tablePtr->flags |= HAS_ACTIVE; + tablePtr->flags &= ~ACTIVE_DISABLED; + tablePtr->activeRow = row; + tablePtr->activeCol = col; + if (tablePtr->activeTagPtr != NULL) { + ckfree((char *) (tablePtr->activeTagPtr)); + tablePtr->activeTagPtr = NULL; + } + TableAdjustActive(tablePtr); + TableConfigCursor(tablePtr); + if (!(tablePtr->flags & BROWSE_CMD) && + tablePtr->browseCmd != NULL) { + Tcl_DString script; + tablePtr->flags |= BROWSE_CMD; + row = tablePtr->activeRow+tablePtr->rowOffset; + col = tablePtr->activeCol+tablePtr->colOffset; + TableMakeArrayIndex(row, col, buf2); + Tcl_DStringInit(&script); + ExpandPercents(tablePtr, tablePtr->browseCmd, row, col, + buf1, buf2, tablePtr->icursor, &script, 0); + result = Tcl_GlobalEval(interp, Tcl_DStringValue(&script)); + if (result == TCL_OK || result == TCL_RETURN) { + Tcl_ResetResult(interp); + } + Tcl_DStringFree(&script); + tablePtr->flags &= ~BROWSE_CMD; + } + } else { + char *p = Tcl_GetString(objv[2]); + + if ((tablePtr->activeTagPtr != NULL) && *p == '@' && + !(tablePtr->flags & ACTIVE_DISABLED) && + TableCellVCoords(tablePtr, row, col, &x, &y, &w, &dummy, 0)) { + /* we are clicking into the same cell + * If it was activated with @x,y indexing, + * find the closest char */ + Tk_TextLayout textLayout; + TableTag *tagPtr = tablePtr->activeTagPtr; + + /* no error checking because GetIndex did it for us */ + p++; + x = strtol(p, &p, 0) - x - tablePtr->activeX; + y = strtol(++p, &p, 0) - y - tablePtr->activeY; + + textLayout = Tk_ComputeTextLayout(tagPtr->tkfont, + tablePtr->activeBuf, -1, + (tagPtr->wrap) ? w : 0, + tagPtr->justify, 0, &dummy, &dummy); + + tablePtr->icursor = Tk_PointToChar(textLayout, x, y); + Tk_FreeTextLayout(textLayout); + TableRefresh(tablePtr, row, col, CELL|INV_FORCE); + } + } + tablePtr->flags |= HAS_ACTIVE; + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * Table_AdjustCmd -- + * This procedure is invoked to process the width/height method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_AdjustCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + Tcl_HashEntry *entryPtr; + Tcl_HashSearch search; + Tcl_HashTable *hashTablePtr; + int i, widthType, dummy, value, posn, offset; + char buf1[INDEX_BUFSIZE]; + + widthType = (*(Tcl_GetString(objv[1])) == 'w'); + /* changes the width/height of certain selected columns */ + if (objc != 3 && (objc & 1)) { + Tcl_WrongNumArgs(interp, 2, objv, widthType ? + "?col? ?width col width ...?" : + "?row? ?height row height ...?"); + return TCL_ERROR; + } + if (widthType) { + hashTablePtr = tablePtr->colWidths; + offset = tablePtr->colOffset; + } else { + hashTablePtr = tablePtr->rowHeights; + offset = tablePtr->rowOffset; + } + + if (objc == 2) { + /* print out all the preset column widths or row heights */ + entryPtr = Tcl_FirstHashEntry(hashTablePtr, &search); + while (entryPtr != NULL) { + posn = ((int) Tcl_GetHashKey(hashTablePtr, entryPtr)) + offset; + value = (int) Tcl_GetHashValue(entryPtr); + sprintf(buf1, "%d %d", posn, value); + /* OBJECTIFY */ + Tcl_AppendElement(interp, buf1); + entryPtr = Tcl_NextHashEntry(&search); + } + } else if (objc == 3) { + /* get the width/height of a particular row/col */ + if (Tcl_GetIntFromObj(interp, objv[2], &posn) != TCL_OK) { + return TCL_ERROR; + } + /* no range check is done, why bother? */ + posn -= offset; + entryPtr = Tcl_FindHashEntry(hashTablePtr, (char *) posn); + if (entryPtr != NULL) { + Tcl_SetIntObj(Tcl_GetObjResult(interp), + (int) Tcl_GetHashValue(entryPtr)); + } else { + Tcl_SetIntObj(Tcl_GetObjResult(interp), widthType ? + tablePtr->defColWidth : tablePtr->defRowHeight); + } + } else { + for (i=2; i<objc; i++) { + /* set new width|height here */ + value = -999999; + if (Tcl_GetIntFromObj(interp, objv[i++], &posn) != TCL_OK || + (strcmp(Tcl_GetString(objv[i]), "default") && + Tcl_GetIntFromObj(interp, objv[i], &value) != TCL_OK)) { + return TCL_ERROR; + } + posn -= offset; + if (value == -999999) { + /* reset that field */ + entryPtr = Tcl_FindHashEntry(hashTablePtr, (char *) posn); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + } else { + entryPtr = Tcl_CreateHashEntry(hashTablePtr, + (char *) posn, &dummy); + Tcl_SetHashValue(entryPtr, (ClientData) value); + } + } + TableAdjustParams(tablePtr); + /* rerequest geometry */ + TableGeometryRequest(tablePtr); + /* + * Invalidate the whole window as TableAdjustParams + * will only check to see if the top left cell has moved + * FIX: should just move from lowest order visible cell + * to edge of window + */ + TableInvalidateAll(tablePtr, 0); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_BboxCmd -- + * This procedure is invoked to process the bbox method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_BboxCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int x, y, w, h, row, col, key; + Tcl_Obj *resultPtr; + + /* Returns bounding box of cell(s) */ + if (objc < 3 || objc > 4) { + Tcl_WrongNumArgs(interp, 2, objv, "first ?last?"); + return TCL_ERROR; + } else if (TableGetIndexObj(tablePtr, objv[2], &row, &col) == TCL_ERROR || + (objc == 4 && + TableGetIndexObj(tablePtr, objv[3], &x, &y) == TCL_ERROR)) { + return TCL_ERROR; + } + + resultPtr = Tcl_GetObjResult(interp); + if (objc == 3) { + row -= tablePtr->rowOffset; col -= tablePtr->colOffset; + if (TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0)) { + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(x)); + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(y)); + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(w)); + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(h)); + } + return TCL_OK; + } else { + int r1, c1, r2, c2, minX = 99999, minY = 99999, maxX = 0, maxY = 0; + + row -= tablePtr->rowOffset; col -= tablePtr->colOffset; + x -= tablePtr->rowOffset; y -= tablePtr->colOffset; + r1 = MIN(row,x); r2 = MAX(row,x); + c1 = MIN(col,y); c2 = MAX(col,y); + key = 0; + for (row = r1; row <= r2; row++) { + for (col = c1; col <= c2; col++) { + if (TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0)) { + /* Get max bounding box */ + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x+w > maxX) maxX = x+w; + if (y+h > maxY) maxY = y+h; + key++; + } + } + } + if (key) { + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(minX)); + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewIntObj(minY)); + Tcl_ListObjAppendElement(NULL, resultPtr, + Tcl_NewIntObj(maxX-minX)); + Tcl_ListObjAppendElement(NULL, resultPtr, + Tcl_NewIntObj(maxY-minY)); + } + } + return TCL_OK; +} + +static char *bdCmdNames[] = { + "mark", "dragto", (char *)NULL +}; +enum bdCmd { + BD_MARK, BD_DRAGTO +}; + +/* + *-------------------------------------------------------------- + * + * Table_BorderCmd -- + * This procedure is invoked to process the bbox method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_BorderCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + Tcl_HashEntry *entryPtr; + int x, y, w, h, row, col, key, dummy, value, cmdIndex; + char *rc = NULL; + Tcl_Obj *objPtr, *resultPtr; + + if (objc < 5 || objc > 6) { + Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y ?row|col?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], bdCmdNames, + "option", 0, &cmdIndex) != TCL_OK || + Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK || + Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) { + return TCL_ERROR; + } + if (objc == 6) { + rc = Tcl_GetStringFromObj(objv[5], &w); + if ((w < 1) || (strncmp(rc, "row", w) && strncmp(rc, "col", w))) { + Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y ?row|col?"); + return TCL_ERROR; + } + } + + resultPtr = Tcl_GetObjResult(interp); + switch ((enum bdCmd) cmdIndex) { + case BD_MARK: + /* Use x && y to determine if we are over a border */ + value = TableAtBorder(tablePtr, x, y, &row, &col); + /* Cache the row && col for use in DRAGTO */ + tablePtr->scanMarkRow = row; + tablePtr->scanMarkCol = col; + if (!value) { + return TCL_OK; + } + TableCellCoords(tablePtr, row, col, &x, &y, &dummy, &dummy); + tablePtr->scanMarkX = x; + tablePtr->scanMarkY = y; + if (objc == 5 || *rc == 'r') { + if (row < 0) { + objPtr = Tcl_NewStringObj("", 0); + } else { + objPtr = Tcl_NewIntObj(row+tablePtr->rowOffset); + } + Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); + } + if (objc == 5 || *rc == 'c') { + if (col < 0) { + objPtr = Tcl_NewStringObj("", 0); + } else { + objPtr = Tcl_NewIntObj(col+tablePtr->colOffset); + } + Tcl_ListObjAppendElement(NULL, resultPtr, objPtr); + } + return TCL_OK; /* BORDER MARK */ + + case BD_DRAGTO: + /* check to see if we want to resize any borders */ + if (tablePtr->resize == SEL_NONE) { return TCL_OK; } + row = tablePtr->scanMarkRow; + col = tablePtr->scanMarkCol; + TableCellCoords(tablePtr, row, col, &w, &h, &dummy, &dummy); + key = 0; + if (row >= 0 && (tablePtr->resize & SEL_ROW)) { + /* row border was active, move it */ + value = y-h; + if (value < -1) value = -1; + if (value != tablePtr->scanMarkY) { + entryPtr = Tcl_CreateHashEntry(tablePtr->rowHeights, + (char *) row, &dummy); + /* -value means rowHeight will be interp'd as pixels, not + lines */ + Tcl_SetHashValue(entryPtr, (ClientData) MIN(0,-value)); + tablePtr->scanMarkY = value; + key++; + } + } + if (col >= 0 && (tablePtr->resize & SEL_COL)) { + /* col border was active, move it */ + value = x-w; + if (value < -1) value = -1; + if (value != tablePtr->scanMarkX) { + entryPtr = Tcl_CreateHashEntry(tablePtr->colWidths, + (char *) col, &dummy); + /* -value means colWidth will be interp'd as pixels, not + chars */ + Tcl_SetHashValue(entryPtr, (ClientData) MIN(0,-value)); + tablePtr->scanMarkX = value; + key++; + } + } + /* Only if something changed do we want to update */ + if (key) { + TableAdjustParams(tablePtr); + /* Only rerequest geometry if the basis is the #rows &| #cols */ + if (tablePtr->maxReqCols || tablePtr->maxReqRows) + TableGeometryRequest(tablePtr); + TableInvalidateAll(tablePtr, 0); + } + return TCL_OK; /* BORDER DRAGTO */ + } + return TCL_OK; +} + +/* clear subcommands */ +static char *clearNames[] = { + "all", "cache", "sizes", "tags", (char *)NULL +}; +enum clearCommand { + CLEAR_ALL, CLEAR_CACHE, CLEAR_SIZES, CLEAR_TAGS +}; + +/* + *-------------------------------------------------------------- + * + * Table_ClearCmd -- + * This procedure is invoked to process the clear method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * Cached info can be lost. Returns valid Tcl result. + * + * Side effects: + * Can cause redraw. + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_ClearCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int cmdIndex, redraw = 0; + + if (objc < 3 || objc > 5) { + Tcl_WrongNumArgs(interp, 2, objv, "option ?first? ?last?"); + return TCL_ERROR; + } + + if (Tcl_GetIndexFromObj(interp, objv[2], clearNames, + "clear option", 0, &cmdIndex) != TCL_OK) { + return TCL_ERROR; + } + + if (objc == 3) { + if (cmdIndex == CLEAR_TAGS || cmdIndex == CLEAR_ALL) { + Tcl_DeleteHashTable(tablePtr->rowStyles); + Tcl_DeleteHashTable(tablePtr->colStyles); + Tcl_DeleteHashTable(tablePtr->cellStyles); + Tcl_DeleteHashTable(tablePtr->flashCells); + Tcl_DeleteHashTable(tablePtr->selCells); + + /* style hash tables */ + Tcl_InitHashTable(tablePtr->rowStyles, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(tablePtr->colStyles, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(tablePtr->cellStyles, TCL_STRING_KEYS); + + /* special style hash tables */ + Tcl_InitHashTable(tablePtr->flashCells, TCL_STRING_KEYS); + Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS); + } + + if (cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) { + Tcl_DeleteHashTable(tablePtr->colWidths); + Tcl_DeleteHashTable(tablePtr->rowHeights); + + /* style hash tables */ + Tcl_InitHashTable(tablePtr->colWidths, TCL_ONE_WORD_KEYS); + Tcl_InitHashTable(tablePtr->rowHeights, TCL_ONE_WORD_KEYS); + } + + if (cmdIndex == CLEAR_CACHE || cmdIndex == CLEAR_ALL) { + Tcl_DeleteHashTable(tablePtr->cache); + Tcl_InitHashTable(tablePtr->cache, TCL_STRING_KEYS); + /* If we were caching and we have no other data source, + * invalidate all the cells */ + if (tablePtr->dataSource == DATA_CACHE) { + TableGetActiveBuf(tablePtr); + } + } + redraw = 1; + } else { + int row, col, r1, r2, c1, c2; + Tcl_HashEntry *entryPtr; + char buf[INDEX_BUFSIZE]; + + if (TableGetIndexObj(tablePtr, objv[3], &row, &col) != TCL_OK || + ((objc == 5) && + TableGetIndexObj(tablePtr, objv[4], &r2, &c2) != TCL_OK)) { + return TCL_ERROR; + } + if (objc == 4) { + r1 = r2 = row; + c1 = c2 = col; + } else { + r1 = MIN(row,r2); r2 = MAX(row,r2); + c1 = MIN(col,c2); c2 = MAX(col,c2); + } + for (row = r1; row <= r2; row++) { + /* Note that *Styles entries are user based (no offset) + * while size entries are 0-based (real) */ + if ((cmdIndex == CLEAR_TAGS || cmdIndex == CLEAR_ALL) && + (entryPtr = Tcl_FindHashEntry(tablePtr->rowStyles, + (char *) row))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + + if ((cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) && + (entryPtr = Tcl_FindHashEntry(tablePtr->rowHeights, + (char *) row-tablePtr->rowOffset))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + + for (col = c1; col <= c2; col++) { + TableMakeArrayIndex(row, col, buf); + + if (cmdIndex == CLEAR_TAGS || cmdIndex == CLEAR_ALL) { + if ((row == r1) && + (entryPtr = Tcl_FindHashEntry(tablePtr->colStyles, + (char *) col))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + if ((entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, + buf))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + if ((entryPtr = Tcl_FindHashEntry(tablePtr->flashCells, + buf))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + if ((entryPtr = Tcl_FindHashEntry(tablePtr->selCells, + buf))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + } + + if ((cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) && + row == r1 && + (entryPtr = Tcl_FindHashEntry(tablePtr->colWidths, (char *) + col-tablePtr->colOffset))) { + Tcl_DeleteHashEntry(entryPtr); + redraw = 1; + } + + if ((cmdIndex == CLEAR_CACHE || cmdIndex == CLEAR_ALL) && + (entryPtr = Tcl_FindHashEntry(tablePtr->cache, buf))) { + Tcl_DeleteHashEntry(entryPtr); + /* if the cache is our data source, + * we need to invalidate the cells changed */ + if ((tablePtr->dataSource == DATA_CACHE) && + (row-tablePtr->rowOffset == tablePtr->activeRow && + col-tablePtr->colOffset == tablePtr->activeCol)) + TableGetActiveBuf(tablePtr); + redraw = 1; + } + } + } + } + /* This could be more sensitive about what it updates, + * but that can actually be a lot more costly in some cases */ + if (redraw) { + if (cmdIndex == CLEAR_SIZES || cmdIndex == CLEAR_ALL) { + TableAdjustParams(tablePtr); + /* rerequest geometry */ + TableGeometryRequest(tablePtr); + } + TableInvalidateAll(tablePtr, 0); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_CurselectionCmd -- + * This procedure is invoked to process the bbox method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_CurselectionCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + Tcl_HashEntry *entryPtr; + Tcl_HashSearch search; + char *value = NULL; + int row, col; + + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?value?"); + return TCL_ERROR; + } + if (objc == 3) { + /* make sure there is a data source to accept a set value */ + if ((tablePtr->state == STATE_DISABLED) || + (tablePtr->dataSource == DATA_NONE)) { + return TCL_OK; + } + value = Tcl_GetString(objv[2]); + for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); + entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { + TableParseArrayIndex(&row, &col, + Tcl_GetHashKey(tablePtr->selCells, entryPtr)); + TableSetCellValue(tablePtr, row, col, value); + row -= tablePtr->rowOffset; + col -= tablePtr->colOffset; + if (row == tablePtr->activeRow && col == tablePtr->activeCol) { + TableGetActiveBuf(tablePtr); + } + TableRefresh(tablePtr, row, col, CELL); + } + } else { + Tcl_Obj *objPtr = Tcl_NewObj(); + + for (entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); + entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { + value = Tcl_GetHashKey(tablePtr->selCells, entryPtr); + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewStringObj(value, -1)); + } + Tcl_SetObjResult(interp, TableCellSortObj(interp, objPtr)); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_CurvalueCmd -- + * This procedure is invoked to process the curvalue method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_CurvalueCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?<value>?"); + return TCL_ERROR; + } else if (!(tablePtr->flags & HAS_ACTIVE)) { + return TCL_OK; + } + + if (objc == 3) { + char *value; + int len; + + value = Tcl_GetStringFromObj(objv[2], &len); + if (STREQ(value, tablePtr->activeBuf)) { + Tcl_SetObjResult(interp, objv[2]); + return TCL_OK; + } + /* validate potential new active buffer contents + * only accept if validation returns acceptance. */ + if (tablePtr->validate && + TableValidateChange(tablePtr, + tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + tablePtr->activeBuf, + value, tablePtr->icursor) != TCL_OK) { + return TCL_OK; + } + tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, len+1); + strcpy(tablePtr->activeBuf, value); + /* mark the text as changed */ + tablePtr->flags |= TEXT_CHANGED; + TableSetActiveIndex(tablePtr); + /* check for possible adjustment of icursor */ + TableGetIcursor(tablePtr, "insert", (int *)0); + TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL); + } + + Tcl_SetStringObj(Tcl_GetObjResult(interp), tablePtr->activeBuf, -1); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_GetCmd -- + * This procedure is invoked to process the bbox method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_GetCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int result = TCL_OK; + int r1, c1, r2, c2, row, col; + + if (objc < 3 || objc > 4) { + Tcl_WrongNumArgs(interp, 2, objv, "first ?last?"); + result = TCL_ERROR; + } else if (TableGetIndexObj(tablePtr, objv[2], &row, &col) == TCL_ERROR) { + result = TCL_ERROR; + } else if (objc == 3) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj(TableGetCellValue(tablePtr, row, col), -1)); + } else if (TableGetIndexObj(tablePtr, objv[3], &r2, &c2) == TCL_ERROR) { + result = TCL_ERROR; + } else { + Tcl_Obj *objPtr = Tcl_NewObj(); + + r1 = MIN(row,r2); r2 = MAX(row,r2); + c1 = MIN(col,c2); c2 = MAX(col,c2); + for ( row = r1; row <= r2; row++ ) { + for ( col = c1; col <= c2; col++ ) { + Tcl_ListObjAppendElement(NULL, objPtr, + Tcl_NewStringObj(TableGetCellValue(tablePtr, + row, col), -1)); + } + } + Tcl_SetObjResult(interp, objPtr); + } + return result; +} + +/* + *-------------------------------------------------------------- + * + * Table_ScanCmd -- + * This procedure is invoked to process the scan method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_ScanCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int x, y, row, col, cmdIndex; + + if (objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x y"); + return TCL_ERROR; + } else if (Tcl_GetIndexFromObj(interp, objv[2], bdCmdNames, + "option", 0, &cmdIndex) != TCL_OK || + Tcl_GetIntFromObj(interp, objv[3], &x) == TCL_ERROR || + Tcl_GetIntFromObj(interp, objv[4], &y) == TCL_ERROR) { + return TCL_ERROR; + } + switch ((enum bdCmd) cmdIndex) { + case BD_MARK: + TableWhatCell(tablePtr, x, y, &row, &col); + tablePtr->scanMarkRow = row-tablePtr->topRow; + tablePtr->scanMarkCol = col-tablePtr->leftCol; + tablePtr->scanMarkX = x; + tablePtr->scanMarkY = y; + break; + + case BD_DRAGTO: { + int oldTop = tablePtr->topRow, oldLeft = tablePtr->leftCol; + y += (5*(y-tablePtr->scanMarkY)); + x += (5*(x-tablePtr->scanMarkX)); + + TableWhatCell(tablePtr, x, y, &row, &col); + + /* maintain appropriate real index */ + tablePtr->topRow = BETWEEN(row-tablePtr->scanMarkRow, + tablePtr->titleRows, tablePtr->rows-1); + tablePtr->leftCol = BETWEEN(col-tablePtr->scanMarkCol, + tablePtr->titleCols, tablePtr->cols-1); + + /* Adjust the table if new top left */ + if (oldTop != tablePtr->topRow || oldLeft != tablePtr->leftCol) { + TableAdjustParams(tablePtr); + } + break; + } + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_SelAnchorCmd -- + * This procedure is invoked to process the selection anchor method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_SelAnchorCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int row, col; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "index"); + return TCL_ERROR; + } else if (TableGetIndexObj(tablePtr, objv[3], &row, &col) != TCL_OK) { + return TCL_ERROR; + } + tablePtr->flags |= HAS_ANCHOR; + /* maintain appropriate real index */ + if (tablePtr->selectTitles) { + tablePtr->anchorRow = BETWEEN(row-tablePtr->rowOffset, + 0, tablePtr->rows-1); + tablePtr->anchorCol = BETWEEN(col-tablePtr->colOffset, + 0, tablePtr->cols-1); + } else { + tablePtr->anchorRow = BETWEEN(row-tablePtr->rowOffset, + tablePtr->titleRows, tablePtr->rows-1); + tablePtr->anchorCol = BETWEEN(col-tablePtr->colOffset, + tablePtr->titleCols, tablePtr->cols-1); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_SelClearCmd -- + * This procedure is invoked to process the selection clear method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_SelClearCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int result = TCL_OK; + char buf1[INDEX_BUFSIZE]; + int row, col, key, clo=0,chi=0,r1,c1,r2,c2; + Tcl_HashEntry *entryPtr; + + if (objc < 4 || objc > 5) { + Tcl_WrongNumArgs(interp, 3, objv, "all|<first> ?<last>?"); + return TCL_ERROR; + } + if (STREQ(Tcl_GetString(objv[3]), "all")) { + Tcl_HashSearch search; + for(entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); + entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) { + TableParseArrayIndex(&row, &col, + Tcl_GetHashKey(tablePtr->selCells,entryPtr)); + Tcl_DeleteHashEntry(entryPtr); + TableRefresh(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, CELL); + } + return TCL_OK; + } + if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR || + (objc==5 && + TableGetIndexObj(tablePtr, objv[4], &r2, &c2) == TCL_ERROR)) { + return TCL_ERROR; + } + key = 0; + if (objc == 4) { + r1 = r2 = row; + c1 = c2 = col; + } else { + r1 = MIN(row,r2); r2 = MAX(row,r2); + c1 = MIN(col,c2); c2 = MAX(col,c2); + } + switch (tablePtr->selectType) { + case SEL_BOTH: + clo = c1; chi = c2; + c1 = tablePtr->colOffset; + c2 = tablePtr->cols-1+c1; + key = 1; + goto CLEAR_CELLS; + CLEAR_BOTH: + key = 0; + c1 = clo; c2 = chi; + case SEL_COL: + r1 = tablePtr->rowOffset; + r2 = tablePtr->rows-1+r1; + break; + case SEL_ROW: + c1 = tablePtr->colOffset; + c2 = tablePtr->cols-1+c1; + break; + } + /* row/col are in user index coords */ +CLEAR_CELLS: + for ( row = r1; row <= r2; row++ ) { + for ( col = c1; col <= c2; col++ ) { + TableMakeArrayIndex(row, col, buf1); + entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf1); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + TableRefresh(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, CELL); + } + } + } + if (key) goto CLEAR_BOTH; + return result; +} + +/* + *-------------------------------------------------------------- + * + * Table_SelIncludesCmd -- + * This procedure is invoked to process the selection includes method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_SelIncludesCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int row, col; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 3, objv, "index"); + return TCL_ERROR; + } else if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR) { + return TCL_ERROR; + } else { + char buf[INDEX_BUFSIZE]; + TableMakeArrayIndex(row, col, buf); + Tcl_SetBooleanObj(Tcl_GetObjResult(interp), + (Tcl_FindHashEntry(tablePtr->selCells, buf)!=NULL)); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_SelSetCmd -- + * This procedure is invoked to process the selection set method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_SelSetCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int row, col, dummy, key; + char buf1[INDEX_BUFSIZE]; + Tcl_HashSearch search; + Tcl_HashEntry *entryPtr; + + int clo=0, chi=0, r1, c1, r2, c2, firstRow, firstCol, lastRow, lastCol; + if (objc < 4 || objc > 5) { + Tcl_WrongNumArgs(interp, 3, objv, "first ?last?"); + return TCL_ERROR; + } + if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR || + (objc==5 && + TableGetIndexObj(tablePtr, objv[4], &r2, &c2) == TCL_ERROR)) { + return TCL_ERROR; + } + key = 0; + lastRow = tablePtr->rows-1+tablePtr->rowOffset; + lastCol = tablePtr->cols-1+tablePtr->colOffset; + if (tablePtr->selectTitles) { + firstRow = tablePtr->rowOffset; + firstCol = tablePtr->colOffset; + } else { + firstRow = tablePtr->titleRows+tablePtr->rowOffset; + firstCol = tablePtr->titleCols+tablePtr->colOffset; + } + /* maintain appropriate user index */ + CONSTRAIN(row, firstRow, lastRow); + CONSTRAIN(col, firstCol, lastCol); + if (objc == 4) { + r1 = r2 = row; + c1 = c2 = col; + } else { + CONSTRAIN(r2, firstRow, lastRow); + CONSTRAIN(c2, firstCol, lastCol); + r1 = MIN(row,r2); r2 = MAX(row,r2); + c1 = MIN(col,c2); c2 = MAX(col,c2); + } + switch (tablePtr->selectType) { + case SEL_BOTH: + if (firstCol > lastCol) c2--; /* No selectable columns in table */ + if (firstRow > lastRow) r2--; /* No selectable rows in table */ + clo = c1; chi = c2; + c1 = firstCol; + c2 = lastCol; + key = 1; + goto SET_CELLS; + SET_BOTH: + key = 0; + c1 = clo; c2 = chi; + case SEL_COL: + r1 = firstRow; + r2 = lastRow; + if (firstCol > lastCol) c2--; /* No selectable columns in table */ + break; + case SEL_ROW: + c1 = firstCol; + c2 = lastCol; + if (firstRow>lastRow) r2--; /* No selectable rows in table */ + break; + } +SET_CELLS: + entryPtr = Tcl_FirstHashEntry(tablePtr->selCells, &search); + for ( row = r1; row <= r2; row++ ) { + for ( col = c1; col <= c2; col++ ) { + TableMakeArrayIndex(row, col, buf1); + if (Tcl_FindHashEntry(tablePtr->selCells, buf1) == NULL) { + Tcl_CreateHashEntry(tablePtr->selCells, buf1, &dummy); + TableRefresh(tablePtr, row-tablePtr->rowOffset, + col-tablePtr->colOffset, CELL); + } + } + } + if (key) goto SET_BOTH; + + /* Adjust the table for top left, selection on screen etc */ + TableAdjustParams(tablePtr); + + /* If the table was previously empty and we want to export the + * selection, we should grab it now */ + if (entryPtr == NULL && tablePtr->exportSelection) { + Tk_OwnSelection(tablePtr->tkwin, XA_PRIMARY, TableLostSelection, + (ClientData) tablePtr); + } + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Table_ViewCmd -- + * This procedure is invoked to process the x|yview method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_ViewCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int row, col, value; + char *xy; + + /* Check xview or yview */ + if (objc > 5) { + Tcl_WrongNumArgs(interp, 2, objv, "?args?"); + return TCL_ERROR; + } + xy = Tcl_GetString(objv[1]); + + if (objc == 2) { + Tcl_Obj *resultPtr; + int diff, x, y, w, h; + double first, last; + + resultPtr = Tcl_GetObjResult(interp); + TableGetLastCell(tablePtr, &row, &col); + TableCellVCoords(tablePtr, row, col, &x, &y, &w, &h, 0); + if (*xy == 'y') { + if (row < tablePtr->titleRows) { + first = 0; + last = 1; + } else { + diff = tablePtr->rowStarts[tablePtr->titleRows]; + last = (double) (tablePtr->rowStarts[tablePtr->rows]-diff); + first = (tablePtr->rowStarts[tablePtr->topRow]-diff) / last; + last = (h+tablePtr->rowStarts[row]-diff) / last; + } + } else { + if (col < tablePtr->titleCols) { + first = 0; + last = 1; + } else { + diff = tablePtr->colStarts[tablePtr->titleCols]; + last = (double) (tablePtr->colStarts[tablePtr->cols]-diff); + first = (tablePtr->colStarts[tablePtr->leftCol]-diff) / last; + last = (w+tablePtr->colStarts[col]-diff) / last; + } + } + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewDoubleObj(first)); + Tcl_ListObjAppendElement(NULL, resultPtr, Tcl_NewDoubleObj(last)); + } else { + /* cache old topleft to see if it changes */ + int oldTop = tablePtr->topRow, oldLeft = tablePtr->leftCol; + + if (objc == 3) { + if (Tcl_GetIntFromObj(interp, objv[2], &value) != TCL_OK) { + return TCL_ERROR; + } + if (*xy == 'y') { + tablePtr->topRow = value + tablePtr->titleRows; + } else { + tablePtr->leftCol = value + tablePtr->titleCols; + } + } else { + int result; + double frac; +#if (TK_MINOR_VERSION > 0) /* 8.1+ */ + result = Tk_GetScrollInfoObj(interp, objc, objv, &frac, &value); +#else + int i; + char **argv = (char **) ckalloc((objc + 1) * sizeof(char *)); + for (i = 0; i < objc; i++) { + argv[i] = Tcl_GetString(objv[i]); + } + argv[i] = NULL; + result = Tk_GetScrollInfo(interp, objc, argv, &frac, &value); + ckfree ((char *) argv); +#endif + switch (result) { + case TK_SCROLL_ERROR: + return TCL_ERROR; + case TK_SCROLL_MOVETO: + if (frac < 0) frac = 0; + if (*xy == 'y') { + tablePtr->topRow = (int)(frac*tablePtr->rows) + +tablePtr->titleRows; + } else { + tablePtr->leftCol = (int)(frac*tablePtr->cols) + +tablePtr->titleCols; + } + break; + case TK_SCROLL_PAGES: + TableGetLastCell(tablePtr, &row, &col); + if (*xy == 'y') { + tablePtr->topRow += value * (row-tablePtr->topRow+1); + } else { + tablePtr->leftCol += value * (col-tablePtr->leftCol+1); + } + break; + case TK_SCROLL_UNITS: + if (*xy == 'y') { + tablePtr->topRow += value; + } else { + tablePtr->leftCol += value; + } + break; + } + } + /* maintain appropriate real index */ + CONSTRAIN(tablePtr->topRow, tablePtr->titleRows, tablePtr->rows-1); + CONSTRAIN(tablePtr->leftCol, tablePtr->titleCols, tablePtr->cols-1); + /* Do the table adjustment if topRow || leftCol changed */ + if (oldTop != tablePtr->topRow || oldLeft != tablePtr->leftCol) { + TableAdjustParams(tablePtr); + } + } + + return TCL_OK; +} + +#if 0 +/* + *-------------------------------------------------------------- + * + * Table_Cmd -- + * This procedure is invoked to process the CMD method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_Cmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int result = TCL_OK; + + return result; +} +#endif diff --git a/libgui/src/tkTableEdit.c b/libgui/src/tkTableEdit.c new file mode 100644 index 00000000000..3fd6d4879b0 --- /dev/null +++ b/libgui/src/tkTableEdit.c @@ -0,0 +1,683 @@ +/* + * tkTableEdit.c -- + * + * This module implements editing functions of a table widget. + * + * Copyright (c) 1998-2000 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#include "tkTable.h" + +static void TableModifyRC _ANSI_ARGS_((register Table *tablePtr, + int doRows, int movetag, + Tcl_HashTable *tagTblPtr, Tcl_HashTable *dimTblPtr, + int offset, int from, int to, int lo, int hi, + int outOfBounds)); + +/* insert/delete subcommands */ +static char *modCmdNames[] = { + "active", "cols", "rows", (char *)NULL +}; +enum modCmd { + MOD_ACTIVE, MOD_COLS, MOD_ROWS +}; + +/* insert/delete row/col switches */ +static char *rcCmdNames[] = { + "-keeptitles", "-holddimensions", "-holdselection", + "-holdtags", "-holdwindows", "--", + (char *) NULL +}; +enum rcCmd { + OPT_TITLES, OPT_DIMS, OPT_SEL, + OPT_TAGS, OPT_WINS, OPT_LAST +}; + +#define HOLD_TITLES 1<<0 +#define HOLD_DIMS 1<<1 +#define HOLD_TAGS 1<<2 +#define HOLD_WINS 1<<3 +#define HOLD_SEL 1<<4 + + +/* + *-------------------------------------------------------------- + * + * Table_EditCmd -- + * This procedure is invoked to process the insert/delete method + * that corresponds to a table widget managed by this module. + * See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ +int +Table_EditCmd(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + register Table *tablePtr = (Table *) clientData; + int doInsert, cmdIndex, first, last; + + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, + "option ?switches? arg ?arg?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObj(interp, objv[2], modCmdNames, + "option", 0, &cmdIndex) != TCL_OK) { + return TCL_ERROR; + } + + doInsert = (*(Tcl_GetString(objv[1])) == 'i'); + switch ((enum modCmd) cmdIndex) { + case MOD_ACTIVE: + if (doInsert) { + /* INSERT */ + if (objc != 5) { + Tcl_WrongNumArgs(interp, 3, objv, "index string"); + return TCL_ERROR; + } + if (TableGetIcursorObj(tablePtr, objv[3], &first) != TCL_OK) { + return TCL_ERROR; + } else if ((tablePtr->flags & HAS_ACTIVE) && + !(tablePtr->flags & ACTIVE_DISABLED) && + tablePtr->state == STATE_NORMAL) { + TableInsertChars(tablePtr, first, Tcl_GetString(objv[4])); + } + } else { + /* DELETE */ + if (objc > 5) { + Tcl_WrongNumArgs(interp, 3, objv, "first ?last?"); + return TCL_ERROR; + } + if (TableGetIcursorObj(tablePtr, objv[3], &first) != TCL_OK) { + return TCL_ERROR; + } + if (objc == 4) { + last = first+1; + } else if (TableGetIcursorObj(tablePtr, objv[4], + &last) != TCL_OK) { + return TCL_ERROR; + } + if ((last >= first) && (tablePtr->flags & HAS_ACTIVE) && + !(tablePtr->flags & ACTIVE_DISABLED) && + tablePtr->state == STATE_NORMAL) { + TableDeleteChars(tablePtr, first, last-first); + } + } + break; /* EDIT ACTIVE */ + + case MOD_COLS: + case MOD_ROWS: { + /* + * ROW/COL INSERTION/DELETION + * FIX: This doesn't handle spans + */ + int i, lo, hi, argsLeft, offset, minkeyoff, doRows; + int maxrow, maxcol, maxkey, minkey, flags, count, *dimPtr; + Tcl_HashTable *tagTblPtr, *dimTblPtr; + Tcl_HashSearch search; + + doRows = (cmdIndex == MOD_ROWS); + flags = 0; + for (i = 3; i < objc; i++) { + if (*(Tcl_GetString(objv[i])) != '-') { + break; + } + if (Tcl_GetIndexFromObj(interp, objv[i], rcCmdNames, + "switch", 0, &cmdIndex) != TCL_OK) { + return TCL_ERROR; + } + if (cmdIndex == OPT_LAST) { + i++; + break; + } + switch (cmdIndex) { + case OPT_TITLES: + flags |= HOLD_TITLES; + break; + case OPT_DIMS: + flags |= HOLD_DIMS; + break; + case OPT_SEL: + flags |= HOLD_SEL; + break; + case OPT_TAGS: + flags |= HOLD_TAGS; + break; + case OPT_WINS: + flags |= HOLD_WINS; + break; + } + } + argsLeft = objc - i; + if (argsLeft < 1 || argsLeft > 2) { + Tcl_WrongNumArgs(interp, 3, objv, "?switches? index ?count?"); + return TCL_ERROR; + } + + count = 1; + maxcol = tablePtr->cols-1+tablePtr->colOffset; + maxrow = tablePtr->rows-1+tablePtr->rowOffset; + if (strcmp(Tcl_GetString(objv[i]), "end") == 0) { + /* allow "end" to be specified as an index */ + first = (doRows) ? maxrow : maxcol; + } else if (Tcl_GetIntFromObj(interp, objv[i], &first) != TCL_OK) { + return TCL_ERROR; + } + if (argsLeft == 2 && + Tcl_GetIntFromObj(interp, objv[++i], &count) != TCL_OK) { + return TCL_ERROR; + } + if (count == 0 || (tablePtr->state == STATE_DISABLED)) { + return TCL_OK; + } + + if (doRows) { + maxkey = maxrow; + minkey = tablePtr->rowOffset; + minkeyoff = tablePtr->rowOffset+tablePtr->titleRows; + offset = tablePtr->rowOffset; + tagTblPtr = tablePtr->rowStyles; + dimTblPtr = tablePtr->rowHeights; + dimPtr = &(tablePtr->rows); + lo = tablePtr->colOffset + + ((flags & HOLD_TITLES) ? tablePtr->titleCols : 0); + hi = maxcol; + } else { + maxkey = maxcol; + minkey = tablePtr->colOffset; + minkeyoff = tablePtr->colOffset+tablePtr->titleCols; + offset = tablePtr->colOffset; + tagTblPtr = tablePtr->colStyles; + dimTblPtr = tablePtr->colWidths; + dimPtr = &(tablePtr->cols); + lo = tablePtr->rowOffset + + ((flags & HOLD_TITLES) ? tablePtr->titleRows : 0); + hi = maxrow; + } + + /* constrain the starting index */ + if (first > maxkey) { + first = maxkey; + } else if (first < minkey) { + first = minkey; + } + if (doInsert) { + /* +count means insert after index, + * -count means insert before index */ + if (count < 0) { + count = -count; + } else { + first++; + } + if ((flags & HOLD_TITLES) && (first < minkeyoff)) { + count -= minkeyoff-first; + if (count <= 0) { + return TCL_OK; + } + first = minkeyoff; + } + if (!(flags & HOLD_DIMS)) { + maxkey += count; + *dimPtr += count; + } + for (i = maxkey; i >= first; i--) { + /* move row/col style && width/height here */ + TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr, + offset, i, i-count, lo, hi, ((i-count) < first)); + } + } else { + /* (index = i && count = 1) == (index = i && count = -1) */ + if (count < 0) { + /* if the count is negative, make sure that the col count will + * delete no greater than the original index */ + if (first+count < minkey) { + if (first-minkey < abs(count)) { + /* + * In this case, the user is asking to delete more rows + * than exist before the minkey, so we have to shrink + * the count down to the existing rows up to index. + */ + count = first-minkey; + } else { + count += first-minkey; + } + first = minkey; + } else { + first += count; + count = -count; + } + } + if ((flags & HOLD_TITLES) && (first <= minkeyoff)) { + count -= minkeyoff-first; + if (count <= 0) { + return TCL_OK; + } + first = minkeyoff; + } + if (count > maxkey-first+1) { + count = maxkey-first+1; + } + if (!(flags & HOLD_DIMS)) { + *dimPtr -= count; + } + for (i = first; i <= maxkey; i++) { + TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr, + offset, i, i+count, lo, hi, ((i+count) > maxkey)); + } + } + if (!(flags & HOLD_SEL) && + Tcl_FirstHashEntry(tablePtr->selCells, &search) != NULL) { + /* clear selection - forceful, but effective */ + Tcl_DeleteHashTable(tablePtr->selCells); + Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS); + } + + /* + * Make sure that the modified dimension is actually legal + * after removing all that stuff. + */ + *dimPtr = MAX(1, *dimPtr); + + TableAdjustParams(tablePtr); + /* change the geometry */ + TableGeometryRequest(tablePtr); + /* FIX: + * This has to handle when the previous rows/cols resize because + * of the *stretchmode. InvalidateAll does that, but could be + * more efficient. + */ + TableInvalidateAll(tablePtr, 0); + break; + } + + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TableDeleteChars -- + * Remove one or more characters from an table widget. + * + * Results: + * None. + * + * Side effects: + * Memory gets freed, the table gets modified and (eventually) + * redisplayed. + * + *---------------------------------------------------------------------- + */ +void +TableDeleteChars(tablePtr, index, count) + register Table *tablePtr; /* Table widget to modify. */ + int index; /* Index of first character to delete. */ + int count; /* How many characters to delete. */ +{ +#ifdef TCL_UTF_MAX + int byteIndex, byteCount, newByteCount, numBytes, numChars; + char *new, *string; + + string = tablePtr->activeBuf; + numBytes = strlen(string); + numChars = Tcl_NumUtfChars(string, numBytes); + if ((index + count) > numChars) { + count = numChars - index; + } + if (count <= 0) { + return; + } + + byteIndex = Tcl_UtfAtIndex(string, index) - string; + byteCount = Tcl_UtfAtIndex(string + byteIndex, count) + - (string + byteIndex); + + newByteCount = numBytes + 1 - byteCount; + new = (char *) ckalloc((unsigned) newByteCount); + memcpy(new, string, (size_t) byteIndex); + strcpy(new + byteIndex, string + byteIndex + byteCount); +#else + int oldlen; + char *new; + + /* this gets the length of the string, as well as ensuring that + * the cursor isn't beyond the end char */ + TableGetIcursor(tablePtr, "end", &oldlen); + + if ((index+count) > oldlen) + count = oldlen-index; + if (count <= 0) + return; + + new = (char *) ckalloc((unsigned)(oldlen-count+1)); + strncpy(new, tablePtr->activeBuf, (size_t) index); + strcpy(new+index, tablePtr->activeBuf+index+count); + /* make sure this string is null terminated */ + new[oldlen-count] = '\0'; +#endif + /* This prevents deletes on BREAK or validation error. */ + if (tablePtr->validate && + TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + tablePtr->activeBuf, new, index) != TCL_OK) { + ckfree(new); + return; + } + + ckfree(tablePtr->activeBuf); + tablePtr->activeBuf = new; + + /* mark the text as changed */ + tablePtr->flags |= TEXT_CHANGED; + + if (tablePtr->icursor >= index) { + if (tablePtr->icursor >= (index+count)) { + tablePtr->icursor -= count; + } else { + tablePtr->icursor = index; + } + } + + TableSetActiveIndex(tablePtr); + + TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL); +} + +/* + *---------------------------------------------------------------------- + * + * TableInsertChars -- + * Add new characters to the active cell of a table widget. + * + * Results: + * None. + * + * Side effects: + * New information gets added to tablePtr; it will be redisplayed + * soon, but not necessarily immediately. + * + *---------------------------------------------------------------------- + */ +void +TableInsertChars(tablePtr, index, value) + register Table *tablePtr; /* Table that is to get the new elements. */ + int index; /* Add the new elements before this element. */ + char *value; /* New characters to add (NULL-terminated + * string). */ +{ +#ifdef TCL_UTF_MAX + int oldlen, byteIndex, byteCount; + char *new, *string; + + byteCount = strlen(value); + if (byteCount == 0) { + return; + } + + /* Is this an autoclear and this is the first update */ + /* Note that this clears without validating */ + if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) { + /* set the buffer to be empty */ + tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1); + tablePtr->activeBuf[0] = '\0'; + /* the insert position now has to be 0 */ + index = 0; + tablePtr->icursor = 0; + } + + string = tablePtr->activeBuf; + byteIndex = Tcl_UtfAtIndex(string, index) - string; + + oldlen = strlen(string); + new = (char *) ckalloc((unsigned)(oldlen + byteCount + 1)); + memcpy(new, string, (size_t) byteIndex); + strcpy(new + byteIndex, value); + strcpy(new + byteIndex + byteCount, string + byteIndex); + + /* validate potential new active buffer */ + /* This prevents inserts on either BREAK or validation error. */ + if (tablePtr->validate && + TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + tablePtr->activeBuf, new, byteIndex) != TCL_OK) { + ckfree(new); + return; + } + + /* + * The following construction is used because inserting improperly + * formed UTF-8 sequences between other improperly formed UTF-8 + * sequences could result in actually forming valid UTF-8 sequences; + * the number of characters added may not be Tcl_NumUtfChars(string, -1), + * because of context. The actual number of characters added is how + * many characters were are in the string now minus the number that + * used to be there. + */ + + if (tablePtr->icursor >= index) { + tablePtr->icursor += Tcl_NumUtfChars(new, oldlen+byteCount) + - Tcl_NumUtfChars(tablePtr->activeBuf, oldlen); + } + + ckfree(string); + tablePtr->activeBuf = new; + +#else + int oldlen, newlen; + char *new; + + newlen = strlen(value); + if (newlen == 0) return; + + /* Is this an autoclear and this is the first update */ + /* Note that this clears without validating */ + if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) { + /* set the buffer to be empty */ + tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1); + tablePtr->activeBuf[0] = '\0'; + /* the insert position now has to be 0 */ + index = 0; + } + oldlen = strlen(tablePtr->activeBuf); + /* get the buffer to at least the right length */ + new = (char *) ckalloc((unsigned)(oldlen+newlen+1)); + strncpy(new, tablePtr->activeBuf, (size_t) index); + strcpy(new+index, value); + strcpy(new+index+newlen, (tablePtr->activeBuf)+index); + /* make sure this string is null terminated */ + new[oldlen+newlen] = '\0'; + + /* validate potential new active buffer */ + /* This prevents inserts on either BREAK or validation error. */ + if (tablePtr->validate && + TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset, + tablePtr->activeCol+tablePtr->colOffset, + tablePtr->activeBuf, new, index) != TCL_OK) { + ckfree(new); + return; + } + ckfree(tablePtr->activeBuf); + tablePtr->activeBuf = new; + + if (tablePtr->icursor >= index) { + tablePtr->icursor += newlen; + } +#endif + + /* mark the text as changed */ + tablePtr->flags |= TEXT_CHANGED; + + TableSetActiveIndex(tablePtr); + + TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL); +} + +/* + *---------------------------------------------------------------------- + * + * TableModifyRC -- + * Helper function that does the core work of moving rows/cols + * and associated tags. + * + * Results: + * None. + * + * Side effects: + * Moves cell data and possibly tag data + * + *---------------------------------------------------------------------- + */ +static void +TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr, + offset, from, to, lo, hi, outOfBounds) + Table *tablePtr; /* Information about text widget. */ + int doRows; /* rows (1) or cols (0) */ + int flags; /* flags indicating what to move */ + Tcl_HashTable *tagTblPtr, *dimTblPtr; /* Pointers to the row/col tags + * and width/height tags */ + int offset; /* appropriate offset */ + int from, to; /* the from and to row/col */ + int lo, hi; /* the lo and hi col/row */ + int outOfBounds; /* the boundary check for shifting items */ +{ + int j, new; + char buf[INDEX_BUFSIZE], buf1[INDEX_BUFSIZE]; + Tcl_HashEntry *entryPtr, *newPtr; + TableEmbWindow *ewPtr; + + /* + * move row/col style && width/height here + * If -holdtags is specified, we don't move the user-set widths/heights + * of the absolute rows/columns, otherwise we enter here to move the + * dimensions appropriately + */ + if (!(flags & HOLD_TAGS)) { + entryPtr = Tcl_FindHashEntry(tagTblPtr, (char *)from); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + entryPtr = Tcl_FindHashEntry(dimTblPtr, (char *)from-offset); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + if (!outOfBounds) { + entryPtr = Tcl_FindHashEntry(tagTblPtr, (char *)to); + if (entryPtr != NULL) { + newPtr = Tcl_CreateHashEntry(tagTblPtr, (char *)from, &new); + Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr)); + Tcl_DeleteHashEntry(entryPtr); + } + entryPtr = Tcl_FindHashEntry(dimTblPtr, (char *)to-offset); + if (entryPtr != NULL) { + newPtr = Tcl_CreateHashEntry(dimTblPtr, (char *)from-offset, + &new); + Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr)); + Tcl_DeleteHashEntry(entryPtr); + } + } + } + for (j = lo; j <= hi; j++) { + if (doRows /* rows */) { + TableMakeArrayIndex(from, j, buf); + TableMakeArrayIndex(to, j, buf1); + TableMoveCellValue(tablePtr, to, j, buf1, from, j, buf, + outOfBounds); + } else { + TableMakeArrayIndex(j, from, buf); + TableMakeArrayIndex(j, to, buf1); + TableMoveCellValue(tablePtr, j, to, buf1, j, from, buf, + outOfBounds); + } + /* + * If -holdselection is specified, we leave the selected cells in the + * absolute cell values, otherwise we enter here to move the + * selection appropriately + */ + if (!(flags & HOLD_SEL)) { + entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + if (!outOfBounds) { + entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf1); + if (entryPtr != NULL) { + Tcl_CreateHashEntry(tablePtr->selCells, buf, &new); + Tcl_DeleteHashEntry(entryPtr); + } + } + } + /* + * If -holdtags is specified, we leave the tags in the + * absolute cell values, otherwise we enter here to move the + * tags appropriately + */ + if (!(flags & HOLD_TAGS)) { + entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf); + if (entryPtr != NULL) { + Tcl_DeleteHashEntry(entryPtr); + } + if (!outOfBounds) { + entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf1); + if (entryPtr != NULL) { + newPtr = Tcl_CreateHashEntry(tablePtr->cellStyles, buf, + &new); + Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr)); + Tcl_DeleteHashEntry(entryPtr); + } + } + } + /* + * If -holdwindows is specified, we leave the windows in the + * absolute cell values, otherwise we enter here to move the + * windows appropriately + */ + if (!(flags & HOLD_WINS)) { + /* + * Delete whatever window might be in our destination + */ + Table_WinDelete(tablePtr, buf); + if (!outOfBounds) { + /* + * buf1 is where the window is + * buf is where we want it to be + * + * This is an adaptation of Table_WinMove, which we can't + * use because we are intermediately fiddling with boundaries + */ + entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf1); + if (entryPtr != NULL) { + /* + * If there was a window in our source, + * get the window pointer to move it + */ + ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr); + /* and free the old hash table entry */ + Tcl_DeleteHashEntry(entryPtr); + + entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, buf, + &new); + /* + * We needn't check if a window was in buf, since the + * Table_WinDelete above should guarantee that no window + * is there. Just set the new entry's value. + */ + Tcl_SetHashValue(entryPtr, (ClientData) ewPtr); + ewPtr->hPtr = entryPtr; + } + } + } + } +} diff --git a/libgui/src/tkTableInitScript.h b/libgui/src/tkTableInitScript.h new file mode 100644 index 00000000000..1084717757b --- /dev/null +++ b/libgui/src/tkTableInitScript.h @@ -0,0 +1,90 @@ +/* + * tkTableInitScript.h -- + * + * This file contains common init script for tkTable + * + * Copyright (c) 1998 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +/* + * The following string is the startup script executed when the table is + * loaded. It looks on disk in several different directories for a script + * "TBL_RUNTIME" (as defined in Makefile) that is compatible with this + * version of tkTable. The sourced script has all key bindings defined. + */ + +static char tkTableInitScript[] = "if {[info proc tkTableInit]==\"\"} {\n\ + proc tkTableInit {} {\n\ + global tk_library tcl_pkgPath errorInfo env\n\ + rename tkTableInit {}\n\ + set errors {}\n\ + if {![info exists env(TK_TABLE_LIBRARY_FILE)]} {\n\ + set env(TK_TABLE_LIBRARY_FILE) " TBL_RUNTIME "\n\ + }\n\ + if {[info exists env(TK_TABLE_LIBRARY)]} {\n\ + lappend dirs $env(TK_TABLE_LIBRARY)\n\ + }\n\ + lappend dirs " TBL_RUNTIME_DIR "\n\ + if {[info exists tcl_pkgPath]} {\n\ + foreach i $tcl_pkgPath {\n\ + lappend dirs [file join $i Tktable" TBL_VERSION "] \\\n\ + [file join $i Tktable] $i\n\ + }\n\ + }\n\ + lappend dirs $tk_library [pwd]\n\ + foreach i $dirs {\n\ + set try [file join $i $env(TK_TABLE_LIBRARY_FILE)]\n\ + if {[file exists $try]} {\n\ + if {![catch {uplevel #0 [list source $try]} msg]} {\n\ + set env(TK_TABLE_LIBRARY) $i\n\ + return\n\ + } else {\n\ + append errors \"$try: $msg\n$errorInfo\n\"\n\ + }\n\ + }\n\ + }\n" +#ifdef NO_EMBEDDED_RUNTIME +" set msg \"Can't find a $env(TK_TABLE_LIBRARY_FILE) in the following directories: \n\"\n\ + append msg \" $dirs\n\n$errors\n\n\"\n\ + append msg \"This probably means that TkTable wasn't installed properly.\"\n\ + return -code error $msg\n" +#else +" set env(TK_TABLE_LIBRARY) EMBEDDED_RUNTIME\n" +# ifdef MAC_TCL +" source -rsrc tkTable" +# else +" uplevel #0 {" +# include "tkTable.tcl.h" +" }" +# endif +#endif +" }\n\ +}\n\ +tkTableInit"; + +/* + * The init script can't make certain calls in a safe interpreter, + * so we always have to use the embedded runtime for it + */ +static char tkTableSafeInitScript[] = "if {[info proc tkTableInit]==\"\"} {\n\ + proc tkTableInit {} {\n\ + set env(TK_TABLE_LIBRARY) EMBEDDED_RUNTIME\n" +#ifdef NO_EMBEDDED_RUNTIME +" append msg \"tkTable requires embedded runtime to be compiled for\"\n\ + append msg \" use in safe interpreters\"\n\ + return -code error $msg\n" +#endif +# ifdef MAC_TCL +" source -rsrc tkTable" +# else +" uplevel #0 {" +# include "tkTable.tcl.h" +" }" +# endif +" }\n\ +}\n\ +tkTableInit"; + diff --git a/libgui/src/tkTablePs.c b/libgui/src/tkTablePs.c new file mode 100644 index 00000000000..018f0791ec3 --- /dev/null +++ b/libgui/src/tkTablePs.c @@ -0,0 +1,1299 @@ +/* + * tkTablePs.c -- + * + * This module implements postscript output for table widgets. + * Based off of Tk8.1a2 tkCanvPs.c. + * + * Copyright (c) 1991-1994 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * changes 1998 Copyright (c) 1998 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + */ + +#include "tkTable.h" + +/* This is for Tcl_DStringAppendAll */ +#if defined(__STDC__) || defined(HAS_STDARG) +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#ifndef TCL_INTEGER_SPACE +/* This appears in 8.1 */ +#define TCL_INTEGER_SPACE 24 +#endif + +/* + * One of the following structures is created to keep track of Postscript + * output being generated. It consists mostly of information provided on + * the widget command line. + */ + +typedef struct TkPostscriptInfo { + int x, y, width, height; /* Area to print, in table pixel + * coordinates. */ + int x2, y2; /* x+width and y+height. */ + char *pageXString; /* String value of "-pagex" option or NULL. */ + char *pageYString; /* String value of "-pagey" option or NULL. */ + double pageX, pageY; /* Postscript coordinates (in points) + * corresponding to pageXString and + * pageYString. Don't forget that y-values + * grow upwards for Postscript! */ + char *pageWidthString; /* Printed width of output. */ + char *pageHeightString; /* Printed height of output. */ + double scale; /* Scale factor for conversion: each pixel + * maps into this many points. */ + Tk_Anchor pageAnchor; /* How to anchor bbox on Postscript page. */ + int rotate; /* Non-zero means output should be rotated + * on page (landscape mode). */ + char *fontVar; /* If non-NULL, gives name of global variable + * containing font mapping information. + * Malloc'ed. */ + char *colorVar; /* If non-NULL, give name of global variable + * containing color mapping information. + * Malloc'ed. */ + char *colorMode; /* Mode for handling colors: "monochrome", + * "gray", or "color". Malloc'ed. */ + int colorLevel; /* Numeric value corresponding to colorMode: + * 0 for mono, 1 for gray, 2 for color. */ + char *fileName; /* Name of file in which to write Postscript; + * NULL means return Postscript info as + * result. Malloc'ed. */ + char *channelName; /* If -channel is specified, the name of + * the channel to use. */ + Tcl_Channel chan; /* Open channel corresponding to fileName. */ + Tcl_HashTable fontTable; /* Hash table containing names of all font + * families used in output. The hash table + * values are not used. */ + char *first, *last; /* table indices to start and end at */ +} TkPostscriptInfo; + +/* + * The table below provides a template that's used to process arguments + * to the table "postscript" command and fill in TkPostscriptInfo + * structures. + */ + +static Tk_ConfigSpec configSpecs[] = { + {TK_CONFIG_STRING, "-colormap", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, colorVar), 0}, + {TK_CONFIG_STRING, "-colormode", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, colorMode), 0}, + {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, fileName), 0}, + {TK_CONFIG_STRING, "-channel", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, channelName), 0}, + {TK_CONFIG_STRING, "-first", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, first), 0}, + {TK_CONFIG_STRING, "-fontmap", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, fontVar), 0}, + {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, height), 0}, + {TK_CONFIG_STRING, "-last", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, last), 0}, + {TK_CONFIG_ANCHOR, "-pageanchor", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, pageAnchor), 0}, + {TK_CONFIG_STRING, "-pageheight", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, pageHeightString), 0}, + {TK_CONFIG_STRING, "-pagewidth", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, pageWidthString), 0}, + {TK_CONFIG_STRING, "-pagex", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, pageXString), 0}, + {TK_CONFIG_STRING, "-pagey", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, pageYString), 0}, + {TK_CONFIG_BOOLEAN, "-rotate", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, rotate), 0}, + {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, width), 0}, + {TK_CONFIG_PIXELS, "-x", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, x), 0}, + {TK_CONFIG_PIXELS, "-y", (char *) NULL, (char *) NULL, "", + Tk_Offset(TkPostscriptInfo, y), 0}, + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0} +}; + +/* + * The prolog data. Generated by str2c from prolog.ps + * This was split in small chunks by str2c because + * some C compiler have limitations on the size of static strings. + * (str2c is a small tcl script in tcl's tool directory (source release)) + */ +/* + * This is a stripped down version of that found in tkCanvPs.c of Tk8.1a2. + * Comments, and stuff pertaining to stipples and other unused entities + * have been removed + */ +static CONST char * CONST prolog[]= { + /* Start of part 1 */ + "%%BeginProlog\n\ +50 dict begin\n\ +\n\ +% This is standard prolog for Postscript generated by Tk's table widget.\n\ +% Based of standard prolog for Tk's canvas widget.\n\ +\n\ +% INITIALIZING VARIABLES\n\ +\n\ +/baseline 0 def\n\ +/height 0 def\n\ +/justify 0 def\n\ +/cellHeight 0 def\n\ +/cellWidth 0 def\n\ +/spacing 0 def\n\ +/strings 0 def\n\ +/xoffset 0 def\n\ +/yoffset 0 def\n\ +/x 0 def\n\ +/y 0 def\n\ +\n\ +% Define the array ISOLatin1Encoding, if it isn't already present.\n\ +\n\ +systemdict /ISOLatin1Encoding known not {\n\ + /ISOLatin1Encoding [\n\ + /space /space /space /space /space /space /space /space\n\ + /space /space /space /space /space /space /space /space\n\ + /space /space /space /space /space /space /space /space\n\ + /space /space /space /space /space /space /space /space\n\ + /space /exclam /quotedbl /numbersign /dollar /percent /ampersand\n\ + /quoteright\n\ + /parenleft /parenright /asterisk /plus /comma /minus /period /slash\n\ + /zero /one /two /three /four /five /six /seven\n\ + /eight /nine /colon /semicolon /less /equal /greater /question\n\ + /at /A /B /C /D /E /F /G\n\ + /H /I /J /K /L /M /N /O\n\ + /P /Q /R /S /T /U /V /W\n\ + /X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n\ + /quoteleft /a /b /c /d /e /f /g\n\ + /h /i /j /k /l /m /n /o\n\ + /p /q /r /s /t /u /v /w\n\ + /x /y /z /braceleft /bar /braceright /asciitilde /space\n\ + /space /space /space /space /space /space /space /space\n\ + /space /space /space /space /space /space /space /space\n\ + /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent\n\ + /dieresis /space /ring /cedilla /space /hungarumlaut /ogonek /caron\n\ + /space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n\ + /dieresis /copyright /ordfem", + + "inine /guillemotleft /logicalnot /hyphen\n\ + /registered /macron\n\ + /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph\n\ + /periodcentered\n\ + /cedillar /onesuperior /ordmasculine /guillemotright /onequarter\n\ + /onehalf /threequarters /questiondown\n\ + /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n\ + /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex\n\ + /Idieresis\n\ + /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n\ + /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn\n\ + /germandbls\n\ + /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n\ + /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex\n\ + /idieresis\n\ + /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n\ + /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn\n\ + /ydieresis\n\ + ] def\n\ +} if\n", + + "\n\ +% font ISOEncode font\n\ +% This procedure changes the encoding of a font from the default\n\ +% Postscript encoding to ISOLatin1. It's typically invoked just\n\ +% before invoking \"setfont\". The body of this procedure comes from\n\ +% Section 5.6.1 of the Postscript book.\n\ +\n\ +/ISOEncode {\n\ + dup length dict begin\n\ + {1 index /FID ne {def} {pop pop} ifelse} forall\n\ + /Encoding ISOLatin1Encoding def\n\ + currentdict\n\ + end\n\ +\n\ + % I'm not sure why it's necessary to use \"definefont\" on this new\n\ + % font, but it seems to be important; just use the name \"Temporary\"\n\ + % for the font.\n\ +\n\ + /Temporary exch definefont\n\ +} bind def\n\ +\n\ +% -- AdjustColor --\n\ +% Given a color value already set for output by the caller, adjusts\n\ +% that value to a grayscale or mono value if requested by the CL variable.\n\ +\n\ +/AdjustColor {\n\ + setrgbcolor\n\ + CL 2 lt {\n\ + currentgray\n\ + CL 0 eq {\n\ + .5 lt {0} {1} ifelse\n\ + } if\n\ + setgray\n\ + } if\n\ +} bind def\n\ +\n\ +% pointSize fontName SetFont\n\ +% The ISOEncode shouldn't be done to Symbol fonts...\n\ +/SetFont {\n\ + findfont exch scalefont ISOEncode setfont\n\ +} def\n\ +\n", + + "% x y strings spacing xoffset yoffset justify ... DrawText --\n\ +% This procedure does all of the real work of drawing text. The\n\ +% color and font must already have been set by the caller, and the\n\ +% following arguments must be on the stack:\n\ +%\n\ +% x, y - Coordinates at which to draw text.\n\ +% strings - An array of strings, one for each line of the text item,\n\ +% in order from top to bottom.\n\ +% spacing - Spacing between lines.\n\ +% xoffset - Horizontal offset for text bbox relative to x and y: 0 for\n\ +% nw/w/sw anchor, -0.5 for n/center/s, and -1.0 for ne/e/se.\n\ +% yoffset - Vertical offset for text bbox relative to x and y: 0 for\n\ +% nw/n/ne anchor, +0.5 for w/center/e, and +1.0 for sw/s/se.\n\ +% justify - 0 for left justification, 0.5 for center, 1 for right justify.\n\ +% cellWidth - width for this cell\n\ +% cellHeight - height for this cell\n\ +%\n\ +% Also, when this procedure is invoked, the color and font must already\n\ +% have been set for the text.\n\ +\n", + + "/DrawCellText {\n\ + /cellHeight exch def\n\ + /cellWidth exch def\n\ + /justify exch def\n\ + /yoffset exch def\n\ + /xoffset exch def\n\ + /spacing exch def\n\ + /strings exch def\n\ + /y exch def\n\ + /x exch def\n\ +\n\ + % Compute the baseline offset and the actual font height.\n\ +\n\ + 0 0 moveto (TXygqPZ) false charpath\n\ + pathbbox dup /baseline exch def\n\ + exch pop exch sub /height exch def pop\n\ + newpath\n\ +\n\ + % Translate coordinates first so that the origin is at the upper-left\n\ + % corner of the text's bounding box. Remember that x and y for\n\ + % positioning are still on the stack.\n\ +\n\ + col0 x sub row0 y sub translate\n\ + cellWidth xoffset mul\n\ + strings length 1 sub spacing mul height add yoffset mul translate\n\ +\n\ + % Now use the baseline and justification information to translate so\n\ + % that the origin is at the baseline and positioning point for the\n\ + % first line of text.\n\ +\n\ + justify cellWidth mul baseline neg translate\n\ +\n\ + % Iterate over each of the lines to output it. For each line,\n\ + % compute its width again so it can be properly justified, then\n\ + % display it.\n\ +\n\ + strings {\n\ + dup stringwidth pop\n\ + justify neg mul 0 moveto\n\ + show\n\ + 0 spacing neg translate\n\ + } forall\n\ +} bind def\n\ +\n", + + "%\n\ +% x, y - Coordinates at which to draw text.\n\ +% strings - An array of strings, one for each line of the text item,\n\ +% in order from top to bottom.\n\ +% spacing - Spacing between lines.\n\ +% xoffset - Horizontal offset for text bbox relative to x and y: 0 for\n\ +% nw/w/sw anchor, -0.5 for n/center/s, and -1.0 for ne/e/se.\n\ +% yoffset - Vertical offset for text bbox relative to x and y: 0 for\n\ +% nw/n/ne anchor, +0.5 for w/center/e, and +1.0 for sw/s/se.\n\ +% justify - 0 for left justification, 0.5 for center, 1 for right justify.\n\ +% cellWidth - width for this cell\n\ +% cellHeight - height for this cell\n\ +%\n\ +% Also, when this procedure is invoked, the color and font must already\n\ +% have been set for the text.\n\ +\n\ +/DrawCellTextOld {\n\ + /cellHeight exch def\n\ + /cellWidth exch def\n\ + /justify exch def\n\ + /yoffset exch def\n\ + /xoffset exch def\n\ + /spacing exch def\n\ + /strings exch def\n\ +\n\ + % Compute the baseline offset and the actual font height.\n\ +\n\ + 0 0 moveto (TXygqPZ) false charpath\n\ + pathbbox dup /baseline exch def\n\ + exch pop exch sub /height exch def pop\n\ + newpath\n\ +\n\ + % Translate coordinates first so that the origin is at the upper-left\n\ + % corner of the text's bounding box. Remember that x and y for\n\ + % positioning are still on the stack.\n\ +\n\ + translate\n\ + cellWidth xoffset mul\n\ + strings length 1 sub spacing mul height add yoffset mul translate\n\ +\n\ + % Now use the baseline and justification information to translate so\n\ + % that the origin is at the baseline and positioning point for the\n\ + % first line of text.\n\ +\n\ + justify cellWidth mul baseline neg translate\n\ +\n\ + % Iterate over each of the lines to output it. For each line,\n\ + % compute its width again so it can be properly justified, then\n\ + % display it.\n\ +\n\ + strings {\n\ + dup stringwidth pop\n\ + justify neg mul 0 moveto\n\ + show\n\ + 0 spacing neg translate\n\ + } forall\n\ +} bind def\n\ +\n\ +%%EndProlog\n\ +", + /* End of part 5 */ + + NULL /* End of data marker */ +}; + +/* + * Forward declarations for procedures defined later in this file: + */ + +static int GetPostscriptPoints _ANSI_ARGS_((Tcl_Interp *interp, + char *string, double *doublePtr)); +int Tk_TablePsFont _ANSI_ARGS_((Tcl_Interp *interp, + Table *tablePtr, Tk_Font tkfont)); +int Tk_TablePsColor _ANSI_ARGS_((Tcl_Interp *interp, + Table *tablePtr, XColor *colorPtr)); +static int TextToPostscript _ANSI_ARGS_((Tcl_Interp *interp, + Table *tablePtr, TableTag *tagPtr, int tagX, int tagY, + int width, int height, int row, int col, + Tk_TextLayout textLayout)); + +/* + * Tcl could really use some more convenience routines... + * This is just Tcl_DStringAppend for multiple lines, including + * the full text of each line + */ +void +Tcl_DStringAppendAll TCL_VARARGS_DEF(Tcl_DString *, arg1) +{ + va_list argList; + Tcl_DString *dstringPtr; + char *string; + + dstringPtr = TCL_VARARGS_START(Tcl_DString *, arg1, argList); + while ((string = va_arg(argList, char *)) != NULL) { + Tcl_DStringAppend(dstringPtr, string, -1); + } + va_end(argList); +} + +/* + *-------------------------------------------------------------- + * + * Table_PostscriptCmd -- + * + * This procedure is invoked to process the "postscript" options + * of the widget command for table widgets. See the user + * documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * See the user documentation. + * + *-------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +Table_PostscriptCmd(clientData, interp, objc, objv) + ClientData clientData; /* Information about table widget. */ + Tcl_Interp *interp; /* Current interpreter. */ + int objc; /* Number of argument objects. */ + Tcl_Obj *CONST objv[]; +{ +#ifdef _WIN32 + /* + * At the moment, it just doesn't like this code... + */ + return TCL_OK; +#else + register Table *tablePtr = (Table *) clientData; + TkPostscriptInfo psInfo, *oldInfoPtr; + int result; + int row, col, firstRow, firstCol, lastRow, lastCol; + /* dimensions of first and last cell to output */ + int x0, y0, w0, h0, xn, yn, wn, hn; + int x, y, w, h, i; +#define STRING_LENGTH 400 + char string[STRING_LENGTH+1], *p, **argv; + size_t length; + int deltaX = 0, deltaY = 0; /* Offset of lower-left corner of area to + * be marked up, measured in table units + * from the positioning point on the page + * (reflects anchor position). Initial + * values needed only to stop compiler + * warnings. */ + Tcl_HashSearch search; + Tcl_HashEntry *hPtr; + CONST char * CONST *chunk; + Tk_TextLayout textLayout = NULL; + char *value; + int rowHeight, total, *colWidths, iW, iH; + TableTag *tagPtr, *colPtr, *rowPtr, *titlePtr; + Tcl_DString postscript, buffer; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?option value ...?"); + return TCL_ERROR; + } + + /* + *---------------------------------------------------------------- + * Initialize the data structure describing Postscript generation, + * then process all the arguments to fill the data structure in. + *---------------------------------------------------------------- + */ + + Tcl_DStringInit(&postscript); + Tcl_DStringInit(&buffer); + oldInfoPtr = tablePtr->psInfoPtr; + tablePtr->psInfoPtr = &psInfo; + /* This is where in the window that we start printing from */ + psInfo.x = 0; + psInfo.y = 0; + psInfo.width = -1; + psInfo.height = -1; + psInfo.pageXString = NULL; + psInfo.pageYString = NULL; + psInfo.pageX = 72*4.25; + psInfo.pageY = 72*5.5; + psInfo.pageWidthString = NULL; + psInfo.pageHeightString = NULL; + psInfo.scale = 1.0; + psInfo.pageAnchor = TK_ANCHOR_CENTER; + psInfo.rotate = 0; + psInfo.fontVar = NULL; + psInfo.colorVar = NULL; + psInfo.colorMode = NULL; + psInfo.colorLevel = 0; + psInfo.fileName = NULL; + psInfo.channelName = NULL; + psInfo.chan = NULL; + psInfo.first = NULL; + psInfo.last = NULL; + Tcl_InitHashTable(&psInfo.fontTable, TCL_STRING_KEYS); + + /* + * The magic StringifyObjects + */ + argv = (char **) ckalloc((objc + 1) * sizeof(char *)); + for (i = 0; i < objc; i++) + argv[i] = Tcl_GetString(objv[i]); + argv[i] = NULL; + + result = Tk_ConfigureWidget(interp, tablePtr->tkwin, configSpecs, + objc-2, argv+2, (char *) &psInfo, + TK_CONFIG_ARGV_ONLY); + if (result != TCL_OK) { + goto cleanup; + } + + if (psInfo.first == NULL) { + firstRow = 0; + firstCol = 0; + } else if (TableGetIndex(tablePtr, psInfo.first, &firstRow, &firstCol) + != TCL_OK) { + result = TCL_ERROR; + goto cleanup; + } + if (psInfo.last == NULL) { + lastRow = tablePtr->rows-1; + lastCol = tablePtr->cols-1; + } else if (TableGetIndex(tablePtr, psInfo.last, &lastRow, &lastCol) + != TCL_OK) { + result = TCL_ERROR; + goto cleanup; + } + + if (psInfo.fileName != NULL) { + /* Check that -file and -channel are not both specified. */ + if (psInfo.channelName != NULL) { + Tcl_AppendResult(interp, "can't specify both -file", + " and -channel", (char *) NULL); + result = TCL_ERROR; + goto cleanup; + } + + /* + * Check that we are not in a safe interpreter. If we are, disallow + * the -file specification. + */ + if (Tcl_IsSafe(interp)) { + Tcl_AppendResult(interp, "can't specify -file in a", + " safe interpreter", (char *) NULL); + result = TCL_ERROR; + goto cleanup; + } + + p = Tcl_TranslateFileName(interp, psInfo.fileName, &buffer); + if (p == NULL) { + result = TCL_ERROR; + goto cleanup; + } + psInfo.chan = Tcl_OpenFileChannel(interp, p, "w", 0666); + Tcl_DStringFree(&buffer); + Tcl_DStringInit(&buffer); + if (psInfo.chan == NULL) { + result = TCL_ERROR; + goto cleanup; + } + } + + if (psInfo.channelName != NULL) { + int mode; + /* + * Check that the channel is found in this interpreter and that it + * is open for writing. + */ + psInfo.chan = Tcl_GetChannel(interp, psInfo.channelName, &mode); + if (psInfo.chan == (Tcl_Channel) NULL) { + result = TCL_ERROR; + goto cleanup; + } + if ((mode & TCL_WRITABLE) == 0) { + Tcl_AppendResult(interp, "channel \"", psInfo.channelName, + "\" wasn't opened for writing", (char *) NULL); + result = TCL_ERROR; + goto cleanup; + } + } + + if (psInfo.colorMode == NULL) { + psInfo.colorLevel = 2; + } else { + length = strlen(psInfo.colorMode); + if (strncmp(psInfo.colorMode, "monochrome", length) == 0) { + psInfo.colorLevel = 0; + } else if (strncmp(psInfo.colorMode, "gray", length) == 0) { + psInfo.colorLevel = 1; + } else if (strncmp(psInfo.colorMode, "color", length) == 0) { + psInfo.colorLevel = 2; + } else { + Tcl_AppendResult(interp, "bad color mode \"", psInfo.colorMode, + "\": must be monochrome, gray or color", (char *) NULL); + goto cleanup; + } + } + + TableCellCoords(tablePtr, firstRow, firstCol, &x0, &y0, &w0, &h0); + TableCellCoords(tablePtr, lastRow, lastCol, &xn, &yn, &wn, &hn); + psInfo.x = x0; + psInfo.y = y0; + if (psInfo.width == -1) { + psInfo.width = xn+wn; + } + if (psInfo.height == -1) { + psInfo.height = yn+hn; + } + psInfo.x2 = psInfo.x + psInfo.width; + psInfo.y2 = psInfo.y + psInfo.height; + + if (psInfo.pageXString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageXString, + &psInfo.pageX) != TCL_OK) { + goto cleanup; + } + } + if (psInfo.pageYString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageYString, + &psInfo.pageY) != TCL_OK) { + goto cleanup; + } + } + if (psInfo.pageWidthString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageWidthString, + &psInfo.scale) != TCL_OK) { + goto cleanup; + } + psInfo.scale /= psInfo.width; + } else if (psInfo.pageHeightString != NULL) { + if (GetPostscriptPoints(interp, psInfo.pageHeightString, + &psInfo.scale) != TCL_OK) { + goto cleanup; + } + psInfo.scale /= psInfo.height; + } else { + psInfo.scale = (72.0/25.4)*WidthMMOfScreen(Tk_Screen(tablePtr->tkwin)) + / WidthOfScreen(Tk_Screen(tablePtr->tkwin)); + } + switch (psInfo.pageAnchor) { + case TK_ANCHOR_NW: + case TK_ANCHOR_W: + case TK_ANCHOR_SW: + deltaX = 0; + break; + case TK_ANCHOR_N: + case TK_ANCHOR_CENTER: + case TK_ANCHOR_S: + deltaX = -psInfo.width/2; + break; + case TK_ANCHOR_NE: + case TK_ANCHOR_E: + case TK_ANCHOR_SE: + deltaX = -psInfo.width; + break; + } + switch (psInfo.pageAnchor) { + case TK_ANCHOR_NW: + case TK_ANCHOR_N: + case TK_ANCHOR_NE: + deltaY = - psInfo.height; + break; + case TK_ANCHOR_W: + case TK_ANCHOR_CENTER: + case TK_ANCHOR_E: + deltaY = -psInfo.height/2; + break; + case TK_ANCHOR_SW: + case TK_ANCHOR_S: + case TK_ANCHOR_SE: + deltaY = 0; + break; + } + + /* + *-------------------------------------------------------- + * Make a PREPASS over all of the tags + * to collect information about all the fonts in use, so that + * we can output font information in the proper form required + * by the Document Structuring Conventions. + *-------------------------------------------------------- + */ + + Tk_TablePsFont(interp, tablePtr, tablePtr->defaultTag.tkfont); + Tcl_ResetResult(interp); + for (hPtr = Tcl_FirstHashEntry(tablePtr->tagTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + tagPtr = (TableTag *) Tcl_GetHashValue(hPtr); + if (tagPtr->tkfont != NULL) { + Tk_TablePsFont(interp, tablePtr, tagPtr->tkfont); + } + } + Tcl_ResetResult(interp); + + /* + *-------------------------------------------------------- + * Generate the header and prolog for the Postscript. + *-------------------------------------------------------- + */ + + sprintf(string, " %d,%d => %d,%d\n", firstRow, firstCol, lastRow, lastCol); + Tcl_DStringAppendAll(&postscript, + "%!PS-Adobe-3.0 EPSF-3.0\n", + "%%Creator: Tk Table Widget ", TBL_VERSION, "\n", + "%%Title: Window ", + Tk_PathName(tablePtr->tkwin), string, + "%%BoundingBox: ", + (char *) NULL); + if (!psInfo.rotate) { + sprintf(string, "%d %d %d %d\n", + (int) (psInfo.pageX + psInfo.scale*deltaX), + (int) (psInfo.pageY + psInfo.scale*deltaY), + (int) (psInfo.pageX + psInfo.scale*(deltaX + psInfo.width) + + 1.0), + (int) (psInfo.pageY + psInfo.scale*(deltaY + psInfo.height) + + 1.0)); + } else { + sprintf(string, "%d %d %d %d\n", + (int) (psInfo.pageX - psInfo.scale*(deltaY + psInfo.height)), + (int) (psInfo.pageY + psInfo.scale*deltaX), + (int) (psInfo.pageX - psInfo.scale*deltaY + 1.0), + (int) (psInfo.pageY + psInfo.scale*(deltaX + psInfo.width) + + 1.0)); + } + Tcl_DStringAppendAll(&postscript, string, + "%%Pages: 1\n%%DocumentData: Clean7Bit\n", + "%%Orientation: ", + psInfo.rotate?"Landscape\n":"Portrait\n", + (char *) NULL); + p = "%%DocumentNeededResources: font "; + for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + sprintf(string, "%s%s\n", p, Tcl_GetHashKey(&psInfo.fontTable, hPtr)); + Tcl_DStringAppend(&postscript, string, -1); + p = "%%+ font "; + } + Tcl_DStringAppend(&postscript, "%%EndComments\n\n", -1); + + /* + * Insert the prolog + */ + for (chunk=prolog; *chunk; chunk++) { + Tcl_DStringAppend(&postscript, *chunk, -1); + } + + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_DStringValue(&postscript), -1); + Tcl_DStringFree(&postscript); + Tcl_DStringInit(&postscript); + } + + /* + * Document setup: set the color level and include fonts. + * This is where we start using &postscript + */ + + sprintf(string, "/CL %d def\n", psInfo.colorLevel); + Tcl_DStringAppendAll(&postscript, "%%BeginSetup\n", string, (char *) NULL); + for (hPtr = Tcl_FirstHashEntry(&psInfo.fontTable, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + sprintf(string, "%s%s\n", "%%IncludeResource: font ", + Tcl_GetHashKey(&psInfo.fontTable, hPtr)); + Tcl_DStringAppend(&postscript, string, -1); + } + Tcl_DStringAppend(&postscript, "%%EndSetup\n\n", -1); + + /* + * Page setup: move to page positioning point, rotate if + * needed, set scale factor, offset for proper anchor position, + * and set clip region. + */ + + sprintf(string, "%.1f %.1f translate\n", + psInfo.pageX, psInfo.pageY); + Tcl_DStringAppendAll(&postscript, "%%Page: 1 1\nsave\n", + string, psInfo.rotate?"90 rotate\n":"", + (char *) NULL); + sprintf(string, "%.4g %.4g scale\n%d %d translate\n", + psInfo.scale, psInfo.scale, deltaX - psInfo.x, deltaY); + Tcl_DStringAppend(&postscript, string, -1); + sprintf(string, "%d %.15g moveto %d %.15g lineto %d %.15g lineto %d %.15g", + psInfo.x, (double) psInfo.y2-psInfo.y, + psInfo.x2,(double) psInfo.y2-psInfo.y, + psInfo.x2, 0.0, psInfo.x, 0.0); + Tcl_DStringAppend(&postscript, string, -1); + Tcl_DStringAppend(&postscript, " lineto closepath clip newpath\n", -1); + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_DStringValue(&postscript), -1); + Tcl_DStringFree(&postscript); + Tcl_DStringInit(&postscript); + } + + /* + * Go through each cell, calculating full desired height + */ + result = TCL_OK; + + hPtr = Tcl_FindHashEntry(tablePtr->tagTable, "title"); + titlePtr = (TableTag *) Tcl_GetHashValue(hPtr); + + total = 0; + colWidths = (int *) ckalloc((lastCol-firstCol) * sizeof(int)); + for (col = 0; col <= lastCol-firstCol; col++) colWidths[col] = 0; + Tcl_DStringAppend(&buffer, "gsave\n", -1); + for (row = firstRow; row <= lastRow; row++) { + rowHeight = 0; + rowPtr = FindRowColTag(tablePtr, row+tablePtr->rowOffset, ROW); + for (col = firstCol; col <= lastCol; col++) { + /* get the coordinates for the cell */ + TableCellCoords(tablePtr, row, col, &x, &y, &w, &h); + if ((x >= psInfo.x2) || (x+w < psInfo.x) || + (y >= psInfo.y2) || (y+h < psInfo.y)) { + continue; + } + + if (row == tablePtr->activeRow && col == tablePtr->activeCol) { + value = tablePtr->activeBuf; + } else { + value = TableGetCellValue(tablePtr, row+tablePtr->rowOffset, + col+tablePtr->colOffset); + } + if (!strlen(value)) { + continue; + } + + /* Create the tag here */ + tagPtr = TableNewTag(); + /* First, merge in the default tag */ + TableMergeTag(tagPtr, &(tablePtr->defaultTag)); + + colPtr = FindRowColTag(tablePtr, col+tablePtr->colOffset, COL); + if (colPtr != (TableTag *) NULL) TableMergeTag(tagPtr, colPtr); + if (rowPtr != (TableTag *) NULL) TableMergeTag(tagPtr, rowPtr); + /* Am I in the titles */ + if (row < tablePtr->topRow || col < tablePtr->leftCol) { + TableMergeTag(tagPtr, titlePtr); + } + /* Does this have a cell tag */ + TableMakeArrayIndex(row+tablePtr->rowOffset, + col+tablePtr->colOffset, string); + hPtr = Tcl_FindHashEntry(tablePtr->cellStyles, string); + if (hPtr != NULL) { + TableMergeTag(tagPtr, (TableTag *) Tcl_GetHashValue(hPtr)); + } + + /* + * the use of -1 instead of Tcl_NumUtfChars means we don't + * pass NULLs to postscript + */ + textLayout = Tk_ComputeTextLayout(tagPtr->tkfont, value, -1, + (tagPtr->wrap>0) ? w : 0, + tagPtr->justify, + (tagPtr->multiline>0) ? 0 : + TK_IGNORE_NEWLINES, &iW, &iH); + + rowHeight = MAX(rowHeight, iH); + colWidths[col-firstCol] = MAX(colWidths[col-firstCol], iW); + + result = TextToPostscript(interp, tablePtr, tagPtr, + x, y, iW, iH, row, col, textLayout); + Tk_FreeTextLayout(textLayout); + if (result != TCL_OK) { + char msg[64 + TCL_INTEGER_SPACE]; + + sprintf(msg, "\n (generating Postscript for cell %s)", + string); + Tcl_AddErrorInfo(interp, msg); + goto cleanup; + } + Tcl_DStringAppend(&buffer, Tcl_GetStringResult(interp), -1); + } + sprintf(string, "/row%d %d def\n", + row, tablePtr->psInfoPtr->y2 - total); + Tcl_DStringAppend(&postscript, string, -1); + total += rowHeight + 2*tablePtr->defaultTag.bd; + } + Tcl_DStringAppend(&buffer, "grestore\n", -1); + sprintf(string, "/row%d %d def\n", row, tablePtr->psInfoPtr->y2 - total); + Tcl_DStringAppend(&postscript, string, -1); + + total = tablePtr->defaultTag.bd; + for (col = firstCol; col <= lastCol; col++) { + sprintf(string, "/col%d %d def\n", col, total); + Tcl_DStringAppend(&postscript, string, -1); + total += colWidths[col-firstCol] + 2*tablePtr->defaultTag.bd; + } + sprintf(string, "/col%d %d def\n", col, total); + Tcl_DStringAppend(&postscript, string, -1); + + Tcl_DStringAppend(&postscript, Tcl_DStringValue(&buffer), -1); + + /* + * Output to channel at the end of it all + * This should more incremental, but that can't be avoided in order + * to post-define width/height of the cols/rows + */ + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_DStringValue(&postscript), -1); + Tcl_DStringFree(&postscript); + Tcl_DStringInit(&postscript); + } + + /* + *--------------------------------------------------------------------- + * Output page-end information, such as commands to print the page + * and document trailer stuff. + *--------------------------------------------------------------------- + */ + + Tcl_DStringAppend(&postscript, + "restore showpage\n\n%%Trailer\nend\n%%EOF\n", -1); + if (psInfo.chan != NULL) { + Tcl_Write(psInfo.chan, Tcl_DStringValue(&postscript), -1); + Tcl_DStringFree(&postscript); + Tcl_DStringInit(&postscript); + } + + /* + * Clean up psInfo to release malloc'ed stuff. + */ + +cleanup: + ckfree((char *) argv); + Tcl_DStringResult(interp, &postscript); + Tcl_DStringFree(&postscript); + Tcl_DStringFree(&buffer); + if (psInfo.first != NULL) { + ckfree(psInfo.first); + } + if (psInfo.last != NULL) { + ckfree(psInfo.last); + } + if (psInfo.pageXString != NULL) { + ckfree(psInfo.pageXString); + } + if (psInfo.pageYString != NULL) { + ckfree(psInfo.pageYString); + } + if (psInfo.pageWidthString != NULL) { + ckfree(psInfo.pageWidthString); + } + if (psInfo.pageHeightString != NULL) { + ckfree(psInfo.pageHeightString); + } + if (psInfo.fontVar != NULL) { + ckfree(psInfo.fontVar); + } + if (psInfo.colorVar != NULL) { + ckfree(psInfo.colorVar); + } + if (psInfo.colorMode != NULL) { + ckfree(psInfo.colorMode); + } + if (psInfo.fileName != NULL) { + ckfree(psInfo.fileName); + } + if ((psInfo.chan != NULL) && (psInfo.channelName == NULL)) { + Tcl_Close(interp, psInfo.chan); + } + if (psInfo.channelName != NULL) { + ckfree(psInfo.channelName); + } + Tcl_DeleteHashTable(&psInfo.fontTable); + tablePtr->psInfoPtr = oldInfoPtr; + return result; +#endif +} + +/* + *-------------------------------------------------------------- + * + * Tk_TablePsColor -- + * + * This procedure is called by individual table items when + * they want to set a color value for output. Given information + * about an X color, this procedure will generate Postscript + * commands to set up an appropriate color in Postscript. + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in the interp's result. + * If no error occurs, then additional Postscript will be + * appended to the interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +Tk_TablePsColor(interp, tablePtr, colorPtr) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Table *tablePtr; /* Information about table. */ + XColor *colorPtr; /* Information about color. */ +{ + TkPostscriptInfo *psInfoPtr = tablePtr->psInfoPtr; + int tmp; + double red, green, blue; + char string[200]; + + /* + * If there is a color map defined, then look up the color's name + * in the map and use the Postscript commands found there, if there + * are any. + */ + + if (psInfoPtr->colorVar != NULL) { + char *cmdString; + + cmdString = Tcl_GetVar2(interp, psInfoPtr->colorVar, + Tk_NameOfColor(colorPtr), 0); + if (cmdString != NULL) { + Tcl_AppendResult(interp, cmdString, "\n", (char *) NULL); + return TCL_OK; + } + } + + /* + * No color map entry for this color. Grab the color's intensities + * and output Postscript commands for them. Special note: X uses + * a range of 0-65535 for intensities, but most displays only use + * a range of 0-255, which maps to (0, 256, 512, ... 65280) in the + * X scale. This means that there's no way to get perfect white, + * since the highest intensity is only 65280 out of 65535. To + * work around this problem, rescale the X intensity to a 0-255 + * scale and use that as the basis for the Postscript colors. This + * scheme still won't work if the display only uses 4 bits per color, + * but most diplays use at least 8 bits. + */ + + tmp = colorPtr->red; + red = ((double) (tmp >> 8))/255.0; + tmp = colorPtr->green; + green = ((double) (tmp >> 8))/255.0; + tmp = colorPtr->blue; + blue = ((double) (tmp >> 8))/255.0; + sprintf(string, "%.3f %.3f %.3f AdjustColor\n", + red, green, blue); + Tcl_AppendResult(interp, string, (char *) NULL); + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * Tk_TablePsFont -- + * + * This procedure is called by individual table items when + * they want to output text. Given information about an X + * font, this procedure will generate Postscript commands + * to set up an appropriate font in Postscript. + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in the interp's result. + * If no error occurs, then additional Postscript will be + * appended to the interp's result. + * + * Side effects: + * The Postscript font name is entered into psInfoPtr->fontTable + * if it wasn't already there. + * + *-------------------------------------------------------------- + */ + +int +Tk_TablePsFont(interp, tablePtr, tkfont) + Tcl_Interp *interp; /* Interpreter for returning Postscript + * or error message. */ + Table *tablePtr; /* Information about table. */ + Tk_Font tkfont; /* Information about font in which text + * is to be printed. */ +{ + TkPostscriptInfo *psInfoPtr = tablePtr->psInfoPtr; + char *end; + char pointString[TCL_INTEGER_SPACE]; + Tcl_DString ds; + int i, points; + + /* + * First, look up the font's name in the font map, if there is one. + * If there is an entry for this font, it consists of a list + * containing font name and size. Use this information. + */ + + Tcl_DStringInit(&ds); + + if (psInfoPtr->fontVar != NULL) { + char *list, **argv; + int objc; + double size; + char *name; + + name = Tk_NameOfFont(tkfont); + list = Tcl_GetVar2(interp, psInfoPtr->fontVar, name, 0); + if (list != NULL) { + if (Tcl_SplitList(interp, list, &objc, &argv) != TCL_OK) { + badMapEntry: + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "bad font map entry for \"", name, + "\": \"", list, "\"", (char *) NULL); + return TCL_ERROR; + } + if (objc != 2) { + goto badMapEntry; + } + size = strtod(argv[1], &end); + if ((size <= 0) || (*end != 0)) { + goto badMapEntry; + } + + Tcl_DStringAppend(&ds, argv[0], -1); + points = (int) size; + + ckfree((char *) argv); + goto findfont; + } + } + + points = Tk_PostscriptFontName(tkfont, &ds); + +findfont: + sprintf(pointString, "%d", points); + Tcl_AppendResult(interp, pointString, " /", Tcl_DStringValue(&ds), + " SetFont\n", (char *) NULL); + Tcl_CreateHashEntry(&psInfoPtr->fontTable, Tcl_DStringValue(&ds), &i); + Tcl_DStringFree(&ds); + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * GetPostscriptPoints -- + * + * Given a string, returns the number of Postscript points + * corresponding to that string. + * + * Results: + * The return value is a standard Tcl return result. If + * TCL_OK is returned, then everything went well and the + * screen distance is stored at *doublePtr; otherwise + * TCL_ERROR is returned and an error message is left in + * the interp's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +GetPostscriptPoints(interp, string, doublePtr) + Tcl_Interp *interp; /* Use this for error reporting. */ + char *string; /* String describing a screen distance. */ + double *doublePtr; /* Place to store converted result. */ +{ + char *end; + double d; + + d = strtod(string, &end); + if (end == string) { + error: + Tcl_AppendResult(interp, "bad distance \"", string, + "\"", (char *) NULL); + return TCL_ERROR; + } +#define UCHAR(c) ((unsigned char) (c)) + while ((*end != '\0') && isspace(UCHAR(*end))) { + end++; + } + switch (*end) { + case 'c': + d *= 72.0/2.54; + end++; + break; + case 'i': + d *= 72.0; + end++; + break; + case 'm': + d *= 72.0/25.4; + end++; + break; + case 0: + break; + case 'p': + end++; + break; + default: + goto error; + } + while ((*end != '\0') && isspace(UCHAR(*end))) { + end++; + } + if (*end != 0) { + goto error; + } + *doublePtr = d; + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TextToPostscript -- + * + * This procedure is called to generate Postscript for + * text items. + * + * Results: + * The return value is a standard Tcl result. If an error + * occurs in generating Postscript then an error message is + * left in the interp's result, replacing whatever used + * to be there. If no error occurs, then Postscript for the + * item is appended to the result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +TextToPostscript(interp, tablePtr, tagPtr, tagX, tagY, width, height, + row, col, textLayout) + Tcl_Interp *interp; /* Leave Postscript or error message here. */ + Table *tablePtr; /* Information about overall canvas. */ + TableTag *tagPtr; /* */ + int tagX, tagY; /* */ + int width, height; /* */ + int row, col; /* */ + Tk_TextLayout textLayout; /* */ +{ + int x, y; + Tk_FontMetrics fm; + char *justify; + char buffer[500]; + Tk_3DBorder fg = tagPtr->fg; + + if (fg == NULL) { + fg = tablePtr->defaultTag.fg; + } + + if (Tk_TablePsFont(interp, tablePtr, tagPtr->tkfont) != TCL_OK) { + return TCL_ERROR; + } + if (Tk_TablePsColor(interp, tablePtr, Tk_3DBorderColor(fg)) != TCL_OK) { + return TCL_ERROR; + } + + sprintf(buffer, "%% %.15g %.15g [\n", (tagX+width)/2.0, + tablePtr->psInfoPtr->y2 - ((tagY+height)/2.0)); + Tcl_AppendResult(interp, buffer, (char *) NULL); + sprintf(buffer, "col%d row%d [\n", col, row); + Tcl_AppendResult(interp, buffer, (char *) NULL); + + Tk_TextLayoutToPostscript(interp, textLayout); + + x = 0; y = 0; justify = NULL; /* lint. */ + switch (tagPtr->anchor) { + case TK_ANCHOR_NW: x = 0; y = 0; break; + case TK_ANCHOR_N: x = 1; y = 0; break; + case TK_ANCHOR_NE: x = 2; y = 0; break; + case TK_ANCHOR_E: x = 2; y = 1; break; + case TK_ANCHOR_SE: x = 2; y = 2; break; + case TK_ANCHOR_S: x = 1; y = 2; break; + case TK_ANCHOR_SW: x = 0; y = 2; break; + case TK_ANCHOR_W: x = 0; y = 1; break; + case TK_ANCHOR_CENTER: x = 1; y = 1; break; + } + switch (tagPtr->justify) { + case TK_JUSTIFY_RIGHT: justify = "1"; break; + case TK_JUSTIFY_CENTER: justify = "0.5";break; + case TK_JUSTIFY_LEFT: justify = "0"; + } + + Tk_GetFontMetrics(tagPtr->tkfont, &fm); + sprintf(buffer, "] %d %g %g %s %d %d DrawCellText\n", + fm.linespace, (x / -2.0), (y / 2.0), justify, + width, height); + Tcl_AppendResult(interp, buffer, (char *) NULL); + + return TCL_OK; +} diff --git a/libgui/src/tkTableUtil.c b/libgui/src/tkTableUtil.c new file mode 100644 index 00000000000..29e2f143456 --- /dev/null +++ b/libgui/src/tkTableUtil.c @@ -0,0 +1,340 @@ +/* + * tkTableUtil.c -- + * + * This module contains utility functions for table widgets. + * + * Copyright (c) 2000 Jeffrey Hobbs + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id$ + */ + +#include "tkTable.h" + +static char * Cmd_GetName _ANSI_ARGS_((const Cmd_Struct *cmds, int val)); +static int Cmd_GetValue _ANSI_ARGS_((const Cmd_Struct *cmds, + const char *arg)); +static void Cmd_GetError _ANSI_ARGS_((Tcl_Interp *interp, + const Cmd_Struct *cmds, const char *arg)); + + +/* + *---------------------------------------------------------------------- + * + * TableOptionBdSet -- + * + * This routine configures the borderwidth value for a tag. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * It may adjust the tag struct values of bd[0..4] and borders. + * + *---------------------------------------------------------------------- + */ + +int +TableOptionBdSet(clientData, interp, tkwin, value, widgRec, offset) + ClientData clientData; /* Type of struct being set. */ + Tcl_Interp *interp; /* Used for reporting errors. */ + Tk_Window tkwin; /* Window containing table widget. */ + char *value; /* Value of option. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ +{ + char **borderStr; + int *bordersPtr, *bdPtr; + int type = (int) clientData; + int result = TCL_OK; + int argc; + char **argv; + + + if ((type == BD_TABLE) && (value[0] == '\0')) { + /* + * NULL strings aren't allowed for the table global -bd + */ + Tcl_AppendResult(interp, "borderwidth value may not be empty", + (char *) NULL); + return TCL_ERROR; + } + + if ((type == BD_TABLE) || (type == BD_TABLE_TAG)) { + TableTag *tagPtr = (TableTag *) (widgRec + offset); + borderStr = &(tagPtr->borderStr); + bordersPtr = &(tagPtr->borders); + bdPtr = tagPtr->bd; + } else if (type == BD_TABLE_WIN) { + TableEmbWindow *tagPtr = (TableEmbWindow *) widgRec; + borderStr = &(tagPtr->borderStr); + bordersPtr = &(tagPtr->borders); + bdPtr = tagPtr->bd; + } else { + panic("invalid type given to TableOptionBdSet\n"); + return TCL_ERROR; /* lint */ + } + + result = Tcl_SplitList(interp, value, &argc, &argv); + if (result == TCL_OK) { + int i, bd[4]; + + if (((type == BD_TABLE) && (argc == 0)) || (argc == 3) || (argc > 4)) { + Tcl_AppendResult(interp, + "1, 2 or 4 values must be specified for borderwidth", + (char *) NULL); + result = TCL_ERROR; + } else { + /* + * We use the shadow bd array first, in case we have an error + * parsing arguments half way through. + */ + for (i = 0; i < argc; i++) { + if (Tk_GetPixels(interp, tkwin, argv[i], &(bd[i])) != TCL_OK) { + result = TCL_ERROR; + break; + } + } + /* + * If everything is OK, store the parsed and given values for + * easy retrieval. + */ + if (result == TCL_OK) { + for (i = 0; i < argc; i++) { + bdPtr[i] = MAX(0, bd[i]); + } + if (*borderStr) { + ckfree(*borderStr); + } + if (value) { + *borderStr = (char *) ckalloc(strlen(value) + 1); + strcpy(*borderStr, value); + } else { + *borderStr = NULL; + } + *bordersPtr = argc; + } + } + ckfree ((char *) argv); + } + + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TableOptionBdGet -- + * + * Results: + * Value of the -bd option. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +TableOptionBdGet(clientData, tkwin, widgRec, offset, freeProcPtr) + ClientData clientData; /* Type of struct being set. */ + Tk_Window tkwin; /* Window containing canvas widget. */ + char *widgRec; /* Pointer to record for item. */ + int offset; /* Offset into item. */ + Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with + * information about how to reclaim + * storage for return string. */ +{ + register int type = (int) clientData; + + if (type == BD_TABLE) { + return ((TableTag *) (widgRec + offset))->borderStr; + } else if (type == BD_TABLE_TAG) { + return ((TableTag *) widgRec)->borderStr; + } else if (type == BD_TABLE_WIN) { + return ((TableEmbWindow *) widgRec)->borderStr; + } else { + panic("invalid type given to TableOptionBdSet\n"); + return NULL; /* lint */ + } +} + +/* + *---------------------------------------------------------------------- + * + * TableTagConfigureBd -- + * This routine configures the border values based on a tag. + * The previous value of the bd string (oldValue) is assumed to + * be a valid value for this tag. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * It may adjust the value used by -bd. + * + *---------------------------------------------------------------------- + */ + +int +TableTagConfigureBd(Table *tablePtr, TableTag *tagPtr, + char *oldValue, int nullOK) +{ + int i, argc, result = TCL_OK; + char **argv; + + /* + * First check to see if the value really changed. + */ + if (strcmp(tagPtr->borderStr ? tagPtr->borderStr : "", + oldValue ? oldValue : "") == 0) { + return TCL_OK; + } + + tagPtr->borders = 0; + if (!nullOK && ((tagPtr->borderStr == NULL) + || (*(tagPtr->borderStr) == '\0'))) { + /* + * NULL strings aren't allowed for this tag + */ + result = TCL_ERROR; + } else if (tagPtr->borderStr) { + result = Tcl_SplitList(tablePtr->interp, tagPtr->borderStr, + &argc, &argv); + if (result == TCL_OK) { + if ((!nullOK && (argc == 0)) || (argc == 3) || (argc > 4)) { + Tcl_SetResult(tablePtr->interp, + "1, 2 or 4 values must be specified to -borderwidth", + TCL_STATIC); + result = TCL_ERROR; + } else { + for (i = 0; i < argc; i++) { + if (Tk_GetPixels(tablePtr->interp, tablePtr->tkwin, + argv[i], &(tagPtr->bd[i])) != TCL_OK) { + result = TCL_ERROR; + break; + } + tagPtr->bd[i] = MAX(0, tagPtr->bd[i]); + } + tagPtr->borders = argc; + } + ckfree ((char *) argv); + } + } + + if (result != TCL_OK) { + if (tagPtr->borderStr) { + ckfree ((char *) tagPtr->borderStr); + } + if (oldValue != NULL) { + size_t length = strlen(oldValue) + 1; + /* + * We are making the assumption that oldValue is correct. + * We have to reparse in case the bad new value had a couple + * of correct args before failing on a bad pixel value. + */ + Tcl_SplitList(tablePtr->interp, oldValue, &argc, &argv); + for (i = 0; i < argc; i++) { + Tk_GetPixels(tablePtr->interp, tablePtr->tkwin, + argv[i], &(tagPtr->bd[i])); + } + ckfree ((char *) argv); + tagPtr->borders = argc; + tagPtr->borderStr = (char *) ckalloc(length); + memcpy(tagPtr->borderStr, oldValue, length); + } else { + tagPtr->borders = 0; + tagPtr->borderStr = (char *) NULL; + } + } + + return result; +} + +/* + *---------------------------------------------------------------------- + * + * Cmd_OptionSet -- + * + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Cmd_OptionSet(ClientData clientData, Tcl_Interp *interp, + Tk_Window unused, char *value, char *widgRec, int offset) +{ + Cmd_Struct *p = (Cmd_Struct *)clientData; + int mode = Cmd_GetValue(p,value); + if (!mode) { + Cmd_GetError(interp,p,value); + return TCL_ERROR; + } + *((int*)(widgRec+offset)) = mode; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * Cmd_OptionGet -- + * + * + * Results: + * Value of the option. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +Cmd_OptionGet(ClientData clientData, Tk_Window unused, + char *widgRec, int offset, Tcl_FreeProc **freeProcPtr) +{ + Cmd_Struct *p = (Cmd_Struct *)clientData; + int mode = *((int*)(widgRec+offset)); + return Cmd_GetName(p,mode); +} + +/* + * simple Cmd_Struct lookup functions + */ + +char * +Cmd_GetName(const Cmd_Struct *cmds, int val) +{ + for(;cmds->name && cmds->name[0];cmds++) { + if (cmds->value==val) return cmds->name; + } + return NULL; +} + +int +Cmd_GetValue(const Cmd_Struct *cmds, const char *arg) +{ + unsigned int len = strlen(arg); + for(;cmds->name && cmds->name[0];cmds++) { + if (!strncmp(cmds->name, arg, len)) return cmds->value; + } + return 0; +} + +void +Cmd_GetError(Tcl_Interp *interp, const Cmd_Struct *cmds, const char *arg) +{ + int i; + Tcl_AppendResult(interp, "bad option \"", arg, "\" must be ", (char *) 0); + for(i=0;cmds->name && cmds->name[0];cmds++,i++) { + Tcl_AppendResult(interp, (i?", ":""), cmds->name, (char *) 0); + } +} diff --git a/libgui/src/tkWinPrintCanvas.c b/libgui/src/tkWinPrintCanvas.c index 5b7bc41830a..029c6687f52 100644 --- a/libgui/src/tkWinPrintCanvas.c +++ b/libgui/src/tkWinPrintCanvas.c @@ -52,20 +52,20 @@ PrintCanvasCmd(clientData, interp, argc, argv) int tiles_wide,tiles_high; int tile_y, tile_x; int screenX1, screenX2, screenY1, screenY2, width, height; - DOCINFO *lpdi = malloc(sizeof(DOCINFO)); + DOCINFO *lpdi = (DOCINFO *) ckalloc(sizeof(DOCINFO)); if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " canvas \"", (char *) NULL); - return TCL_ERROR; + goto error; } /* The second arg is the canvas widget */ if (!Tcl_GetCommandInfo(interp, argv[1], &canvCmd)) { Tcl_AppendResult(interp, "couldn't get canvas information for \"", argv[1], "\"", (char *) NULL); - return TCL_ERROR; + goto error; } memset(&dm,0,sizeof(DEVMODE)); @@ -74,7 +74,7 @@ PrintCanvasCmd(clientData, interp, argc, argv) memset(lpdi,0,sizeof(DOCINFO)); lpdi->cbSize=sizeof(DOCINFO); - lpdi->lpszDocName=malloc(255); + lpdi->lpszDocName= (LPCSTR) ckalloc(255); sprintf((char*)lpdi->lpszDocName,"SN - Printing\0"); lpdi->lpszOutput=NULL; @@ -164,8 +164,12 @@ PrintCanvasCmd(clientData, interp, argc, argv) EndDoc(pd.hDC); done: + ckfree ((char*) lpdi->lpszDocName); + ckfree ((char*) lpdi); return TCL_OK; - error: +error: + ckfree ((char*) lpdi->lpszDocName); + ckfree ((char*) lpdi); return TCL_ERROR; } diff --git a/libgui/src/tkWinPrintText.c b/libgui/src/tkWinPrintText.c index a9ffd36bfb9..88ed8b8884d 100644 --- a/libgui/src/tkWinPrintText.c +++ b/libgui/src/tkWinPrintText.c @@ -212,7 +212,8 @@ typedef struct TextStyle { -void DisplayDLineToDrawable(TkText *textPtr, DLine *dlPtr, DLine *prevPtr, TkWinDrawable *drawable); +static void +DisplayDLineToDrawable(TkText *textPtr, DLine *dlPtr, DLine *prevPtr, TkWinDrawable *drawable); /* *-------------------------------------------------------------- @@ -248,7 +249,7 @@ PrintTextCmd(clientData, interp, argc, argv) Pixmap pixmap; int bottomY = 0; /* Initialization needed only to stop * compiler warnings. */ - DOCINFO *lpdi = malloc(sizeof(DOCINFO)); + DOCINFO *lpdi = (DOCINFO *) ckalloc(sizeof(DOCINFO)); TkTextIndex first, last; int numLines; HDC hDCpixmap; @@ -272,7 +273,7 @@ PrintTextCmd(clientData, interp, argc, argv) Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " text \"", (char *) NULL); - return TCL_ERROR; + goto error; } /* @@ -281,7 +282,7 @@ PrintTextCmd(clientData, interp, argc, argv) if (!Tcl_GetCommandInfo(interp, argv[1], &textCmd)) { Tcl_AppendResult(interp, "couldn't get text information for \"", argv[1], "\"", (char *) NULL); - return TCL_ERROR; + goto error; } memset(&dm,0,sizeof(DEVMODE)); @@ -290,7 +291,7 @@ PrintTextCmd(clientData, interp, argc, argv) memset(lpdi,0,sizeof(DOCINFO)); lpdi->cbSize=sizeof(DOCINFO); - lpdi->lpszDocName=malloc(255); + lpdi->lpszDocName = (LPCSTR) ckalloc(255); sprintf((char*)lpdi->lpszDocName,"SN - Printing\0"); lpdi->lpszOutput=NULL; @@ -445,8 +446,12 @@ PrintTextCmd(clientData, interp, argc, argv) textPtr->dInfoPtr->flags|=DINFO_OUT_OF_DATE; done: + ckfree ((char*) lpdi->lpszDocName); + ckfree ((char*) lpdi); return TCL_OK; - error: +error: + ckfree ((char*) lpdi->lpszDocName); + ckfree ((char*) lpdi); return TCL_ERROR; } |