tktreectrl-2.4.1/0000755000076400010400000000000011646706161014223 5ustar TimAdministratorstktreectrl-2.4.1/aclocal.m40000644000076400010400000000030711460430700016046 0ustar TimAdministrators# # Include the TEA standard macro set # builtin(include,tclconfig/tcl.m4) # # Add here whatever m4 macros you want to define for your package # builtin(include,pkg.m4) builtin(include,winrc.m4) tktreectrl-2.4.1/ChangeLog0000644000076400010400000001504011470327374015775 0ustar TimAdministrators2009-08-20 Jeff Hobbs * Makefile.in (pkgIndex.tcl): $-safe pwd handling. AS bug 84046 2008-02-27 Jeff Hobbs * generic/tkTreeTheme.c: use Get|SetWindowLongPtr to work with Win64. Requires latest Windows headers. 2008-02-23 Jeff Hobbs * generic/tkTreeTheme.c (DllMain): get module at dll load time to avoid GetModuleHandleEx call. 2008-02-22 Jeff Hobbs * demos/demo.tcl, doc/What's New in TkTreeCtrl.html: * doc/treectrl.html, doc/treectrl.man, doc/treectrl.n * shellicon/configure, shellicon/configure.ac: * configure, configure.ac: bump version to 2.2.5 * winrc.m4: correct RC_DEPARG definition for !gcc case. * generic/tkTreeNotify.c (Percents_ItemDelete, ExpandItemList) (Percents_ItemVisibility, Percents_Selection): remove TclFormatInt * generic/qebind.c (QE_ExpandNumber): references and add ExpandItemList to simplify item list expansion. Corrects crash with 8.4-built treectrl used in 8.5. 2007-05-10 Jeff Hobbs * generic/tkTreeUtils.c (Tree_FillRegion): disable OS X specific code as Tk improvements have made it unnecessary, and it actually made it act funny in 8.5. 2007-01-26 Jeff Hobbs * generic/tkTreeCtrl.h (vsnprintf): _vsnprintf on Windows. 2006-08-15 Jeff Hobbs * library/filelist-bindings.tcl (::TreeCtrl::EditClose): rewrote bindings of edit widget helpers to use TreeCtrlEntry and TreeCtrlText classes. Fix for binding possibly triggering . * generic/tkTreeDisplay.c (Tree_Display): Allow Tree_DeselectHidden * generic/tkTreeItem.c (Item_Configure): to be deferred to next * generic/tkTreeCtrl.h: redraw by calling Tree_DInfoChanged(tree, DINFO_REDO_SELECTION). Significantly improves performance of multiple item visibility changes. 2006-08-14 Jeff Hobbs * generic/tkTreeItem.c (Item_Configure): on checking for -visible, verify that the value actually changed, because it can be expensive. 2006-08-04 Jeff Hobbs * generic/tkTreeCtrl.c (TreeWidgetCmd): set the tk caret when the active item changes. 2006-04-05 Jeff Hobbs * generic/tkTreeCtrl.c (LoupeCmd): correct loupe on OS X x86. * configure, configure.ac: add AC_C_BIGENDIAN check * tclconfig/tcl.m4: TEA rcs 1.91 2006/03/28 21:07:09 2006-01-25 Jeff Hobbs * configure, configure.ac: update to TEA 3.5 * tclconfig/tcl.m4: TEA rcs 1.89 2006/01/25 21:25:02 2005-12-02 Jeff Hobbs * tclconfig/tcl.m4, configure.ac, configure: update to TEA 3.4 2005-09-27 Jeff Hobbs * generic/tkTreeCtrl.c (LoupeCmd): don't capture display (it causes flashing) on OS X. 2005-09-26 Jeff Hobbs * generic/tkTreeCtrl.c (LoupeCmd): add OS X support. Correct Win32 code to use grab size constraints and honor the virtual system metrics (OS X needs similar correction still). Hide cursor on OS X and capture display while grabbing. 2005-09-25 Jeff Hobbs * demos/demo.tcl: just check for 'loupe' to run loupe demo * generic/tkTreeCtrl.c (LoupeCmd): add Win32 code to enable loupe functionality on Windows. 2005-08-22 Jeff Hobbs * Makefile.in: install man pages with html docs * configure, configure.ac, tclconfig/tcl.m4: updated to newer TEA system 2005-08-09 Jeff Hobbs * generic/tkTreeStyle.c (Style_DoLayout): use if instead of tertiary ?: operator for funcs with different return types. *** other mods by Tim Baker (treectrl) to this point *** 2005-05-02 Jeff Hobbs * generic/tkTreeTheme.c: correct headers to build on unix and use of c++-style var decls. 2005-03-25 Jeff Hobbs * Makefile.in, generic/tkTreeCtrl.h: OS X patch from * configure, configure.ac, tclconfig/tcl.m4: Steffen * license.terms (new): 2005-03-18 Jeff Hobbs * Makefile.in (AR): use @AR@ * configure, configure.ac, tclconfig/tcl.m4: TEA 3.2 update 2005-02-14 Jeff Hobbs * demos/demo.tcl: try loading treectrl before trying the IsDevelopment branch of loading. * generic/tkTreeItem.c (CompareAscii, CompareDict): handle the case where no text value has been set for sorting *** other mods by Tim Baker (treectrl) to this point *** 2004-11-30 Jeff Hobbs * generic/tkTreeItem.c (TreeItem_FromObj): s/MOD_/TMOD_ to prevent existing defined name conflict * generic/tkTreeElem.c: add "Elem" to a few names to prevent name collision (notable CreateBitmap on Windows). 2004-11-29 Jeff Hobbs * generic/tkTreeItem.c, generic/tkTreeElem.c: whitespace police * generic/tkTreeCtrl.c: adapt to Tk_PhotoPut(Zoomed)Block API changes for 8.5 (TIP #116). 2004-10-09 Jeff Hobbs * Makefile.in: Revamp build system to use TEA 3.1 setup. * configure: * configure.ac: * tclconfig/tcl.m4: * pkgIndex.tcl.in: Automate creation of pkgIndex.tcl and use * demos/demo.tcl: tcl_findLibrary to avoid the issue of build vs. * tests/all.tcl: install package. * generic/tkTreeCtrl.c: * generic/tkTreeDisplay.c: correctly handle the damageRgn var. * generic/tkTreeUtils.c: Implement Tk_OffsetRegion as XOffsetRegion on unix. (werner) * library/filelist-bindings.tcl: ensure TreeCtrl namespace exists * library/treectrl.tcl: source filelist-bindings *** Tim Baker (treectrl) made numerous changes for 1.1 *** 2004-02-09 Jeff Hobbs * generic/tkTreeCtrl.c (ImageChangedProc): cause image change to * generic/tkTreeColumn.c (ImageChangedProc): refresh window. Could narrow down the full update, but better than nothing. 2003-12-02 Jeff Hobbs * library/filelist-bindings.tcl: whitespace police added check for Priv(buttonMode) before use in bindings that may not get an associated button-down event * library/treectrl.tcl: whitespace police 2003-11-26 Jeff Hobbs * generic/tkTreeCtrl.c (LoupeCmd): remove extra interp arg to Tk_PhotoPutZoomedBlock. 2003-11-25 Jeff Hobbs * generic/tkTreeColumn.c: whitespace police * generic/tkTreeCtrl.h: * generic/tkTreeCtrl.c: whitespace police (TreeWorldChanged): add calls to TreeStyle_TreeChanged and TreeColumn_TreeChanged to correctly display font size changes * ChangeLog: created tktreectrl-2.4.1/configure0000755000076400010400000113354211646360600016135 0ustar TimAdministrators#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.67 for treectrl 2.4. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='treectrl' PACKAGE_TARNAME='treectrl' PACKAGE_VERSION='2.4' PACKAGE_STRING='treectrl 2.4' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" enable_option_checking=no ac_subst_vars='LTLIBOBJS LIBOBJS WISH_PROG TCLSH_PROG VC_MANIFEST_EMBED_EXE VC_MANIFEST_EMBED_DLL RANLIB_STUB MAKE_STUB_LIB MAKE_STATIC_LIB MAKE_SHARED_LIB MAKE_LIB TCL_DBGX LDFLAGS_DEFAULT CFLAGS_DEFAULT DIST_WIN_MACHINE LD_LIBRARY_PATH_VAR SHLIB_CFLAGS SHLIB_LD_LIBS SHLIB_LD STLIB_LD CC_OBJNAME CFLAGS_WARNING CFLAGS_OPTIMIZE CFLAGS_DEBUG CELIB_DIR AR SHARED_BUILD DIST_WIN_THREADS TCL_THREADS GTK_LIBS GTK_CFLAGS PKG_CONFIG PKG_MANIFEST MACHINE RES RC_DEPARG RC_DEFINE RC_INCLUDE RC_TYPE RC_OUT RC subdirs XMKMF TK_XLIB_DIR_NATIVE TK_TOP_DIR_NATIVE TK_INCLUDES TCL_TOP_DIR_NATIVE TCL_INCLUDES PKG_OBJECTS PKG_SOURCES MATH_LIBS EGREP GREP RANLIB SET_MAKE INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM CPP OBJEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC TK_XINCLUDES TK_LIBS TK_STUB_LIB_SPEC TK_STUB_LIB_FLAG TK_STUB_LIB_FILE TK_LIB_SPEC TK_LIB_FLAG TK_LIB_FILE TK_SRC_DIR TK_BIN_DIR TK_VERSION TCL_SHLIB_LD_LIBS TCL_LD_FLAGS TCL_EXTRA_CFLAGS TCL_DEFS TCL_LIBS CLEANFILES TCL_STUB_LIB_SPEC TCL_STUB_LIB_FLAG TCL_STUB_LIB_FILE TCL_LIB_SPEC TCL_LIB_FLAG TCL_LIB_FILE TCL_SRC_DIR TCL_BIN_DIR TCL_PATCH_LEVEL TCL_VERSION PKG_CFLAGS PKG_LIBS PKG_INCLUDES PKG_HEADERS PKG_TCL_SOURCES PKG_STUB_OBJECTS PKG_STUB_SOURCES PKG_STUB_LIB_FILE PKG_LIB_FILE EXEEXT CYGPATH PACKAGE_PATCHLEVEL target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_tcl with_tk with_tclinclude with_tkinclude with_x enable_shellicon enable_gtk enable_threads enable_shared enable_64bit enable_64bit_vis enable_rpath enable_wince with_celib enable_symbols ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP XMKMF PKG_CONFIG GTK_CFLAGS GTK_LIBS' ac_subdirs_all='shellicon' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures treectrl 2.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/treectrl] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of treectrl 2.4:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-shellicon build the shellicon extension (default: no) --enable-gtk build GTK+ theme-aware treectrl (default: no) --enable-threads build with threads --enable-shared build and link with shared libraries (default: on) --enable-64bit enable 64bit support (default: off) --enable-64bit-vis enable 64bit Sparc VIS support (default: off) --disable-rpath disable rpath support (default: on) --enable-wince enable Win/CE support (where applicable) --enable-symbols build with debugging symbols (default: off) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-tcl directory containing tcl configuration (tclConfig.sh) --with-tk directory containing tk configuration (tkConfig.sh) --with-tclinclude directory containing the public Tcl header files --with-tkinclude directory containing the public Tk header files --with-x use the X Window System --with-celib=DIR use Windows/CE support library from DIR Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor XMKMF Path to xmkmf, Makefile generator for X Window System PKG_CONFIG path to pkg-config utility GTK_CFLAGS C compiler flags for GTK, overriding pkg-config GTK_LIBS linker flags for GTK, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF treectrl configure 2.4 generated by GNU Autoconf 2.67 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval "test \"\${$3+set}\"" = set; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_type cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by treectrl $as_me 2.4, which was generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5 ; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu PACKAGE_PATCHLEVEL=2.4.1 cat >>confdefs.h <<_ACEOF #define PACKAGE_PATCHLEVEL "$PACKAGE_PATCHLEVEL" _ACEOF # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.9" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for correct TEA configuration" >&5 $as_echo_n "checking for correct TEA configuration... " >&6; } if test x"${PACKAGE_NAME}" = x ; then as_fn_error $? " The PACKAGE_NAME variable must be defined by your TEA configure.in" "$LINENO" 5 fi if test x"3.9" = x ; then as_fn_error $? " TEA version not specified." "$LINENO" 5 elif test "3.9" != "${TEA_VERSION}" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: warning: requested TEA version \"3.9\", have \"${TEA_VERSION}\"" >&5 $as_echo "warning: requested TEA version \"3.9\", have \"${TEA_VERSION}\"" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5 $as_echo "ok (TEA ${TEA_VERSION})" >&6; } fi compile_for_windows="no" if test x"${host_alias}" != x ; then case $host_alias in *mingw32*) compile_for_windows="yes" esac fi case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) compile_for_windows="yes" ;; esac if test $compile_for_windows = yes ; then # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CYGPATH+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CYGPATH"; then ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CYGPATH="cygpath -w" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" fi fi CYGPATH=$ac_cv_prog_CYGPATH if test -n "$CYGPATH"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5 $as_echo "$CYGPATH" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi EXEEXT=".exe" TEA_PLATFORM="windows" else CYGPATH=echo EXEEXT="" TEA_PLATFORM="unix" fi # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi { $as_echo "$as_me:${as_lineno-$LINENO}: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&5 $as_echo "$as_me: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&6;} # This package name must be replaced statically for AC_SUBST to work # Substitute STUB_LIB_FILE in case package creates a stub library too. # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... ac_aux_dir= for ac_dir in tclconfig "$srcdir"/tclconfig; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in tclconfig \"$srcdir\"/tclconfig" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true # Check whether --with-tcl was given. if test "${with_tcl+set}" = set; then : withval=$with_tcl; with_tclconfig="${withval}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5 $as_echo_n "checking for Tcl configuration... " >&6; } if test "${ac_cv_c_tclconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&5 $as_echo "$as_me: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&2;} with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5 fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi fi if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" as_fn_error $? "Can't find Tcl configuration definitions" "$LINENO" 5 else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${TCL_BIN_DIR}/tclConfig.sh" >&5 $as_echo "found ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of ${TCL_BIN_DIR}/tclConfig.sh" >&5 $as_echo_n "checking for existence of ${TCL_BIN_DIR}/tclConfig.sh... " >&6; } if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 $as_echo "loading" >&6; } . "${TCL_BIN_DIR}/tclConfig.sh" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5 $as_echo "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" case "`uname -s`" in *CYGWIN_*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cygwin variant" >&5 $as_echo_n "checking for cygwin variant... " >&6; } case ${TCL_EXTRA_CFLAGS} in *-mwin32*|*-mno-cygwin*) TEA_PLATFORM="windows" CFLAGS="$CFLAGS -mwin32" { $as_echo "$as_me:${as_lineno-$LINENO}: result: win32" >&5 $as_echo "win32" >&6; } ;; *) TEA_PLATFORM="unix" { $as_echo "$as_me:${as_lineno-$LINENO}: result: unix" >&5 $as_echo "unix" >&6; } ;; esac EXEEXT=".exe" ;; *) ;; esac # The BUILD_$pkg is to define the correct extern storage class # handling when making this package cat >>confdefs.h <<_ACEOF #define BUILD_${PACKAGE_NAME} /**/ _ACEOF # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp *.ilk vc*.pch" fi # TEA specific: #-------------------------------------------------------------------- # Load the tkConfig.sh file if necessary (Tk extension) #-------------------------------------------------------------------- # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true # Check whether --with-tk was given. if test "${with_tk+set}" = set; then : withval=$with_tk; with_tkconfig="${withval}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk configuration" >&5 $as_echo_n "checking for Tk configuration... " >&6; } if test "${ac_cv_c_tkconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself" >&5 $as_echo "$as_me: WARNING: --with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself" >&2;} with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else as_fn_error $? "${with_tkconfig} directory doesn't contain tkConfig.sh" "$LINENO" 5 fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../tk[8-9].[0-9]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../tk[8-9].[0-9]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../../tk[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi fi if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" as_fn_error $? "Can't find Tk configuration definitions" "$LINENO" 5 else no_tk= TK_BIN_DIR="${ac_cv_c_tkconfig}" { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${TK_BIN_DIR}/tkConfig.sh" >&5 $as_echo "found ${TK_BIN_DIR}/tkConfig.sh" >&6; } fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of ${TK_BIN_DIR}/tkConfig.sh" >&5 $as_echo_n "checking for existence of ${TK_BIN_DIR}/tkConfig.sh... " >&6; } if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 $as_echo "loading" >&6; } . "${TK_BIN_DIR}/tkConfig.sh" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find ${TK_BIN_DIR}/tkConfig.sh" >&5 $as_echo "could not find ${TK_BIN_DIR}/tkConfig.sh" >&6; } fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd "${TK_BIN_DIR}"; pwd`" \ "`cd "${TK_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) $as_echo "#define MAC_OSX_TK 1" >>confdefs.h TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi # TEA specific: #----------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&5 $as_echo "$as_me: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&6;} prefix=${TCL_PREFIX} else { $as_echo "$as_me:${as_lineno-$LINENO}: --prefix defaulting to /usr/local" >&5 $as_echo "$as_me: --prefix defaulting to /usr/local" >&6;} prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&5 $as_echo "$as_me: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&6;} exec_prefix=${TCL_EXEC_PREFIX} else { $as_echo "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to ${prefix}" >&5 $as_echo "$as_me: --exec-prefix defaulting to ${prefix}" >&6;} exec_prefix=$prefix fi fi #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5 ; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5 ; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5 ; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5 ; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- if test -n "$ac_tool_prefix"; then # 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler understands -pipe" >&5 $as_echo_n "checking if the compiler understands -pipe... " >&6; } if test "${tcl_cv_cc_pipe+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_cc_pipe=yes else tcl_cv_cc_pipe=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_pipe" >&5 $as_echo "$tcl_cv_cc_pipe" >&6; } if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if test "${ac_cv_c_bigendian+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac if test "${TEA_PLATFORM}" = "unix" ; then #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- ac_fn_c_check_func "$LINENO" "sin" "ac_cv_func_sin" if test "x$ac_cv_func_sin" = x""yes; then : MATH_LIBS="" else MATH_LIBS="-lm" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lieee" >&5 $as_echo_n "checking for main in -lieee... " >&6; } if test "${ac_cv_lib_ieee_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lieee $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ieee_main=yes else ac_cv_lib_ieee_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee_main" >&5 $as_echo "$ac_cv_lib_ieee_main" >&6; } if test "x$ac_cv_lib_ieee_main" = x""yes; then : MATH_LIBS="-lieee $MATH_LIBS" fi #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -linet" >&5 $as_echo_n "checking for main in -linet... " >&6; } if test "${ac_cv_lib_inet_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_inet_main=yes else ac_cv_lib_inet_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5 $as_echo "$ac_cv_lib_inet_main" >&6; } if test "x$ac_cv_lib_inet_main" = x""yes; then : LIBS="$LIBS -linet" fi ac_fn_c_check_header_mongrel "$LINENO" "net/errno.h" "ac_cv_header_net_errno_h" "$ac_includes_default" if test "x$ac_cv_header_net_errno_h" = x""yes; then : $as_echo "#define HAVE_NET_ERRNO_H 1" >>confdefs.h fi #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = x""yes; then : tcl_checkSocket=0 else tcl_checkSocket=1 fi if test "$tcl_checkSocket" = 1; then ac_fn_c_check_func "$LINENO" "setsockopt" "ac_cv_func_setsockopt" if test "x$ac_cv_func_setsockopt" = x""yes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5 $as_echo_n "checking for setsockopt in -lsocket... " >&6; } if test "${ac_cv_lib_socket_setsockopt+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char setsockopt (); int main () { return setsockopt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_setsockopt=yes else ac_cv_lib_socket_setsockopt=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5 $as_echo "$ac_cv_lib_socket_setsockopt" >&6; } if test "x$ac_cv_lib_socket_setsockopt" = x""yes; then : LIBS="$LIBS -lsocket" else tcl_checkBoth=1 fi fi fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" ac_fn_c_check_func "$LINENO" "accept" "ac_cv_func_accept" if test "x$ac_cv_func_accept" = x""yes; then : tcl_checkNsl=0 else LIBS=$tk_oldLibs fi fi ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = x""yes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then : LIBS="$LIBS -lnsl" fi fi # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking dirent.h" >&5 $as_echo_n "checking dirent.h... " >&6; } if test "${tcl_cv_dirent_h+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_dirent_h=yes else tcl_cv_dirent_h=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_dirent_h" >&5 $as_echo "$tcl_cv_dirent_h" >&6; } if test $tcl_cv_dirent_h = no; then $as_echo "#define NO_DIRENT_H 1" >>confdefs.h fi # TEA specific: ac_fn_c_check_header_mongrel "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default" if test "x$ac_cv_header_errno_h" = x""yes; then : else $as_echo "#define NO_ERRNO_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "float.h" "ac_cv_header_float_h" "$ac_includes_default" if test "x$ac_cv_header_float_h" = x""yes; then : else $as_echo "#define NO_FLOAT_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "values.h" "ac_cv_header_values_h" "$ac_includes_default" if test "x$ac_cv_header_values_h" = x""yes; then : else $as_echo "#define NO_VALUES_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" if test "x$ac_cv_header_limits_h" = x""yes; then : $as_echo "#define HAVE_LIMITS_H 1" >>confdefs.h else $as_echo "#define NO_LIMITS_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = x""yes; then : tcl_ok=1 else tcl_ok=0 fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtol" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtoul" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtod" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* if test $tcl_ok = 0; then $as_echo "#define NO_STDLIB_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = x""yes; then : tcl_ok=1 else tcl_ok=0 fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strstr" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strerror" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then $as_echo "#define NO_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default" if test "x$ac_cv_header_sys_wait_h" = x""yes; then : else $as_echo "#define NO_SYS_WAIT_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = x""yes; then : else $as_echo "#define NO_DLFCN_H 1" >>confdefs.h fi # OS/390 lacks sys/param.h (and doesn't need it, by chance). for ac_header in sys/param.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_PARAM_H 1 _ACEOF fi done # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- vars="qebind.c tkTreeColumn.c tkTreeCtrl.c tkTreeDisplay.c tkTreeDrag.c tkTreeElem.c tkTreeHeader.c tkTreeItem.c tkTreeMarquee.c tkTreeNotify.c tkTreeStyle.c tkTreeTheme.c tkTreeUtils.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then as_fn_error $? "could not find header file '${srcdir}/$i'" "$LINENO" 5 fi PKG_HEADERS="$PKG_HEADERS $i" done vars="-I. -I\"`${CYGPATH} ${srcdir}/generic`\"" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done PKG_CFLAGS="$PKG_CFLAGS " vars="" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find stub source file '$i'" "$LINENO" 5 fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done vars="library/treectrl.tcl library/filelist-bindings.tcl" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then as_fn_error $? "could not find tcl source file '${srcdir}/$i'" "$LINENO" 5 fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG #-------------------------------------------------------------------- #TEA_PUBLIC_TCL_HEADERS { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl public headers" >&5 $as_echo_n "checking for Tcl public headers... " >&6; } # Check whether --with-tclinclude was given. if test "${with_tclinclude+set}" = set; then : withval=$with_tclinclude; with_tclinclude=${withval} fi if test "${ac_cv_c_tclh+set}" = set; then : $as_echo_n "(cached) " >&6 else # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else as_fn_error $? "${with_tclinclude} directory does not contain tcl.h" "$LINENO" 5 fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi fi # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then as_fn_error $? "tcl.h not found. Please specify its location with --with-tclinclude" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tclh}" >&5 $as_echo "${ac_cv_c_tclh}" >&6; } fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl private include files" >&5 $as_echo_n "checking for Tcl private include files... " >&6; } TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then as_fn_error $? "Cannot find private header tclInt.h in ${TCL_SRC_DIR}" "$LINENO" 5 fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${result}" >&5 $as_echo "${result}" >&6; } #TEA_PUBLIC_TK_HEADERS { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk public headers" >&5 $as_echo_n "checking for Tk public headers... " >&6; } # Check whether --with-tkinclude was given. if test "${with_tkinclude+set}" = set; then : withval=$with_tkinclude; with_tkinclude=${withval} fi if test "${ac_cv_c_tkh+set}" = set; then : $as_echo_n "(cached) " >&6 else # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else as_fn_error $? "${with_tkinclude} directory does not contain tk.h" "$LINENO" 5 fi else list="" if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TK_INCLUDE_SPEC}" != x ; then d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi fi # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then as_fn_error $? "tk.h not found. Please specify its location with --with-tkinclude" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tkh}" >&5 $as_echo "${ac_cv_c_tkh}" >&6; } fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 header files" >&5 $as_echo_n "checking for X11 header files... " >&6; } if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${INCLUDE_DIR_NATIVE}" >&5 $as_echo "${INCLUDE_DIR_NATIVE}" >&6; } fi # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk private include files" >&5 $as_echo_n "checking for Tk private include files... " >&6; } TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I${TK_XLIB_DIR_NATIVE}" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then as_fn_error $? "Cannot find private header tkInt.h in ${TK_SRC_DIR}" "$LINENO" 5 fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${result}" >&5 $as_echo "${result}" >&6; } #-------------------------------------------------------------------- # For Unix/Tk builds, make sure that the X libraries/headers are found. #-------------------------------------------------------------------- if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5 ;; #( *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.i conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else not_really_there="yes" fi rm -f conftest.err conftest.i conftest.$ac_ext else if test ! -r $x_includes/X11/Intrinsic.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 header files" >&5 $as_echo_n "checking for X11 header files... " >&6; } found_xincludes="no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : found_xincludes="yes" else found_xincludes="no" fi rm -f conftest.err conftest.i conftest.$ac_ext if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Intrinsic.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $i" >&5 $as_echo "$i" >&6; } XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test "$found_xincludes" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: couldn't find any!" >&5 $as_echo "couldn't find any!" >&6; } fi if test "$no_x" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 libraries" >&5 $as_echo_n "checking for X11 libraries... " >&6; } XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $i" >&5 $as_echo "$i" >&6; } XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XCreateWindow in -lXwindow" >&5 $as_echo_n "checking for XCreateWindow in -lXwindow... " >&6; } if test "${ac_cv_lib_Xwindow_XCreateWindow+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXwindow $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XCreateWindow (); int main () { return XCreateWindow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xwindow_XCreateWindow=yes else ac_cv_lib_Xwindow_XCreateWindow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xwindow_XCreateWindow" >&5 $as_echo "$ac_cv_lib_Xwindow_XCreateWindow" >&6; } if test "x$ac_cv_lib_Xwindow_XCreateWindow" = x""yes; then : XLIBSW=-lXwindow fi fi if test "$XLIBSW" = nope ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find any! Using -lX11." >&5 $as_echo "could not find any! Using -lX11." >&6; } XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi fi # Needed for OS X ppx/intel image handling { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if test "${ac_cv_c_bigendian+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac if test "$GCC" = yes; then : # Needed for pointer-to-int conversions with GCC on 64-bit ac_fn_c_check_type "$LINENO" "intptr_t" "ac_cv_type_intptr_t" "$ac_includes_default" if test "x$ac_cv_type_intptr_t" = x""yes; then : $as_echo "#define HAVE_INTPTR_T 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pointer-size signed integer type" >&5 $as_echo_n "checking for pointer-size signed integer type... " >&6; } if test "${tcl_cv_intptr_t+set}" = set; then : $as_echo_n "(cached) " >&6 else for tcl_cv_intptr_t in "int" "long" "long long" none; do if test "$tcl_cv_intptr_t" != none; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !(sizeof (void *) <= sizeof ($tcl_cv_intptr_t))]; test_array [0] = 0 ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_ok=yes else tcl_ok=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$tcl_ok" = yes && break; fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_intptr_t" >&5 $as_echo "$tcl_cv_intptr_t" >&6; } if test "$tcl_cv_intptr_t" != none; then cat >>confdefs.h <<_ACEOF #define intptr_t $tcl_cv_intptr_t _ACEOF fi fi fi #-------------------------------------------------------------------- # __CHANGE__ # A few miscellaneous platform-specific items: # # Define a special symbol for Windows (BUILD_sample in this case) so # that we create the export library with the dll. See sha1.h on how # to use this. # # Windows creates a few extra files that need to be cleaned up. # You can add more files to clean if your extension creates any extra # files. # # Define any extra compiler flags in the PACKAGE_CFLAGS variable. # These will be appended to the current set of compiler flags for # your system. #-------------------------------------------------------------------- OUTPUTFILES=Makefile if test "${TEA_PLATFORM}" = "windows" ; then vars="tkWinTree.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="gdi32.lib user32.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done # Check whether --enable-shellicon was given. if test "${enable_shellicon+set}" = set; then : enableval=$enable_shellicon; tcl_ok=$enableval else tcl_ok=no fi if test "$tcl_ok" = "yes" ; then subdirs="$subdirs shellicon" fi # Find rc.exe or windres.exe. # Defined in winrc.m4. # AC_MSG_CHECKING([for windows resource compiler]) RC_DEPARG='"$<"' if test "${GCC}" = "yes" ; then # Extract the first word of "windres", so it can be a program name with args. set dummy windres; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_RC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RC"; then ac_cv_prog_RC="$RC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RC="windres" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RC=$ac_cv_prog_RC if test -n "$RC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RC" >&5 $as_echo "$RC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "${RC}" = "" ; then as_fn_error $? "Required resource tool 'windres' not found on PATH." "$LINENO" 5 fi RC_OUT=-o RC_TYPE= RC_INCLUDE=--include RC_DEFINE=--define RES=res.o # Check for a bug in gcc's windres that causes the # compile to fail when a Windows native path is # passed into windres. The mingw toolchain requires # Windows native paths while Cygwin should work # with both. Avoid the bug by passing a POSIX # path when using the Cygwin toolchain. if test "$ac_cv_cygwin" != "yes" -a "$CYGPATH" != "echo" ; then conftest=/tmp/conftest.rc echo "STRINGTABLE BEGIN" > $conftest echo "101 \"name\"" >> $conftest echo "END" >> $conftest { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Windows native path bug in windres" >&5 $as_echo_n "checking for Windows native path bug in windres... " >&6; } cyg_conftest=`$CYGPATH $conftest` if { ac_try='$RC -o conftest.res.o $cyg_conftest' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 (eval $ac_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } RC_DEPARG='"$(shell $(CYGPATH) $<)"' else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi conftest= cyg_conftest= fi else if test "$do64bit" != "no" ; then RC="\"${MSSDK}/bin/rc.exe\"" elif test "$doWince" != "no" ; then RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" else RC="rc" fi RC_OUT=-fo RC_TYPE=-r RC_INCLUDE=-i RC_DEFINE=-d RES=res fi # X86|AMD64|IA64 for manifest # PKG_MANIFEST -> VC_MANIFEST_EMBED_DLL -> MAKE_SHARED_LIB vars="treectrl.dll.manifest" for i in $vars; do # Check for existence of .manifest.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/$i.in"; then as_fn_error $? "could not find manifest file '${srcdir}/$i'" "$LINENO" 5 fi PKG_MANIFEST="$PKG_MANIFEST $i" # If package .manifest is provided, don't clean it # If package .manifest is generated by Makefile, clean it # If package .manifest is generated by configure, distclean it #TEA_ADD_CLEANFILES([$i]) done # Create treectrl.dll.manifest from treectrl.dll.manifest.in. # treectrl.dll.manifest is included by treectrl.rc. # If building with a Microsoft compiler that generates # treectrlNN.dll.manifest (to pick the correct MSVCRT runtime) then # that manifest is merged with mine using mt.exe (see the Makefile # rule for PKG_LIB_FILE). OUTPUTFILES="Makefile treectrl.dll.manifest" vars="treectrl.rc" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then as_fn_error $? "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${RES}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${RES}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${RES}" fi PKG_OBJECTS="$PKG_OBJECTS $j" CLEANFILES="$CLEANFILES $j" ;; esac done fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use Cocoa or Carbon" >&5 $as_echo_n "checking whether to use Cocoa or Carbon... " >&6; } case ${TK_LIBS} in *Cocoa*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Cocoa" >&5 $as_echo "Cocoa" >&6; } PKG_CFLAGS="$PKG_CFLAGS -DMAC_TK_COCOA -std=gnu99 -x objective-c -fobjc-gc" vars="tkMacOSXTree.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="-framework Cocoa -framework Carbon" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Carbon" >&5 $as_echo "Carbon" >&6; } PKG_CFLAGS="$PKG_CFLAGS -DMAC_TK_CARBON" vars="tkMacOSXTree.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="-framework Carbon" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done ;; esac fi if test "${TEA_WINDOWINGSYSTEM}" = "x11"; then vars="tkUnixTree.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done # Check whether --enable-gtk was given. if test "${enable_gtk+set}" = set; then : enableval=$enable_gtk; tcl_ok=$enableval else tcl_ok=no fi if test "$tcl_ok" = "yes" ; then if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_PKG_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK" >&5 $as_echo_n "checking for GTK... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$GTK_CFLAGS"; then pkg_cv_GTK_CFLAGS="$GTK_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 gdk-pixbuf-xlib-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0 gdk-pixbuf-xlib-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTK_CFLAGS=`$PKG_CONFIG --cflags "gtk+-2.0 gdk-pixbuf-xlib-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$GTK_LIBS"; then pkg_cv_GTK_LIBS="$GTK_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 gdk-pixbuf-xlib-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0 gdk-pixbuf-xlib-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTK_LIBS=`$PKG_CONFIG --libs "gtk+-2.0 gdk-pixbuf-xlib-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GTK_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtk+-2.0 gdk-pixbuf-xlib-2.0"` else GTK_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtk+-2.0 gdk-pixbuf-xlib-2.0"` fi # Put the nasty error message in config.log where it belongs echo "$GTK_PKG_ERRORS" >&5 as_fn_error $? "Package requirements (gtk+-2.0 gdk-pixbuf-xlib-2.0) were not met: $GTK_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables GTK_CFLAGS and GTK_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables GTK_CFLAGS and GTK_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details" "$LINENO" 5 ; } else GTK_CFLAGS=$pkg_cv_GTK_CFLAGS GTK_LIBS=$pkg_cv_GTK_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : fi PKG_CFLAGS="$PKG_CFLAGS -DTREECTRL_GTK $GTK_CFLAGS" vars="$GTK_LIBS" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done fi vars="${MATH_LIBS}" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done fi #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. #-------------------------------------------------------------------- # Check whether --enable-threads was given. if test "${enable_threads+set}" = set; then : enableval=$enable_threads; tcl_ok=$enableval else tcl_ok=yes fi if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention $as_echo "#define USE_THREAD_ALLOC 1" >>confdefs.h $as_echo "#define _REENTRANT 1" >>confdefs.h if test "`uname -s`" = "SunOS" ; then $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h fi $as_echo "#define _THREAD_SAFE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5 $as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; } if test "${ac_cv_lib_pthread_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_mutex_init=yes else ac_cv_lib_pthread_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_pthread_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5 $as_echo_n "checking for __pthread_mutex_init in -lpthread... " >&6; } if test "${ac_cv_lib_pthread___pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char __pthread_mutex_init (); int main () { return __pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread___pthread_mutex_init=yes else ac_cv_lib_pthread___pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_pthread___pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread___pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5 $as_echo_n "checking for pthread_mutex_init in -lpthreads... " >&6; } if test "${ac_cv_lib_pthreads_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthreads $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthreads_pthread_mutex_init=yes else ac_cv_lib_pthreads_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_pthreads_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthreads_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5 $as_echo_n "checking for pthread_mutex_init in -lc... " >&6; } if test "${ac_cv_lib_c_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_pthread_mutex_init=yes else ac_cv_lib_c_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_c_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_c_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5 $as_echo_n "checking for pthread_mutex_init in -lc_r... " >&6; } if test "${ac_cv_lib_c_r_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_r_pthread_mutex_init=yes else ac_cv_lib_c_r_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_c_r_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_c_r_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&5 $as_echo "$as_me: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&2;} fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output { $as_echo "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5 $as_echo_n "checking for building with threads... " >&6; } if test "${TCL_THREADS}" = 1; then $as_echo "#define TCL_THREADS 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5 $as_echo "yes (default)" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&5 $as_echo "$as_me: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&2;} fi ;; *) if test "${TCL_THREADS}" = "1"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&5 $as_echo "$as_me: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&2;} fi ;; esac if test "${TCL_THREADS}" = "1"; then : DIST_WIN_THREADS=-threads else DIST_WIN_THREADS="" fi #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5 $as_echo_n "checking how to build libraries... " >&6; } # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; tcl_ok=$enableval else tcl_ok=yes fi if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: shared" >&5 $as_echo "shared" >&6; } SHARED_BUILD=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: static" >&5 $as_echo "static" >&6; } SHARED_BUILD=0 $as_echo "#define STATIC_BUILD 1" >>confdefs.h fi #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- # Step 0.a: Enable 64 bit support? { $as_echo "$as_me:${as_lineno-$LINENO}: checking if 64bit support is requested" >&5 $as_echo_n "checking if 64bit support is requested... " >&6; } # Check whether --enable-64bit was given. if test "${enable_64bit+set}" = set; then : enableval=$enable_64bit; do64bit=$enableval else do64bit=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $do64bit" >&5 $as_echo "$do64bit" >&6; } # Step 0.b: Enable Solaris 64 bit VIS support? { $as_echo "$as_me:${as_lineno-$LINENO}: checking if 64bit Sparc VIS support is requested" >&5 $as_echo_n "checking if 64bit Sparc VIS support is requested... " >&6; } # Check whether --enable-64bit-vis was given. if test "${enable_64bit_vis+set}" = set; then : enableval=$enable_64bit_vis; do64bitVIS=$enableval else do64bitVIS=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $do64bitVIS" >&5 $as_echo "$do64bitVIS" >&6; } # Force 64bit on with VIS if test "$do64bitVIS" = "yes"; then : do64bit=yes fi # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports visibility \"hidden\"" >&5 $as_echo_n "checking if compiler supports visibility \"hidden\"... " >&6; } if test "${tcl_cv_cc_visibility_hidden+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {} int main () { f(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_visibility_hidden=yes else tcl_cv_cc_visibility_hidden=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_visibility_hidden" >&5 $as_echo "$tcl_cv_cc_visibility_hidden" >&6; } if test $tcl_cv_cc_visibility_hidden = yes; then : $as_echo "#define MODULE_SCOPE extern __attribute__((__visibility__(\"hidden\")))" >>confdefs.h fi # Step 0.d: Disable -rpath support? { $as_echo "$as_me:${as_lineno-$LINENO}: checking if rpath support is requested" >&5 $as_echo_n "checking if rpath support is requested... " >&6; } # Check whether --enable-rpath was given. if test "${enable_rpath+set}" = set; then : enableval=$enable_rpath; doRpath=$enableval else doRpath=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doRpath" >&5 $as_echo "$doRpath" >&6; } # TEA specific: Cross-compiling options for Windows/CE builds? if test "${TEA_PLATFORM}" = windows; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Windows/CE build is requested" >&5 $as_echo_n "checking if Windows/CE build is requested... " >&6; } # Check whether --enable-wince was given. if test "${enable_wince+set}" = set; then : enableval=$enable_wince; doWince=$enableval else doWince=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doWince" >&5 $as_echo "$doWince" >&6; } fi # Set the variable "system" to hold the name and version number # for the system. { $as_echo "$as_me:${as_lineno-$LINENO}: checking system version" >&5 $as_echo_n "checking system version... " >&6; } if test "${tcl_cv_sys_version+set}" = set; then : $as_echo_n "(cached) " >&6 else # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5 $as_echo "$as_me: WARNING: can't find uname command" >&2;} tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5 $as_echo "$tcl_cv_sys_version" >&6; } system=$tcl_cv_sys_version # Require ranlib early so we can override it in special cases below. # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O if test "$GCC" = yes; then : # TEA specific: CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" else CFLAGS_WARNING="" fi CC_OBJNAME="-o \$@" # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" if test "x$SHLIB_VERSION" = x; then : SHLIB_VERSION="1.0" fi case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test ! -d "${PATH64}" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&5 $as_echo "$as_me: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ensure latest Platform SDK is installed" >&5 $as_echo "$as_me: WARNING: Ensure latest Platform SDK is installed" >&2;} do64bit="no" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using 64-bit $MACHINE mode" >&5 $as_echo " Using 64-bit $MACHINE mode" >&6; } do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then as_fn_error $? "Windows/CE and 64-bit builds incompatible" "$LINENO" 5 fi if test "$GCC" = "yes" ; then as_fn_error $? "Windows/CE and GCC builds incompatible" "$LINENO" 5 fi # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true # Check whether --with-celib was given. if test "${with_celib+set}" = set; then : withval=$with_celib; with_celibconfig=${withval} fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Windows/CE celib directory" >&5 $as_echo_n "checking for Windows/CE celib directory... " >&6; } if test "${ac_cv_c_celibconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else as_fn_error $? "${with_celibconfig} directory doesn't contain inc directory" "$LINENO" 5 fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[0-9]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[0-9]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi fi if test x"${ac_cv_c_celibconfig}" = x ; then as_fn_error $? "Cannot find celib support library directory" "$LINENO" 5 else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: found $CELIB_DIR" >&5 $as_echo "found $CELIB_DIR" >&6; } fi fi # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length($1)) { printf "CEVERSION=\"%s\"\n", $1; \ if ($1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length($2)) { printf "TARGETCPU=\"%s\"\n", toupper($2) }; \ if (length($3)) { printf "ARCH=\"%s\"\n", toupper($3) }; \ if (length($4)) { printf "PLATFORM=\"%s\"\n", $4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then as_fn_error $? "could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" "$LINENO" 5 doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 vars="bufferoverflowU.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower($0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do cat >>confdefs.h <<_ACEOF #define $i 1 _ACEOF done cat >>confdefs.h <<_ACEOF #define _WIN32_WCE $CEVERSION _ACEOF cat >>confdefs.h <<_ACEOF #define UNDER_CE $CEVERSION _ACEOF CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" else RC="rc" lflags="-nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode if test x"${RC}" = x ; then RC="windres" fi CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD="$CC -shared" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" CFLAGS_DEBUG="${CFLAGS_DEBUG} -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE" CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE" CC_OBJNAME="-Fo\$@" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"; then : # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([^ ]*\)/\1_r/'` ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using $CC for compiling with threads" >&5 $as_echo "Using $CC for compiling with threads" >&6; } fi LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes; then : if test "$GCC" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} else do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" fi fi if test "`uname -m`" = ia64; then : # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" if test "$GCC" = yes; then : CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' else CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' else if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared -Wl,-bexpall' else SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" fi SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lbind" >&5 $as_echo_n "checking for inet_ntoa in -lbind... " >&6; } if test "${ac_cv_lib_bind_inet_ntoa+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbind $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_ntoa (); int main () { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bind_inet_ntoa=yes else ac_cv_lib_bind_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bind_inet_ntoa" >&5 $as_echo "$ac_cv_lib_bind_inet_ntoa" >&6; } if test "x$ac_cv_lib_bind_inet_ntoa" = x""yes; then : LIBS="$LIBS -lbind -lsocket" fi ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" EXE_SUFFIX=".exe" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnetwork" >&5 $as_echo_n "checking for inet_ntoa in -lnetwork... " >&6; } if test "${ac_cv_lib_network_inet_ntoa+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnetwork $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_ntoa (); int main () { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_network_inet_ntoa=yes else ac_cv_lib_network_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_inet_ntoa" >&5 $as_echo "$ac_cv_lib_network_inet_ntoa" >&6; } if test "x$ac_cv_lib_network_inet_ntoa" = x""yes; then : LIBS="$LIBS -lnetwork" fi ;; HP-UX-*.11.*) # Use updated header definitions where possible $as_echo "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library if test "`uname -m`" = ia64; then : SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi else SHLIB_SUFFIX=".sl" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if test "${ac_cv_lib_dld_shl_load+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = yes; then : LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else CFLAGS="$CFLAGS -z" # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes"; then : if test "$GCC" = yes; then : case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} ;; esac else do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" fi fi ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = yes; then : CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" else case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" fi ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes; then : if test "$GCC" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported by gcc" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported by gcc" >&2;} else do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" fi fi ;; Linux*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "`uname -m`" = "alpha"; then : CFLAGS="$CFLAGS -mieee" fi if test $do64bit = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -m64 flag" >&5 $as_echo_n "checking if compiler accepts -m64 flag... " >&6; } if test "${tcl_cv_cc_m64+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_m64=yes else tcl_cv_cc_m64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_m64" >&5 $as_echo "$tcl_cv_cc_m64" >&6; } if test $tcl_cv_cc_m64 = yes; then : CFLAGS="$CFLAGS -m64" do64bit_ok=yes fi fi # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. if test x"${USE_COMPAT}" != x; then : CFLAGS="$CFLAGS -fno-inline" fi ;; GNU*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" if test "`uname -m`" = "alpha"; then : CFLAGS="$CFLAGS -mieee" fi ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi ;; OpenBSD-*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF" >&5 $as_echo_n "checking for ELF... " >&6; } if test "${tcl_cv_ld_elf+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __ELF__ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : tcl_cv_ld_elf=yes else tcl_cv_ld_elf=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_elf" >&5 $as_echo "$tcl_cv_ld_elf" >&6; } if test $tcl_cv_ld_elf = yes; then : LDFLAGS=-Wl,-export-dynamic else LDFLAGS="" fi if test "${TCL_THREADS}" = "1"; then : # OpenBSD builds and links with -pthread, never -lpthread. LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" SHLIB_CFLAGS="$SHLIB_CFLAGS -pthread" fi # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*|FreeBSD-[3-4].*) # FreeBSD 3.* and greater have ELF. # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "${TCL_THREADS}" = "1"; then : # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" TCL_SHLIB_LD_EXTRAS="-soname \$@" SHLIB_SUFFIX=".so" LDFLAGS="" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "${TCL_THREADS}" = "1"; then : # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS" fi # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ($i~/^(isysroot|mmacosx-version-min)/) print "-"$i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!($i~/^(isysroot|mmacosx-version-min)/)) print "-"$i}'`" if test $do64bit = yes; then : case `arch` in ppc) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch ppc64 flag" >&5 $as_echo_n "checking if compiler accepts -arch ppc64 flag... " >&6; } if test "${tcl_cv_cc_arch_ppc64+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_arch_ppc64=yes else tcl_cv_cc_arch_ppc64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_ppc64" >&5 $as_echo "$tcl_cv_cc_arch_ppc64" >&6; } if test $tcl_cv_cc_arch_ppc64 = yes; then : CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes fi;; i386) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch x86_64 flag" >&5 $as_echo_n "checking if compiler accepts -arch x86_64 flag... " >&6; } if test "${tcl_cv_cc_arch_x86_64+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_arch_x86_64=yes else tcl_cv_cc_arch_x86_64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_x86_64" >&5 $as_echo "$tcl_cv_cc_arch_x86_64" >&6; } if test $tcl_cv_cc_arch_x86_64 = yes; then : CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes fi;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&5 $as_echo "$as_me: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&2;};; esac else # Check for combined 32-bit and 64-bit fat build if echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '; then : fat_32_64=yes fi fi # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -single_module flag" >&5 $as_echo_n "checking if ld accepts -single_module flag... " >&6; } if test "${tcl_cv_ld_single_module+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_ld_single_module=yes else tcl_cv_ld_single_module=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_single_module" >&5 $as_echo "$tcl_cv_ld_single_module" >&6; } if test $tcl_cv_ld_single_module = yes; then : SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi # TEA specific: link shlib with current and compatiblity version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([0-9]\{1,5\}\)\(\(\.[0-9]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" # Don't use -prebind when building for Mac OS X 10.4 or later only: if test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int($2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4; then : LDFLAGS="$LDFLAGS -prebind" fi LDFLAGS="$LDFLAGS -headerpad_max_install_names" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5 $as_echo_n "checking if ld accepts -search_paths_first flag... " >&6; } if test "${tcl_cv_ld_search_paths_first+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_ld_search_paths_first=yes else tcl_cv_ld_search_paths_first=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_search_paths_first" >&5 $as_echo "$tcl_cv_ld_search_paths_first" >&6; } if test $tcl_cv_ld_search_paths_first = yes; then : LDFLAGS="$LDFLAGS -Wl,-search_paths_first" fi if test "$tcl_cv_cc_visibility_hidden" != yes; then : $as_echo "#define MODULE_SCOPE __private_extern__" >>confdefs.h tcl_cv_cc_visibility_hidden=yes fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. if test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"; then : if test "${TEA_WINDOWINGSYSTEM}" = x11; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit X11" >&5 $as_echo_n "checking for 64-bit X11... " >&6; } if test "${tcl_cv_lib_x11_64+set}" = set; then : $as_echo_n "(cached) " >&6 else for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_lib_x11_64=yes else tcl_cv_lib_x11_64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_x11_64" >&5 $as_echo "$tcl_cv_lib_x11_64" >&6; } fi if test "${TEA_WINDOWINGSYSTEM}" = aqua; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit Tk" >&5 $as_echo_n "checking for 64-bit Tk... " >&6; } if test "${tcl_cv_lib_tk_64+set}" = set; then : $as_echo_n "(cached) " >&6 else for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { Tk_InitStubs(NULL, "", 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_lib_tk_64=yes else tcl_cv_lib_tk_64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_tk_64" >&5 $as_echo "$tcl_cv_lib_tk_64" >&6; } fi # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. if test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no; then : { $as_echo "$as_me:${as_lineno-$LINENO}: Removing 64-bit architectures from compiler & linker flags" >&5 $as_echo "$as_me: Removing 64-bit architectures from compiler & linker flags" >&6;} for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done fi fi ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy $as_echo "#define _OE_SOCKETS 1" >>confdefs.h ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" if test "$SHARED_BUILD" = 1; then : SHLIB_LD='ld -shared -expect_unresolved "*"' else SHLIB_LD='ld -non_shared -expect_unresolved "*"' fi SHLIB_SUFFIX=".so" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = yes; then : CFLAGS="$CFLAGS -mieee" else CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" fi # see pthread_intro(3) for pthread support on osf1, k.furukawa if test "${TCL_THREADS}" = 1; then : CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` if test "$GCC" = yes; then : LIBS="$LIBS -lpthread -lmach -lexc" else CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi fi ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) if test "$GCC" = yes; then : SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" else SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" fi SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[0-6]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. $as_echo "#define _REENTRANT 1" >>confdefs.h $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. $as_echo "#define _REENTRANT 1" >>confdefs.h $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes; then : arch=`isainfo` if test "$arch" = "sparcv9 sparc"; then : if test "$GCC" = yes; then : if test "`${CC} -dumpversion | awk -F. '{print $1}'`" -lt 3; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&2;} else do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" fi else do64bit_ok=yes if test "$do64bitVIS" = yes; then : CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" else CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" fi # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" fi else if test "$arch" = "amd64 i386"; then : if test "$GCC" = yes; then : case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;};; esac else do64bit_ok=yes case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported for $arch" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported for $arch" >&2;} fi fi fi SHLIB_SUFFIX=".so" if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$do64bit_ok" = yes; then : if test "$arch" = "sparcv9 sparc"; then : # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" else if test "$arch" = "amd64 i386"; then : # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" fi fi fi else case $system in SunOS-5.[1-9][0-9]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' fi ;; esac if test "$do64bit" = yes -a "$do64bit_ok" = no; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit support being disabled -- don't know magic for this platform" >&5 $as_echo "$as_me: WARNING: 64bit support being disabled -- don't know magic for this platform" >&2;} fi # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. if test "$GCC" = yes; then : case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$tcl_cv_cc_visibility_hidden" != yes; then : $as_echo "#define MODULE_SCOPE extern" >>confdefs.h $as_echo "#define NO_VIZ /**/" >>confdefs.h fi if test "$SHARED_LIB_SUFFIX" = ""; then : # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' fi if test "$UNSHARED_LIB_SUFFIX" = ""; then : # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' fi # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary { $as_echo "$as_me:${as_lineno-$LINENO}: checking for required early compiler flags" >&5 $as_echo_n "checking for required early compiler flags... " >&6; } tcl_flags="" if test "${tcl_cv_flag__isoc99_source+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__isoc99_source=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _ISOC99_SOURCE 1 #include int main () { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__isoc99_source=yes else tcl_cv_flag__isoc99_source=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__isoc99_source}" = "xyes" ; then $as_echo "#define _ISOC99_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _ISOC99_SOURCE" fi if test "${tcl_cv_flag__largefile64_source+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile64_source=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE64_SOURCE 1 #include int main () { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile64_source=yes else tcl_cv_flag__largefile64_source=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile64_source}" = "xyes" ; then $as_echo "#define _LARGEFILE64_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _LARGEFILE64_SOURCE" fi if test "${tcl_cv_flag__largefile_source64+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *p = (char *)open64; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile_source64=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE64 1 #include int main () { char *p = (char *)open64; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile_source64=yes else tcl_cv_flag__largefile_source64=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then $as_echo "#define _LARGEFILE_SOURCE64 1" >>confdefs.h tcl_flags="$tcl_flags _LARGEFILE_SOURCE64" fi if test "x${tcl_flags}" = "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_flags}" >&5 $as_echo "${tcl_flags}" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit integer type" >&5 $as_echo_n "checking for 64-bit integer type... " >&6; } if test "${tcl_cv_type_64bit+set}" = set; then : $as_echo_n "(cached) " >&6 else tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { __int64 value = (__int64) 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_type_64bit=__int64 else tcl_type_64bit="long long" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { switch (0) { case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; } ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_type_64bit=${tcl_type_64bit} fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "${tcl_cv_type_64bit}" = none ; then $as_echo "#define TCL_WIDE_INT_IS_LONG 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: using long" >&5 $as_echo "using long" >&6; } elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* { $as_echo "$as_me:${as_lineno-$LINENO}: result: using Tcl header defaults" >&5 $as_echo "using Tcl header defaults" >&6; } else cat >>confdefs.h <<_ACEOF #define TCL_WIDE_INT_TYPE ${tcl_cv_type_64bit} _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_cv_type_64bit}" >&5 $as_echo "${tcl_cv_type_64bit}" >&6; } # Now check for auxiliary declarations { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct dirent64" >&5 $as_echo_n "checking for struct dirent64... " >&6; } if test "${tcl_cv_struct_dirent64+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct dirent64 p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_struct_dirent64=yes else tcl_cv_struct_dirent64=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_dirent64" >&5 $as_echo "$tcl_cv_struct_dirent64" >&6; } if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then $as_echo "#define HAVE_STRUCT_DIRENT64 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5 $as_echo_n "checking for struct stat64... " >&6; } if test "${tcl_cv_struct_stat64+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct stat64 p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_struct_stat64=yes else tcl_cv_struct_stat64=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_stat64" >&5 $as_echo "$tcl_cv_struct_stat64" >&6; } if test "x${tcl_cv_struct_stat64}" = "xyes" ; then $as_echo "#define HAVE_STRUCT_STAT64 1" >>confdefs.h fi for ac_func in open64 lseek64 do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for off64_t" >&5 $as_echo_n "checking for off64_t... " >&6; } if test "${tcl_cv_type_off64_t+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { off64_t offset; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_type_off64_t=yes else tcl_cv_type_off64_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then $as_echo "#define HAVE_TYPE_OFF64_T 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test "$MACHINE" = "X86"; then : DIST_WIN_MACHINE=x86 fi if test "$MACHINE" = "AMD64"; then : DIST_WIN_MACHINE=x86_64 fi if test "$MACHINE" = "IA64"; then : DIST_WIN_MACHINE=ia64 fi #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for build with symbols" >&5 $as_echo_n "checking for build with symbols... " >&6; } # Check whether --enable-symbols was given. if test "${enable_symbols+set}" = set; then : enableval=$enable_symbols; tcl_ok=$enableval else tcl_ok=no fi DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (standard debugging)" >&5 $as_echo "yes (standard debugging)" >&6; } fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then $as_echo "#define TCL_MEM_DEBUG 1" >>confdefs.h fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled symbols mem debugging" >&5 $as_echo "enabled symbols mem debugging" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled $tcl_ok debugging" >&5 $as_echo "enabled $tcl_ok debugging" >&6; } fi fi if test "${enable_symbols+set}" = set && test "$enable_symbols" != no; then PKG_CFLAGS="$PKG_CFLAGS -DTREECTRL_DEBUG" fi #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- $as_echo "#define USE_TCL_STUBS 1" >>confdefs.h $as_echo "#define USE_TK_STUBS 1" >>confdefs.h #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\$@ \$(PKG_OBJECTS)" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "manifest needed" >/dev/null 2>&1; then : # Could do a CHECK_PROG for mt, but should always be with MSVC8+ VC_MANIFEST_EMBED_DLL="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest \$(PKG_MANIFEST) -outputresource:\$@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest \$(PKG_MANIFEST) -outputresource:\$@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" # Don't clean .manifest provided by the package (see TEA_ADD_MANIFEST) # or one created by Makefile or configure. Could use the /manifest:filename # linker option to explicitly set the linker-generated filename. eval eval "manifest=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}.manifest" CLEANFILES="$CLEANFILES $manifest" fi rm -f conftest* MAKE_STUB_LIB="\${STLIB_LD} -out:\$@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \$@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi #-------------------------------------------------------------------- # Find tclsh so that we can run pkg_mkIndex to generate the pkgIndex.tcl # file during the install process. Don't run the TCLSH_PROG through # ${CYGPATH} because it's being used directly by make. # Require that we use a tclsh shell version 8.2 or later since earlier # versions have bugs in the pkg_mkIndex routine. # Add WISH as well if this is a Tk extension. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5 $as_echo_n "checking for tclsh... " >&6; } if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${TCLSH_PROG}" >&5 $as_echo "${TCLSH_PROG}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wish" >&5 $as_echo_n "checking for wish... " >&6; } if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${WISH_PROG}" >&5 $as_echo "${WISH_PROG}" >&6; } #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- ac_config_files="$ac_config_files $OUTPUTFILES" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS="" : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by treectrl $as_me 2.4, which was generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ treectrl config.status 2.4 configured by $0, generated by GNU Autoconf 2.67, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "$OUTPUTFILES") CONFIG_FILES="$CONFIG_FILES $OUTPUTFILES" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi # # CONFIG_SUBDIRS section. # if test "$no_recursion" != yes; then # Remove --cache-file, --srcdir, and --disable-option-checking arguments # so they do not pile up. ac_sub_configure_args= ac_prev= eval "set x $ac_configure_args" shift for ac_arg do if test -n "$ac_prev"; then ac_prev= continue fi case $ac_arg in -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ | --c=*) ;; --config-cache | -C) ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ;; --disable-option-checking) ;; *) case $ac_arg in *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_sub_configure_args " '$ac_arg'" ;; esac done # Always prepend --prefix to ensure using the same prefix # in subdir configurations. ac_arg="--prefix=$prefix" case $ac_arg in *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" # Pass --silent if test "$silent" = yes; then ac_sub_configure_args="--silent $ac_sub_configure_args" fi # Always prepend --disable-option-checking to silence warnings, since # different subdirs can have different --enable and --with options. ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" ac_popdir=`pwd` for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue # Do not complain, so a configure script can configure whichever # parts of a large source tree are present. test -d "$srcdir/$ac_dir" || continue ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 $as_echo "$ac_msg" >&6 as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" # Check for guested configure; otherwise get Cygnus style configure. if test -f "$ac_srcdir/configure.gnu"; then ac_sub_configure=$ac_srcdir/configure.gnu elif test -f "$ac_srcdir/configure"; then ac_sub_configure=$ac_srcdir/configure elif test -f "$ac_srcdir/configure.in"; then # This should be Cygnus configure. ac_sub_configure=$ac_aux_dir/configure else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} ac_sub_configure= fi # The recursion is here. if test -n "$ac_sub_configure"; then # Make the cache file name correct relative to the subdirectory. case $cache_file in [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; *) # Relative name. ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 $as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} # The eval makes quoting arguments work. eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 fi cd "$ac_popdir" done fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi tktreectrl-2.4.1/configure.ac0000755000076400010400000002452711646360313016521 0ustar TimAdministrators#!/bin/bash -norc dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tcl installation dnl to configure the system for the local environment. #----------------------------------------------------------------------- # Sample configure.in for Tcl Extensions. # See the TEA sample extension for description of structure and items. #----------------------------------------------------------------------- #----------------------------------------------------------------------- # __CHANGE__ # This very first macro is used to verify that the configure script can # find the sources. The argument to AC_INIT should be a unique filename # for this package, and can be a relative path, such as: # # AC_INIT(generic/tcl.h) #----------------------------------------------------------------------- AC_INIT([treectrl], [2.4]) AC_SUBST([PACKAGE_PATCHLEVEL], [2.4.1]) AC_DEFINE_UNQUOTED(PACKAGE_PATCHLEVEL, "$PACKAGE_PATCHLEVEL") TEA_INIT([3.9]) AC_CONFIG_AUX_DIR(tclconfig) #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- TEA_PATH_TCLCONFIG TEA_LOAD_TCLCONFIG #-------------------------------------------------------------------- # Load the tkConfig.sh file if necessary (Tk extension) #-------------------------------------------------------------------- TEA_PATH_TKCONFIG TEA_LOAD_TKCONFIG #----------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- TEA_PREFIX #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- TEA_SETUP_COMPILER #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- TEA_ADD_SOURCES([qebind.c tkTreeColumn.c tkTreeCtrl.c tkTreeDisplay.c tkTreeDrag.c tkTreeElem.c tkTreeHeader.c tkTreeItem.c tkTreeMarquee.c tkTreeNotify.c tkTreeStyle.c tkTreeTheme.c tkTreeUtils.c]) TEA_ADD_HEADERS([]) TEA_ADD_INCLUDES([-I. -I\"`${CYGPATH} ${srcdir}/generic`\"]) TEA_ADD_CFLAGS([]) TEA_ADD_STUB_SOURCES([]) TEA_ADD_TCL_SOURCES([library/treectrl.tcl library/filelist-bindings.tcl]) #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG #-------------------------------------------------------------------- #TEA_PUBLIC_TCL_HEADERS TEA_PRIVATE_TCL_HEADERS #TEA_PUBLIC_TK_HEADERS TEA_PRIVATE_TK_HEADERS #-------------------------------------------------------------------- # For Unix/Tk builds, make sure that the X libraries/headers are found. #-------------------------------------------------------------------- TEA_PATH_X # Needed for OS X ppx/intel image handling AC_C_BIGENDIAN AS_IF([test "$GCC" = yes], [ # Needed for pointer-to-int conversions with GCC on 64-bit AC_CHECK_TYPE([intptr_t], [ AC_DEFINE([HAVE_INTPTR_T], 1, [Do we have the intptr_t type?])], [ AC_CACHE_CHECK([for pointer-size signed integer type], tcl_cv_intptr_t, [ for tcl_cv_intptr_t in "int" "long" "long long" none; do if test "$tcl_cv_intptr_t" != none; then AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT], [[sizeof (void *) <= sizeof ($tcl_cv_intptr_t)]])], [tcl_ok=yes], [tcl_ok=no]) test "$tcl_ok" = yes && break; fi done]) if test "$tcl_cv_intptr_t" != none; then AC_DEFINE_UNQUOTED([intptr_t], [$tcl_cv_intptr_t], [Signed integer type wide enough to hold a pointer.]) fi ]) ], []) #-------------------------------------------------------------------- # __CHANGE__ # A few miscellaneous platform-specific items: # # Define a special symbol for Windows (BUILD_sample in this case) so # that we create the export library with the dll. See sha1.h on how # to use this. # # Windows creates a few extra files that need to be cleaned up. # You can add more files to clean if your extension creates any extra # files. # # Define any extra compiler flags in the PACKAGE_CFLAGS variable. # These will be appended to the current set of compiler flags for # your system. #-------------------------------------------------------------------- OUTPUTFILES=Makefile if test "${TEA_PLATFORM}" = "windows" ; then TEA_ADD_SOURCES([tkWinTree.c]) TEA_ADD_LIBS([gdi32.lib user32.lib]) AC_ARG_ENABLE(shellicon, AC_HELP_STRING([--enable-shellicon], [build the shellicon extension (default: no)]), [tcl_ok=$enableval], [tcl_ok=no]) if test "$tcl_ok" = "yes" ; then AC_CONFIG_SUBDIRS(shellicon) fi # Find rc.exe or windres.exe. # Defined in winrc.m4. TREECTRL_PROG_RC # X86|AMD64|IA64 for manifest AC_SUBST(MACHINE) # PKG_MANIFEST -> VC_MANIFEST_EMBED_DLL -> MAKE_SHARED_LIB TEA_ADD_MANIFEST([treectrl.dll.manifest]) # Create treectrl.dll.manifest from treectrl.dll.manifest.in. # treectrl.dll.manifest is included by treectrl.rc. # If building with a Microsoft compiler that generates # treectrlNN.dll.manifest (to pick the correct MSVCRT runtime) then # that manifest is merged with mine using mt.exe (see the Makefile # rule for PKG_LIB_FILE). OUTPUTFILES="Makefile treectrl.dll.manifest" TREECTRL_ADD_RC([treectrl.rc]) fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then AC_MSG_CHECKING([whether to use Cocoa or Carbon]) case ${TK_LIBS} in *Cocoa*) AC_MSG_RESULT([Cocoa]) TEA_ADD_CFLAGS([-DMAC_TK_COCOA -std=gnu99 -x objective-c -fobjc-gc]) TEA_ADD_SOURCES([tkMacOSXTree.c]) TEA_ADD_LIBS([-framework Cocoa -framework Carbon]) ;; *) AC_MSG_RESULT([Carbon]) TEA_ADD_CFLAGS([-DMAC_TK_CARBON]) TEA_ADD_SOURCES([tkMacOSXTree.c]) TEA_ADD_LIBS([-framework Carbon]) ;; esac fi if test "${TEA_WINDOWINGSYSTEM}" = "x11"; then TEA_ADD_SOURCES([tkUnixTree.c]) AC_ARG_ENABLE(gtk, AC_HELP_STRING([--enable-gtk], [build GTK+ theme-aware treectrl (default: no)]), [tcl_ok=$enableval], [tcl_ok=no]) if test "$tcl_ok" = "yes" ; then PKG_CHECK_MODULES([GTK], [gtk+-2.0 gdk-pixbuf-xlib-2.0]) TEA_ADD_CFLAGS([-DTREECTRL_GTK $GTK_CFLAGS]) TEA_ADD_LIBS([$GTK_LIBS]) fi TEA_ADD_LIBS([${MATH_LIBS}]) fi #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. #-------------------------------------------------------------------- TEA_ENABLE_THREADS AS_IF([test "${TCL_THREADS}" = "1"], [ DIST_WIN_THREADS=-threads ], [ DIST_WIN_THREADS="" ]) AC_SUBST(DIST_WIN_THREADS) #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- TEA_ENABLE_SHARED #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- TEA_CONFIG_CFLAGS AS_IF([test "$MACHINE" = "X86"], [DIST_WIN_MACHINE=x86]) AS_IF([test "$MACHINE" = "AMD64"], [DIST_WIN_MACHINE=x86_64]) AS_IF([test "$MACHINE" = "IA64"], [DIST_WIN_MACHINE=ia64]) AC_SUBST(DIST_WIN_MACHINE) #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- TEA_ENABLE_SYMBOLS if test "${enable_symbols+set}" = set && test "$enable_symbols" != no; then TEA_ADD_CFLAGS([-DTREECTRL_DEBUG]) fi #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- AC_DEFINE(USE_TCL_STUBS) AC_DEFINE(USE_TK_STUBS) #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- TEA_MAKE_LIB #-------------------------------------------------------------------- # Find tclsh so that we can run pkg_mkIndex to generate the pkgIndex.tcl # file during the install process. Don't run the TCLSH_PROG through # ${CYGPATH} because it's being used directly by make. # Require that we use a tclsh shell version 8.2 or later since earlier # versions have bugs in the pkg_mkIndex routine. # Add WISH as well if this is a Tk extension. #-------------------------------------------------------------------- TEA_PROG_TCLSH TEA_PROG_WISH #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- AC_OUTPUT([$OUTPUTFILES]) tktreectrl-2.4.1/demos/0000755000076400010400000000000011646706164015335 5ustar TimAdministratorstktreectrl-2.4.1/demos/biglist.tcl0000644000076400010400000003240211573563373017501 0ustar TimAdministrators# Copyright (c) 2005-2011 Tim Baker # A nice feature of the element type "window" is the -clip option. set ::clip 1 namespace eval DemoBigList {} proc DemoBigList::Init {T} { variable Priv set Priv(noise) 0 # # Configure the treectrl widget # $T configure -selectmode extended \ -showroot no -showbuttons no -showlines no \ -showrootlines no if {$::clip} { $T configure -xscrollincrement 4 -yscrollincrement 4 } else { # Hide the borders because child windows appear on top of them $T configure -borderwidth 0 -highlightthickness 0 } # # Create columns # $T column create -expand yes -text Item -itembackground {#F7F7F7} -tags colItem $T column create -text "Item ID" -justify center -itembackground {} -tags colID $T column create -text "Parent ID" -justify center -itembackground {} -tags colParent # Specify the column that will display the heirarchy buttons and lines $T configure -treecolumn colItem # # Create elements # set Priv(bg) $::SystemButtonFace set outline gray70 $T item state define openW $T item state define openE $T item state define openWE $T element create eRectTop rect -outline $outline -fill $Priv(bg) \ -outlinewidth 1 -open {wes openWE es openE ws openW} -rx 7 $T element create eRectBottom rect -outline $outline -fill $Priv(bg) \ -outlinewidth 1 -open n -rx 7 # Title $T element create elemBorderTitle border -relief {sunken open raised {}} \ -thickness 1 -filled yes -background $::SystemButtonFace $T element create elemTxtTitle text \ -font [list DemoFontBold] # Citizen $T element create elemTxtItem text $T element create elemTxtName text \ -fill [list blue {}] # Citizen info $T element create elemWindow window if {$::clip} { $T element configure elemWindow -clip yes } # # Create styles using the elements # set S [$T style create styTitle] $T style elements $S {elemBorderTitle elemTxtTitle} $T style layout $S elemTxtTitle -expand news $T style layout $S elemBorderTitle -detach yes -indent no -iexpand xy set S [$T style create styItem] $T style elements $S {eRectTop elemTxtItem elemTxtName} $T style layout $S eRectTop -detach yes -indent no -iexpand xy \ -draw {yes open no {}} -padx {2 0} $T style layout $S elemTxtItem -expand ns $T style layout $S elemTxtName -expand ns -padx {20} set S [$T style create styID] $T style elements $S {eRectTop elemTxtItem} $T style layout $S eRectTop -detach yes -indent yes -iexpand xy -draw {yes open no {}} $T style layout $S elemTxtItem -padx 6 -expand ns set S [$T style create styParent] $T style elements $S {eRectTop elemTxtItem} $T style layout $S eRectTop -detach yes -indent yes -iexpand xy \ -draw {yes open no {}} -padx {0 2} $T style layout $S elemTxtItem -padx 6 -expand ns set S [$T style create styCitizen] $T style elements $S {eRectBottom elemWindow} $T style layout $S eRectBottom -detach yes -indent no -iexpand xy \ -padx 2 -pady {0 1} $T style layout $S elemWindow -pady {0 2} # # Create 10000 items. Each of these items will hold 10 child items. # set index 1 foreach I [$T item create -count 10000 -parent root -button yes -open no \ -height 20 -tags title] { set Priv(titleIndex,$I) $index incr index 10 } # This binding will add child items to an item just before it is expanded. $T notify bind $T { DemoBigList::ExpandBefore %T %I } # In this demo there are 100,000 items that display a window element. # It would take a lot of time and memory to create 100,000 Tk windows # all at once when initializing the demo list. # The solution is to assign item styles only when items are actually # visible to the user onscreen. # # This binding will assign styles to items when they are displayed and # clear the styles when they are no longer displayed. $T notify bind $T { DemoBigList::ItemVisibility %T %v %h } set Priv(freeWindows) {} set Priv(nextWindowId) 0 set Priv(prev) "" GetWindowHeight $T # When the Tile/Ttk theme changes, recalculate the height of styCitizen # windows. if {$::tile} { bind DemoBigList <> { after idle BigListThemeChanged [DemoList] } } bind DemoBigList { if {[lindex [%W identify %x %y] 0] eq "header"} { TreeCtrl::DoubleButton1 %W %x %y } else { DemoBigList::Button1 %W %x %y } break } bind DemoBigList { DemoBigList::Button1 %W %x %y break } bind DemoBigList { DemoBigList::Motion %W %x %y } bind DemoBigListChildWindow { set x [expr {%X - [winfo rootx [DemoList]]}] set y [expr {%Y - [winfo rooty [DemoList]]}] DemoBigList::Motion [DemoList] $x $y } bindtags $T [list $T DemoBigList TreeCtrl [winfo toplevel $T] all] return } # DemoBigList::GetWindowHeight # # Calculate and store the height of one of the windows used to display citizen # information. Since item styles are assigned on-the-fly (see the # BigListItemVisibility procedure) we need to know the height an item would # have if it had the "styCitizen" style assigned so the scrollbars are set # properly. # # Arguments: # T The treectrl widget. proc DemoBigList::GetWindowHeight {T} { variable Priv # Create a new window just to get the requested size. This will be the # value of the item -height option for some items. set w [NewWindow $T root] update idletasks if {$::clip} { set height [winfo reqheight [lindex [winfo children $w] 0]] } else { set height [winfo reqheight $w] } # Add 2 pixels for the border and gap incr height 2 set Priv(windowHeight) $height FreeWindow $T $w return } # DemoBigList::ExpandBefore -- # # Handle the event. If the item already has child items, # then nothing happens. Otherwise 1 or more items are created as children # of the item being expanded. # # Take advantage of the event to create child items # immediately prior to expanding a parent item. # # Arguments: # T The treectrl widget. # I The item whose children are about to be displayed. proc DemoBigList::ExpandBefore {T I} { variable Priv set parent [$T item parent $I] if {[$T item numchildren $I]} return # Title if {[$T item tag expr $I title]} { set index $Priv(titleIndex,$I) set threats {Severe High Elevated Guarded Low} set names1 {Bill John Jack Bob Tim Sam Mary Susan Lilian Jeff Gary Neil Margaret} set names2 {Smith Hobbs Baker Furst Newel Gates Marshal McNoodle Marley} # Add 10 child items to this item. Each item represents 1 citizen. # The styles will be assigned in BigListItemVisibility. foreach I [$T item create -count 10 -parent $I -open no -button yes \ -height 20 -tags citizen] { set name1 [lindex $names1 [expr {int(rand() * [llength $names1])}]] set name2 [lindex $names2 [expr {int(rand() * [llength $names2])}]] set Priv(itemIndex,$I) $index set Priv(name,$I) "$name1 $name2" set Priv(threat,$I) [lindex $threats [expr {int(rand() * 5)}]] incr index } return } # Citizen if {[$T item tag expr $I citizen]} { # Add 1 child item to this item. # The styles will be assigned in BigListItemVisibility. $T item create -parent $I -height $Priv(windowHeight) -tags info } return } # DemoBigList::ItemVisibility -- # # Handle the event. Item styles are assigned or cleared # when item visibility changes. # # Take advantage of the event to update the appearance of # items just before they become visible onscreen. # # Arguments: # T The treectrl widget. # visible List of items that are now visible. # hidden List of items that are no longer visible. proc DemoBigList::ItemVisibility {T visible hidden} { variable Priv # Assign styles and configure elements in each item that is now # visible on screen. foreach I $visible { set parent [$T item parent $I] # Title if {[$T item tag expr $I title]} { set first $Priv(titleIndex,$I) set last [expr {$first + 10 - 1}] set first [format %06d $first] set last [format %06d $last] $T item span $I colItem 3 $T item style set $I colItem styTitle $T item element configure $I \ colItem elemTxtTitle -text "Citizens $first-$last" continue } # Citizen if {[$T item tag expr $I citizen]} { set index $Priv(itemIndex,$I) $T item style set $I colItem styItem colID styID colParent styParent $T item element configure $I \ colItem elemTxtItem -text "Citizen $index" + elemTxtName \ -textvariable ::DemoBigList::Priv(name,$I) , \ colParent elemTxtItem -text $parent , \ colID elemTxtItem -text $I $T item state forcolumn $I colItem openE $T item state forcolumn $I colID openWE $T item state forcolumn $I colParent openW continue } # Citizen info if {[$T item tag expr $I info]} { set w [NewWindow $T $parent] $T item style set $I colItem styCitizen $T item span $I colItem 3 $T item element configure $I colItem \ elemWindow -window $w } } # Clear the styles of each item that is no longer visible on screen. foreach I $hidden { # Citizen info if {[$T item tag expr $I info]} { # Add this window to the list of unused windows set w [$T item element cget $I colItem elemWindow -window] FreeWindow $T $w } $T item style set $I colItem "" colParent "" colID "" } return } proc DemoBigList::NewWindow {T I} { variable Priv # Check the list of unused windows if {[llength $Priv(freeWindows)]} { set w [lindex $Priv(freeWindows) 0] set Priv(freeWindows) [lrange $Priv(freeWindows) 1 end] if {$::clip} { set f $w set w [lindex [winfo children $f] 0] } if {$Priv(noise)} { dbwin "reuse window $w" } # No unused windows exist. Create a new one. } else { set id [incr Priv(nextWindowId)] if {$::clip} { set f [frame $T.clip$id -background blue] set w [frame $f.frame$id -background $Priv(bg)] } else { set w [frame $T.frame$id -background $Priv(bg)] } # Name: label + entry label $w.label1 -text "Name:" -anchor w -background $Priv(bg) $::entryCmd $w.entry1 -width 24 # Threat Level: label + menubutton label $w.label2 -text "Threat Level:" -anchor w -background $Priv(bg) if {$::tile} { ttk::combobox $w.mb2 -values {Severe High Elevated Guarded Low} \ -state readonly -width [string length "Elevated"] } else { menubutton $w.mb2 -indicatoron yes -menu $w.mb2.m \ -width [string length Elevated] -relief raised menu $w.mb2.m -tearoff no foreach label {Severe High Elevated Guarded Low} { $w.mb2.m add radiobutton -label $label \ -value $label \ -command [list $w.mb2 configure -text $label] } } # Button set message \ "After abducting and probing these people over the last\n\ 50 years, the only thing we've learned for certain is that\n\ one in ten just doesn't seem to mind." if {$::thisPlatform ne "windows"} { set message [string map {\n ""} $message] } $::buttonCmd $w.b3 -text "Anal Probe Wizard..." -command [list tk_messageBox \ -parent . -message $message -title "Anal Probe 2.0"] grid $w.label1 -row 0 -column 0 -sticky w -padx {0 8} grid $w.entry1 -row 0 -column 1 -sticky w -pady 4 grid $w.label2 -row 1 -column 0 -sticky w -padx {0 8} grid $w.mb2 -row 1 -column 1 -sticky w -pady 4 grid $w.b3 -row 3 -column 0 -columnspan 2 -sticky we -pady {0 4} AddBindTag $w DemoBigListChildWindow AddBindTag $w TagIdentify if {$Priv(noise)} { dbwin "create window $w" } } # Tie the widgets to the global variables for this citizen $w.entry1 configure -textvariable ::DemoBigList::Priv(name,$I) $w.mb2 configure -textvariable ::DemoBigList::Priv(threat,$I) if {!$::tile} { foreach label {Severe High Elevated Guarded Low} { $w.mb2.m entryconfigure $label -variable ::DemoBigList::Priv(threat,$I) } } if {$::clip} { return $f } return $w } proc DemoBigList::FreeWindow {T w} { variable Priv # Add the window to our list of free windows. DemoClear will actually # delete the window when the demo changes. lappend Priv(freeWindows) $w if {$Priv(noise)} { dbwin "free window $w" } return } proc DemoBigList::Button1 {w x y} { variable ::TreeCtrl::Priv focus $w $w identify -array id $x $y set Priv(buttonMode) "" if {$id(where) eq "header"} { TreeCtrl::ButtonPress1 $w $x $y } elseif {$id(where) eq "item"} { set item $id(item) # click a button if {$id(element) eq ""} { TreeCtrl::ButtonPress1 $w $x $y return } if {[$w item tag expr $item !info]} { $w item toggle $item } } return } proc DemoBigList::Motion {w x y} { variable Priv $w identify -array id $x $y if {$id(where) eq "item"} { set item $id(item) if {[$w item tag expr $item !info]} { if {$item ne $Priv(prev)} { $w configure -cursor hand2 set Priv(prev) $item } return } } if {$Priv(prev) ne ""} { $w configure -cursor "" set Priv(prev) "" } return } proc DemoBigList::ThemeChanged {T} { variable Priv GetWindowHeight $T if {[$T item id {first visible tag info}] ne ""} { $T item conf {tag info} -height $Priv(windowHeight) } return } tktreectrl-2.4.1/demos/bitmaps.tcl0000644000076400010400000000422011573516761017477 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker namespace eval DemoBitmaps {} proc DemoBitmaps::Init {T} { # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no \ -selectmode browse -orient horizontal -wrap "5 items" \ -showheader no -backgroundimage sky $T configure -canvaspadx 6 -canvaspady 6 -itemgapx 4 -itemgapy 4 # # Create columns # $T column create -itembackground {gray90 {}} -tags C0 # # Create elements # $T element create elemTxt text -fill [list $::SystemHighlightText {selected focus}] $T element create elemSelTxt rect -fill [list $::SystemHighlight {selected focus}] \ -showfocus yes $T element create elemSelBmp rect -outline [list $::SystemHighlight {selected focus}] \ -outlinewidth 4 $T element create elemBmp bitmap \ -foreground [list $::SystemHighlight {selected focus}] \ -background linen \ -bitmap {question {selected}} # # Create styles using the elements # set S [$T style create STYLE -orient vertical] $T style elements $S {elemSelBmp elemBmp elemSelTxt elemTxt} $T style layout $S elemSelBmp -union elemBmp \ -ipadx 6 -ipady 6 $T style layout $S elemBmp -pady {0 6} -expand we $T style layout $S elemSelTxt -union elemTxt -ipadx 2 $T style layout $S elemTxt -expand we # Set default item style $T column configure C0 -itemstyle $S # # Create items and assign styles # set bitmapNames [list error gray75 gray50 gray25 gray12 hourglass info \ questhead question warning] foreach name $bitmapNames { set I [$T item create] $T item text $I C0 $name $T item element configure $I C0 elemBmp -bitmap $name $T item lastchild root $I } foreach name $bitmapNames { set I [$T item create] $T item style set $I C0 $S $T item text $I C0 $name if 1 { $T item element configure $I C0 elemBmp -bitmap $name \ -foreground [list brown {}] \ -background {"" {}} } else { $T item element configure $I C0 elemBmp -bitmap $name \ -foreground [list $::SystemHighlight {selected focus} brown {}] \ -background {"" {}} } $T item lastchild root $I } return } tktreectrl-2.4.1/demos/column-lock.tcl0000644000076400010400000002637611573564574020310 0ustar TimAdministrators# Copyright (c) 2006-2011 Tim Baker namespace eval DemoColumnLock {} proc DemoColumnLock::Init {T} { variable Priv InitPics *checked # # Configure the treectrl widget # $T configure \ -showbuttons no \ -showlines no \ -showroot no \ -xscrollincrement 40 -xscrolldelay 50 -xscrollsmoothing yes \ -yscrollincrement 0 -yscrolldelay 50 -yscrollsmoothing yes # # Create columns # for {set i 0} {$i < 100} {incr i} { $T column create -text "C$i" -tags C$i -width [expr {40 + 20 * ($i % 2)}] -justify center } $T column configure first -text LEFT -lock left -width "" $T column configure last -text RIGHT -lock right -width "" $T item state define CHECK $T item state define mouseover # # Create styles for the left-locked column, and create items # $T element create label1.bg rect -fill {gray80 mouseover gray {}} $T element create label1.text text $T style create label1 -orient horizontal $T style elements label1 {label1.bg label1.text} $T style layout label1 label1.bg -detach yes -iexpand xy $T style layout label1 label1.text -expand wns -padx 2 for {set i 1} {$i <= 10} {incr i} { set I [$T item create -tags R$i -parent root] $T item style set $I C0 label1 $T item text $I C0 "R$i" } $T element create label2.bd border -background $::SystemButtonFace \ -relief raised -thickness 2 -filled yes $T element create label2.text text $T style create label2 -orient horizontal $T style elements label2 {label2.bd label2.text} $T style layout label2 label2.bd -detach yes -iexpand xy $T style layout label2 label2.text -expand news -padx 2 -pady 2 for {set i 11} {$i <= 20} {incr i} { set I [$T item create -tags R$i -parent root] $T item style set $I C0 label2 $T item text $I C0 "R$i" } $T element create label3.div rect -fill black -height 2 $T element create label3.text text $T style create label3 -orient horizontal $T style elements label3 {label3.div label3.text} $T style layout label3 label3.div -detach yes -expand n -iexpand x $T style layout label3 label3.text -expand ws -padx 2 -pady 2 for {set i 21} {$i <= 30} {incr i} { set I [$T item create -tags R$i -parent root] $T item style set $I C0 label3 $T item text $I C0 "R$i" } $T element create label4.rect rect -fill {#e0e8f0 mouseover} $T element create label4.text text $T element create label4.w window -clip yes -destroy yes $T style create label4 -orient vertical $T style elements label4 {label4.rect label4.text label4.w} $T style layout label4 label4.rect -detach yes -iexpand xy $T style layout label4 label4.text -expand we -padx 2 -pady 2 $T style layout label4 label4.w -iexpand x -padx 2 -pady {0 2} for {set i 31} {$i <= 40} {incr i} { set I [$T item create -tags R$i -parent root] $T item style set $I C0 label4 $T item element configure $I C0 label4.text -textvariable ::DemoColumnLock::Priv(R$i) set clip [frame $T.clipR${I}C0 -borderwidth 0] $::entryCmd $clip.e -width 4 -textvariable ::DemoColumnLock::Priv(R$i) $T item element configure $I C0 label4.w -window $clip set Priv(R$i) "R$i" } # # Create styles for the right-locked column # $T element create labelR1.bg rect -fill {gray80 mouseover gray {}} $T element create labelR1.img image -image {checked CHECK unchecked {}} $T style create labelR1 -orient horizontal $T style elements labelR1 {labelR1.bg labelR1.img} $T style layout labelR1 labelR1.bg -detach yes -iexpand xy $T style layout labelR1 labelR1.img -expand news -padx 2 -pady 2 $T element create labelR2.bd border -background $::SystemButtonFace \ -relief raised -thickness 2 -filled yes $T element create labelR2.img image -image {checked CHECK unchecked {}} $T style create labelR2 -orient horizontal $T style elements labelR2 {labelR2.bd labelR2.img} $T style layout labelR2 labelR2.bd -detach yes -iexpand xy $T style layout labelR2 labelR2.img -expand news -padx 2 -pady 2 $T element create labelR3.div rect -fill black -height 2 $T element create labelR3.img image -image {checked CHECK unchecked {}} $T style create labelR3 -orient horizontal $T style elements labelR3 {labelR3.div labelR3.img} $T style layout labelR3 labelR3.div -detach yes -expand n -iexpand x $T style layout labelR3 labelR3.img -expand news -padx 2 -pady 2 $T element create labelR4.rect rect -fill {#e0e8f0 mouseover} $T element create labelR4.img image -image {checked CHECK unchecked {}} $T style create labelR4 -orient vertical $T style elements labelR4 {labelR4.rect labelR4.img} $T style layout labelR4 labelR4.rect -detach yes -iexpand xy $T style layout labelR4 labelR4.img -expand news -padx 2 -pady 2 $T item style set {range R1 R10} last labelR1 $T item style set {range R11 R20} last labelR2 $T item style set {range R21 R30} last labelR3 $T item style set {range R31 R40} last labelR4 # # Create styles for the non-locked columns # $T item state define selN $T item state define selS $T item state define selW $T item state define selE $T element create cell.bd rect -outline gray -outlinewidth 1 -open wn \ -fill {gray80 mouseover #F7F7F7 CHECK} set fill [list gray !focus $::SystemHighlight {}] $T element create cell.selN rect -height 2 -fill $fill $T element create cell.selS rect -height 2 -fill $fill $T element create cell.selW rect -width 2 -fill $fill $T element create cell.selE rect -width 2 -fill $fill $T style create cell -orient horizontal $T style elements cell {cell.bd cell.selN cell.selS cell.selW cell.selE} $T style layout cell cell.bd -detach yes -iexpand xy $T style layout cell cell.selN -detach yes -expand s -iexpand x -draw {no !selN} $T style layout cell cell.selS -detach yes -expand n -iexpand x -draw {no !selS} $T style layout cell cell.selW -detach yes -expand e -iexpand y -draw {no !selW} $T style layout cell cell.selE -detach yes -expand w -iexpand y -draw {no !selE} # NOTE 1: the following column descriptions are equivalent in this demo: # "range {first next} {last prev}" # "all lock none" (see note #2 below) # "lock none !tail" # The above item descriptions all specify the unlocked columns between # the left-locked and right-locked columns. $T item style set "root children" "range {first next} {last prev}" cell $T element create windowStyle.rect rect -fill {#e0e8f0 mouseover #F7F7F7 CHECK} $T element create windowStyle.text text $T element create windowStyle.window window -clip yes -destroy yes $T style create windowStyle -orient vertical $T style elements windowStyle {windowStyle.rect windowStyle.text windowStyle.window} $T style layout windowStyle windowStyle.rect -detach yes -iexpand xy $T style layout windowStyle windowStyle.text -expand we -padx 2 -pady 2 $T style layout windowStyle windowStyle.window -iexpand x -padx 2 -pady {0 2} # NOTE 2: "all lock none" also matches the tail column, however the # [item style set] command does not operate on the tail column so it is # ignored. Explicitly naming the tail column would result in an error # however. Another example of this behaviour is [column delete all]. $T item style set "list {R2 R22}" "all lock none" windowStyle foreach C [$T column id "lock none !tail"] { set Priv(C$C) [$T column cget $C -tags] set I R2 set clip [frame $T.clipR${I}C$C -borderwidth 0] $::entryCmd $clip.e -width 4 -textvariable ::DemoColumnLock::Priv(C$C) $T item element configure $I $C windowStyle.window -window $clip + \ windowStyle.text -textvariable ::DemoColumnLock::Priv(C$C) set I R22 set clip [frame $T.clipR${I}C$C -borderwidth 0] $::entryCmd $clip.e -width 4 -textvariable ::DemoColumnLock::Priv(C$C) $T item element configure $I $C windowStyle.window -window $clip + \ windowStyle.text -textvariable ::DemoColumnLock::Priv(C$C) } bind DemoColumnLock { DemoColumnLock::Button1 %W %x %y } bind DemoColumnLock { DemoColumnLock::Motion1 %W %x %y DemoColumnLock::Motion %W %x %y } bind DemoColumnLock { DemoColumnLock::Motion %W %x %y } set Priv(prev) "" set Priv(selection) {} bindtags $T [list $T DemoColumnLock TreeCtrl [winfo toplevel $T] all] return } proc DemoColumnLock::Button1 {w x y} { variable Priv $w identify -array id $x $y set Priv(selecting) 0 if {$id(where) eq "item"} { set item $id(item) set column $id(column) if {[$w column compare $column == last]} { $w item state set $item ~CHECK return } if {[$w column cget $column -lock] eq "none"} { set Priv(corner1) [list $item $column] set Priv(corner2) $Priv(corner1) set Priv(selecting) 1 UpdateSelection $w } } return } proc DemoColumnLock::Motion1 {w x y} { variable Priv $w identify -array id $x $y if {$id(where) eq "item"} { set item $id(item) set column $id(column) if {[$w column cget $column -lock] eq "none"} { if {$Priv(selecting)} { set corner [list $item $column] if {$corner ne $Priv(corner2)} { set Priv(corner2) $corner UpdateSelection $w } } } } return } proc DemoColumnLock::Motion {w x y} { variable Priv $w identify -array id $x $y if {$id(where) eq ""} { # nothing } elseif {$id(where) eq "header"} { # nothing } elseif {$id(where) eq "item"} { set item $id(item) set column $id(column) set curr [list $item $column] if {$curr ne $Priv(prev)} { if {$Priv(prev) ne ""} { eval $w item state forcolumn $Priv(prev) !mouseover } $w item state forcolumn $item $column mouseover set Priv(prev) $curr } return } if {$Priv(prev) ne ""} { eval $w item state forcolumn $Priv(prev) !mouseover set Priv(prev) "" } return } proc DemoColumnLock::UpdateSelection {w} { variable Priv # Clear the old selection. foreach {item column} $Priv(selection) { $w item state forcolumn $item $column {!selN !selS !selE !selW} } set Priv(selection) {} # Order the 2 corners. foreach {item1 column1} $Priv(corner1) {} foreach {item2 column2} $Priv(corner2) {} if {[$w item compare $item1 > $item2]} { set swap $item1 set item1 $item2 set item2 $swap } if {[$w column compare $column1 > $column2]} { set swap $column1 set column1 $column2 set column2 $swap } # Set the state of every item-column on the edges of the selection. $w item state forcolumn $item1 "range $column1 $column2" selN $w item state forcolumn $item2 "range $column1 $column2" selS $w item state forcolumn "range $item1 $item2" $column1 selW $w item state forcolumn "range $item1 $item2" $column2 selE # Remember every item-column on the edges of the selection. foreach item [list $item1 $item2] { foreach column [$w column id "range $column1 $column2"] { lappend Priv(selection) $item $column } } foreach item [$w item id "range $item1 $item2"] { foreach column [list $column1 $column2] { lappend Priv(selection) $item $column } } return } proc DemoColumnLock::AddText {} { set w [DemoList] $w style elements cell {cell.bd label1.text cell.selN cell.selS cell.selW cell.selE} $w item text visible {lock none} abc } tktreectrl-2.4.1/demos/demo.tcl0000755000076400010400000020372111646361145016771 0ustar TimAdministrators#!/bin/wish84.exe # Copyright (c) 2002-2011 Tim Baker set VERSION 2.4.1 package require Tk 8.4 set thisPlatform $::tcl_platform(platform) if {$thisPlatform eq "unix" && [tk windowingsystem] eq "aqua"} { set thisPlatform "macosx" } switch -- [tk windowingsystem] { aqua { set thisPlatform "macosx" } classic { set thisPlatform "macintosh" } win32 { set thisPlatform "windows" } x11 { set thisPlatform "unix" } } proc Platform {args} { if {![llength $args]} { return $::thisPlatform } return [expr {[lsearch -exact $args $::thisPlatform] != -1}] } # Get full pathname to this file set ScriptDir [file normalize [file dirname [info script]]] # Command to create a full pathname in this file's directory proc Path {args} { return [file normalize [eval [list file join $::ScriptDir] $args]] } # Create some photo images on demand proc InitPics {args} { foreach pattern $args { if {[lsearch [image names] $pattern] == -1} { foreach file [glob -directory [Path pics] $pattern.gif] { set imageName [file root [file tail $file]] # I created an image called "file", which clobbered the # original Tcl command "file". Then I got confused. if {[llength [info commands $imageName]]} { error "don't want to create image called \"$imageName\"" } image create photo $imageName -file $file # Hack -- Create a "selected" version too image create photo ${imageName}Sel ${imageName}Sel copy $imageName imagetint ${imageName}Sel $::SystemHighlight 128 } } } return } # http://wiki.tcl.tk/1530 if {[info procs lassign] eq ""} { proc lassign {values args} { uplevel 1 [list foreach $args [linsert $values end {}] break] lrange $values [llength $args] end } } if {[catch { package require dbwin }]} { proc dbwin {s} { puts [string trimright $s "\n"] } } proc dbwintrace {name1 name2 op} { dbwin $::dbwin } trace add variable ::dbwin write dbwintrace # This gets called if 'package require' won't work during development. proc LoadSharedLibrary {} { switch -- $::thisPlatform { macintosh { set pattern treectrl*.shlb } macosx { set pattern treectrl*.dylib } unix { set pattern libtreectrl*[info sharedlibextension]* } windows { set pattern treectrl*[info sharedlibextension] } } set SHLIB [glob -nocomplain -directory [Path ..] $pattern] if {[llength $SHLIB] != 1} { return 0 } # When using configure/make, the "make demo" Makefile target sets the value of # the TREECTRL_LIBRARY environment variable which is used by tcl_findLibrary to # find our treectrl.tcl file. When *not* using configure/make, we set the value # of TREECTRL_LIBRARY and load the shared library manually. Note that # tcl_findLibrary is called by the Treectrl_Init() routine in C. set ::env(TREECTRL_LIBRARY) [Path .. library] load $SHLIB return 1 } puts "demo.tcl: Tcl/Tk [info patchlevel] [winfo server .]" # See if treectrl is already loaded for some reason if {[llength [info commands treectrl]]} { puts "demo.tcl: using previously-loaded treectrl package v[package provide treectrl]" if {$VERSION ne [package provide treectrl]} { puts "demo.tcl: WARNING: expected v$VERSION" } # For 'package require' to work with the development version, make sure the # TCLLIBPATH and TREECTRL_LIBRARY environment variables are set by your # Makefile/Jamfile/IDE etc. } elseif {![catch {package require treectrl $VERSION} err]} { puts "demo.tcl: 'package require' succeeded" } else { puts "demo.tcl: 'package require' failed: >>> $err <<<" if {[LoadSharedLibrary]} { puts "demo.tcl: loaded treectrl library by hand" } else { error "demo.tcl: can't load treectrl package" } } # Display path of shared library that was loaded foreach list [info loaded] { set file [lindex $list 0] set pkg [lindex $list 1] if {$pkg ne "Treectrl"} continue puts "demo.tcl: using '$file'" break } if {[info exists env(TREECTRL_LIBRARY)]} { puts "demo.tcl: TREECTRL_LIBRARY=$env(TREECTRL_LIBRARY)" } else { puts "demo.tcl: TREECTRL_LIBRARY undefined" } puts "demo.tcl: treectrl_library=$treectrl_library" set tile 0 set tileFull 0 ; # 1 if using tile-aware treectrl catch { if {[ttk::style layout TreeCtrl] ne ""} { set tile 1 set tileFull 1 } } if {$tile == 0} { catch { package require tile 0.7.8 namespace export style namespace eval ::tile { namespace export setTheme } namespace eval ::ttk { namespace import ::style namespace import ::tile::setTheme } set tile 1 } } if {$tile} { # Don't import ttk::entry, it messes up the edit bindings, and I'm not # sure how to get/set the equivalent -borderwidth, -selectborderwidth # etc options of a TEntry. set entryCmd ::ttk::entry set buttonCmd ::ttk::button set checkbuttonCmd ::ttk::checkbutton set radiobuttonCmd ttk::radiobutton set scrollbarCmd ::ttk::scrollbar set scaleCmd ::ttk::scale } else { set entryCmd ::entry set buttonCmd ::button set checkbuttonCmd ::checkbutton set radiobuttonCmd ::radiobutton set scrollbarCmd ::scrollbar set scaleCmd ::scale } option add *TreeCtrl.Background white #option add *TreeCtrl.itemPrefix item #option add *TreeCtrl.ColumnPrefix col if {$tile} { set font TkDefaultFont } else { switch -- $::thisPlatform { macintosh { set font {Geneva 9} } macosx { set font {{Lucida Grande} 13} } unix { set font {Helvetica -12} } default { # There is a bug on my Win98 box with Tk_MeasureChars() and # MS Sans Serif 8. set font {{MS Sans} 8} } } } array set fontInfo [font actual $font] eval font create DemoFont [array get fontInfo] option add *TreeCtrl.font DemoFont array set fontInfo [font actual $font] set fontInfo(-weight) bold eval font create DemoFontBold [array get fontInfo] array set fontInfo [font actual $font] set fontInfo(-underline) 1 eval font create DemoFontUnderline [array get fontInfo] proc SetDemoFontSize {size} { font configure DemoFont -size $size font configure DemoFontBold -size $size font configure DemoFontUnderline -size $size return } proc IncreaseFontSize {} { set size [font configure DemoFont -size] if {$size < 0} { incr size -1 } else { incr size } SetDemoFontSize $size return } proc DecreaseFontSize {} { set size [font configure DemoFont -size] if {$size < 0} { incr size } else { incr size -1 } SetDemoFontSize $size return } # Demo sources foreach file { biglist bitmaps column-lock explorer firefox gradients gradients2 gradients3 headers help imovie layout mailwasher mycomputer outlook-folders outlook-newgroup random span table textvariable www-options } { source [Path $file.tcl] } # Get default colors set w [listbox .listbox] set SystemButtonFace [$w cget -highlightbackground] set SystemHighlight [$w cget -selectbackground] set SystemHighlightText [$w cget -selectforeground] destroy $w if {$thisPlatform == "unix"} { # I hate that gray selection color set SystemHighlight #316ac5 set SystemHighlightText White } proc MakeMenuBar {} { set m [menu .menubar] . configure -menu $m set m2 [menu $m.mFile -tearoff no] if {$::thisPlatform ne "unix" && [info commands console] ne ""} { console eval { wm title . "TkTreeCtrl Console" if {[info tclversion] == 8.4} { .console configure -font {Courier 9} } .console configure -height 8 # ::tk::ConsolePrompt wm geometry . +0-100 } $m2 add command -label "Console" -command { if {[console eval {winfo ismapped .}]} { console hide } else { console show } } } else { # uplevel #0 source ~/Programming/console.tcl } $m2 add command -label "Event Browser" -command EventsWindow::ToggleWindowVisibility $m2 add command -label "Identify" -command IdentifyWindow::ToggleWindowVisibility $m2 add command -label "Style Editor" -command ToggleStyleEditorWindow $m2 add command -label "View Source" -command SourceWindow::ToggleWindowVisibility $m2 add command -label "Magnifier" -command LoupeWindow::ToggleWindowVisibility $m2 add separator $m2 add checkbutton -label "Native Gradients" -command ToggleNativeGradients \ -variable ::NativeGradients $m2 add separator $m2 add command -label "Increase Font Size" -command IncreaseFontSize $m2 add command -label "Decrease Font Size" -command DecreaseFontSize switch -- [Platform] { macintosh - macosx { $m add cascade -label "TkTreeCtrl" -menu $m2 } unix - windows { $m2 add separator $m2 add command -label "Quit" -command exit $m add cascade -label "File" -menu $m2 } } if {$::tile} { set m2 [menu $m.mTheme -tearoff no] $m add cascade -label "Theme" -menu $m2 foreach theme [lsort -dictionary [ttk::style theme names]] { $m2 add radiobutton -label $theme -command [list ttk::setTheme $theme] \ -variable ::DemoTheme -value $theme } $m2 add separator $m2 add command -label "Inspector" -command ThemeWindow::ToggleWindowVisibility } return } namespace eval EventsWindow {} proc EventsWindow::Init {} { set w [toplevel .events] wm withdraw $w # wm transient $w . wm title $w "TkTreeCtrl Events" set m [menu $w.menubar] $w configure -menu $m set m1 [menu $m.m1 -tearoff 0] $m1 add cascade -label "Static" -menu [menu $m1.m1 -tearoff 0] $m1 add cascade -label "Dynamic" -menu [menu $m1.m2 -tearoff 0] $m1 add command -label "Clear Window" -command "$w.f.t item delete all" \ -accelerator Ctrl+X $m1 add command -label "Rebuild Menus" -command "EventsWindow::RebuildMenus $w.f.t $m" $m add cascade -label "Events" -menu $m1 bind $w "$w.f.t item delete all" TreePlusScrollbarsInAFrame $w.f 1 1 pack $w.f -expand yes -fill both set T $w.f.t $T configure -showheader no -showroot no -showrootlines no -height 300 $T column create -tags C0 $T configure -treecolumn C0 $T element create e1 text -fill [list $::SystemHighlightText {selected focus}] $T element create e2 text -fill [list $::SystemHighlightText {selected focus}] $T element create e3 rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ -showfocus yes $T element create e4 rect -fill blue -width 100 -height 2 set S [$T style create s1] $T style elements $S {e3 e1} $T style layout $S e3 -union [list e1] -ipadx 1 -ipady {0 1} set S [$T style create s2] $T style elements $S {e3 e1 e2} $T style layout $S e1 -width 20 -sticky w $T style layout $S e3 -union [list e1 e2] -ipadx 1 -ipady {0 1} set S [$T style create s3] $T style elements $S {e4} $T column configure C0 -itemstyle s1 RebuildMenus $T $m wm protocol $w WM_DELETE_WINDOW "EventsWindow::ToggleWindowVisibility" switch -- $::thisPlatform { macintosh - macosx { wm geometry $w -40+40 } default { wm geometry $w -0+0 } } return } proc EventsWindow::RebuildMenus {T m} { variable Priv foreach event [lsort -dictionary [[DemoList] notify eventnames]] { set details [lsort -dictionary [[DemoList] notify detailnames $event]] foreach detail $details { set pattern <$event-$detail> set linkage [[DemoList] notify linkage $pattern] lappend patterns $pattern $linkage lappend patterns2($linkage) $pattern } if {![llength $details]} { set pattern <$event> set linkage [[DemoList] notify linkage $pattern] lappend patterns $pattern $linkage lappend patterns2($linkage) $pattern } } $m.m1.m1 delete 0 end $m.m1.m2 delete 0 end set menu(static) $m.m1.m1 set menu(dynamic) $m.m1.m2 foreach {pattern linkage} $patterns { if {![info exists Priv(track,$pattern)]} { set Priv(track,$pattern) 1 } $menu($linkage) add checkbutton -label $pattern \ -variable ::EventsWindow::Priv(track,$pattern) \ -command [list EventsWindow::ToggleEvent $T $pattern] } foreach linkage {static dynamic} { $menu($linkage) add separator $menu($linkage) add command -label "Toggle All" \ -command [list EventsWindow::ToggleEvents $T $patterns2($linkage)] } set Priv(events) {} set Priv(afterId) "" foreach {pattern linkage} $patterns { [DemoList] notify bind $T $pattern { EventsWindow::EventBinding %W %? } } return } proc EventsWindow::EventBinding {T charMap} { variable Priv lappend Priv(events) $charMap if {$Priv(afterId) eq ""} { set Priv(afterId) [after idle [list EventsWindow::RecordEvents $T]] } return } proc EventsWindow::RecordEvents {T} { variable Priv set Priv(afterId) "" set events $Priv(events) set Priv(events) {} if {![winfo ismapped .events]} return if {[$T item numchildren root] > 2000} { set N [expr {[$T item numchildren root] - 2000}] $T item delete "root firstchild" "root child $N" } if {0 && [$T item count] > 1} { set I [$T item create] $T item style set $I 0 s3 $T item lastchild root $I } set open 1 if {[llength $events] > 50} { set open 0 } foreach list $events { RecordEvent $T $list $open } $T see "last visible" return } proc EventsWindow::RecordEvent {T list open} { set I [$T item create -open $open] array set map $list $T item text $I C0 $map(P) $T item lastchild root $I foreach {char value} $list { if {[string first $char "TWPed"] != -1} continue set I2 [$T item create] $T item style set $I2 C0 s2 $T item element configure $I2 C0 e1 -text $char + e2 -text $value $T item lastchild $I $I2 $T item configure $I -button yes } return } proc EventsWindow::ToggleWindowVisibility {} { set w .events if {![winfo exists $w]} { Init } if {[winfo ismapped $w]} { wm withdraw $w } else { wm deiconify $w raise $w } return } proc EventsWindow::ToggleEvent {T pattern} { variable Priv [DemoList] notify configure $T $pattern -active $Priv(track,$pattern) return } proc EventsWindow::ToggleEvents {T patterns} { variable Priv foreach pattern $patterns { set Priv(track,$pattern) [expr {!$Priv(track,$pattern)}] ToggleEvent $T $pattern } return } namespace eval IdentifyWindow {} proc IdentifyWindow::Init {} { set w .identify toplevel $w wm withdraw $w wm title $w "TkTreeCtrl Identify" set wText $w.text text $wText -state disabled -width 70 -height 3 -font [[DemoList] cget -font] $wText tag configure tagBold -font DemoFontBold pack $wText -expand yes -fill both wm protocol $w WM_DELETE_WINDOW "IdentifyWindow::ToggleWindowVisibility" return } proc IdentifyWindow::Update {T x y} { set w .identify if {![winfo exists $w]} return if {![winfo ismapped $w]} return set wText $w.text $wText configure -state normal $wText delete 1.0 end set nearest [$T item id [list nearest $x $y]] $wText insert end "x=" tagBold "$x " {} "y=" tagBold "$y " {} "nearest=" tagBold $nearest\n $wText insert end "string: " foreach {key val} [$T identify $x $y] { $wText insert end $key tagBold " $val " } $wText insert end "\narray: " $T identify -array id $x $y switch -- $id(where) { "header" { set keys [list where header column element side] } "item" { set keys [list where item column element button line] } default { set keys [array names id] } } foreach key $keys { set val $id($key) if {$val eq ""} { set val "\"\"" } $wText insert end $key tagBold " $val " } $wText configure -state disabled return } proc IdentifyWindow::ToggleWindowVisibility {} { set w .identify if {![winfo exists $w]} { Init } if {[winfo ismapped $w]} { wm withdraw $w } else { wm deiconify $w raise $w } return } namespace eval SourceWindow {} proc SourceWindow::Init {} { set w [toplevel .source] wm withdraw $w # wm transient $w . set f [frame $w.f -borderwidth 0] if {[lsearch -exact [font names] TkFixedFont] != -1} { set font TkFixedFont } else { switch -- $::thisPlatform { macintosh - macosx { set font {Geneva 9} } unix { set font {Courier -12} } default { set font {Courier 9} } } } text $f.t -font $font -tabs [font measure $font 12345678] -wrap none \ -yscrollcommand "$f.sv set" -xscrollcommand "$f.sh set" $::scrollbarCmd $f.sv -orient vertical -command "$f.t yview" $::scrollbarCmd $f.sh -orient horizontal -command "$f.t xview" pack $f -expand yes -fill both grid columnconfigure $f 0 -weight 1 grid rowconfigure $f 0 -weight 1 grid configure $f.t -row 0 -column 0 -sticky news grid configure $f.sh -row 1 -column 0 -sticky we grid configure $f.sv -row 0 -column 1 -sticky ns wm protocol $w WM_DELETE_WINDOW "SourceWindow::ToggleWindowVisibility" switch -- $::thisPlatform { macintosh - macosx { wm geometry $w +0+30 } default { wm geometry $w -0+0 } } return } proc SourceWindow::ShowSource {file} { wm title .source "TkTreeCtrl Source: $file" set path [Path $file] set t .source.f.t set chan [open $path] $t delete 1.0 end $t insert end [read $chan] $t mark set insert 1.0 close $chan return } proc SourceWindow::ToggleWindowVisibility {} { set w .source if {[winfo ismapped $w]} { wm withdraw $w } else { wm deiconify $w raise $w } return } proc ToggleStyleEditorWindow {} { set w .styleEditor if {![winfo exists $w]} { source [Path style-editor.tcl] StyleEditor::Init [DemoList] StyleEditor::SetListOfStyles } elseif {[winfo ismapped $w]} { wm withdraw $w } else { wm deiconify $w raise $w StyleEditor::SetListOfStyles } return } namespace eval ThemeWindow {} proc ThemeWindow::Init {} { set w [toplevel .theme] wm withdraw $w # wm transient $w . wm title $w "TkTreeCtrl Themes" set m [menu $w.menubar] $w configure -menu $m set m1 [menu $m.m1 -tearoff 0] $m1 add command -label "Set List" -command ThemeWindow::SetList $m add cascade -label "Theme" -menu $m1 TreePlusScrollbarsInAFrame $w.f 1 1 pack $w.f -expand yes -fill both set T $w.f.t $T configure -showheader no -showroot no -showrootlines no -height 300 $T column create -tags C0 $T configure -treecolumn C0 $T element create e1 text -fill [list $::SystemHighlightText {selected focus}] $T element create e3 rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ -showfocus yes set S [$T style create s1] $T style elements $S {e3 e1} $T style layout $S e3 -union [list e1] -ipadx 1 -ipady {0 1} $T column configure C0 -itemstyle s1 SetList wm protocol $w WM_DELETE_WINDOW "ThemeWindow::ToggleWindowVisibility" return } proc ThemeWindow::ToggleWindowVisibility {} { set w .theme if {![winfo exists $w]} { Init } if {[winfo ismapped $w]} { wm withdraw $w } else { wm deiconify $w raise $w } return } proc ThemeWindow::SetList {} { set w .theme set T $w.f.t $T item delete all # # Themes # foreach theme [lsort -dictionary [ttk::style theme names]] { set I [$T item create -button yes -open no -tags theme -parent root] $T item text $I C0 $theme ttk::style theme settings $theme { set I2 [$T item create -button yes -open no -parent $I] $T item text $I2 C0 ELEMENTS # # Elements # foreach element [lsort -dictionary [ttk::style element names]] { # # Element options # set options [ttk::style element options $element] set I3 [$T item create -button [llength $options] -open no -tags element -parent $I2] $T item text $I3 C0 $element foreach option [lsort -dictionary $options] { set I4 [$T item create -open no -tags {element option} -parent $I3] $T item text $I4 C0 $option } } # # Styles # set I2 [$T item create -button yes -open no -parent $I] $T item text $I2 C0 STYLES set styles [list "."] ; # [ttk::style names] please! foreach style [lsort -dictionary $styles] { # # Style options # set cfg [ttk::style configure $style] set I3 [$T item create -button [llength $cfg] -open no -tags style -parent $I2] $T item text $I3 C0 $style foreach {option value} $cfg { set I4 [$T item create -open no -tags {style option} -parent $I3] $T item text $I4 C0 "$option $value" } } } } return } set ::NativeGradients 1 proc ToggleNativeGradients {} { [DemoList] gradient native $::NativeGradients dbwin "native gradients is now $::NativeGradients" return } SourceWindow::Init MakeMenuBar # http://wiki.tcl.tk/950 proc sbset {sb first last} { # Get infinite loop on X11 if {$::thisPlatform ne "unix"} { if {$first <= 0 && $last >= 1} { grid remove $sb } else { grid $sb } } $sb set $first $last return } proc TreePlusScrollbarsInAFrame {f h v} { if {$::tileFull} { frame $f -borderwidth 0 } else { frame $f -borderwidth 1 -relief sunken } treectrl $f.t -highlightthickness 0 -borderwidth 0 if {[Platform unix]} { $f.t configure -headerfont [$f.t cget -font] } $f.t configure -xscrollincrement 20 -xscrollsmoothing 1 # $f.t configure -itemprefix item# -columnprefix column# $f.t debug configure -enable no -display yes -erasecolor pink \ -drawcolor orange -displaydelay 30 -textlayout 0 -data 0 -span 0 if {$h} { $::scrollbarCmd $f.sh -orient horizontal -command "$f.t xview" # $f.t configure -xscrollcommand "$f.sh set" $f.t notify bind $f.sh { sbset %W %l %u } bind $f.sh "focus $f.t" } if {$v} { $::scrollbarCmd $f.sv -orient vertical -command "$f.t yview" # $f.t configure -yscrollcommand "$f.sv set" $f.t notify bind $f.sv { sbset %W %l %u } bind $f.sv "focus $f.t" } grid columnconfigure $f 0 -weight 1 grid rowconfigure $f 0 -weight 1 grid configure $f.t -row 0 -column 0 -sticky news if {$h} { grid configure $f.sh -row 1 -column 0 -sticky we } if {$v} { grid configure $f.sv -row 0 -column 1 -sticky ns } bind $f.t { TreeCtrl::MarqueeBegin %W %x %y set DebugExpose(x1) %x set DebugExpose(y1) %y break } bind $f.t { TreeCtrl::MarqueeUpdate %W %x %y set DebugExpose(x2) %x set DebugExpose(y2) %y break } bind $f.t { TreeCtrl::MarqueeEnd %W %x %y %W debug expose $DebugExpose(x1) $DebugExpose(y1) $DebugExpose(x2) $DebugExpose(y2) break } MakeListPopup $f.t MakeHeaderPopup $f.t switch -- $::thisPlatform { macintosh - macosx { bind $f.t { ShowPopup %W %x %y %X %Y } bind $f.t { ShowPopup %W %x %y %X %Y } } unix - windows { bind $f.t { ShowPopup %W %x %y %X %Y } } } return } proc ShouldShowLines {T} { if {![$T cget -usetheme]} { return 1 } switch -- [$T theme platform] { aqua - gtk { return 0 } } return 1 } proc MakeMainWindow {} { wm title . "TkTreeCtrl Demo" switch -- $::thisPlatform { macintosh - macosx { wm geometry . +6+30 } default { wm geometry . +0+0 } } panedwindow .pw2 -orient horizontal -borderwidth 0 -sashwidth 6 panedwindow .pw1 -orient vertical -borderwidth 0 -sashwidth 6 # Tree + scrollbar: demos TreePlusScrollbarsInAFrame .f1 1 1 .f1.t configure -showbuttons no -showlines no -showroot no -height 100 .f1.t column create -text "List of Demos" -expand yes -button no -tags C0 .f1.t configure -treecolumn C0 # Tree + scrollbar: styles + elements in list TreePlusScrollbarsInAFrame .f4 1 1 .f4.t configure -showlines [ShouldShowLines .f4.t] -showroot no -height 140 .f4.t column create -text "Elements and Styles" -expand yes -button no -tags C0 .f4.t configure -treecolumn C0 # Tree + scrollbar: styles + elements in selected item TreePlusScrollbarsInAFrame .f3 1 1 .f3.t configure -showlines [ShouldShowLines .f3.t] -showroot no .f3.t column create -text "Styles in Item" -expand yes -button no -tags C0 .f3.t configure -treecolumn C0 .pw1 add .f1 .f4 .f3 -height 150 # Frame on right frame .f2 # Tree + scrollbars TreePlusScrollbarsInAFrame .f2.f1 1 1 [DemoList] configure -indent 19 # Give it a big border to debug drawing if {!$::tileFull} { [DemoList] configure -borderwidth 6 -relief ridge -highlightthickness 3 } grid columnconfigure .f2 0 -weight 1 grid rowconfigure .f2 0 -weight 1 grid configure .f2.f1 -row 0 -column 0 -sticky news -pady 0 # Window to display result of "T identify" bind TagIdentify { if {"%W" ne [DemoList]} { set x [expr {%X - [winfo rootx [DemoList]]}] set y [expr {%Y - [winfo rooty [DemoList]]}] } else { set x %x set y %y } IdentifyWindow::Update [DemoList] $x $y } AddBindTag [DemoList] TagIdentify .pw2 add .pw1 -width 200 .pw2 add .f2 -width 450 pack .pw2 -expand yes -fill both bind [DemoList] { set NativeGradients [expr {!$NativeGradients}] ToggleNativeGradients } ### # A treectrl widget can generate the following built-in events: # called when the active item changes # called before an item is closed # called after an item is closed # called before an item is opened # called after an item is opened # called before items are deleted # called when horizontal scroll position changes # called when vertical scroll position changes # called when items are added to or removed from the selection # # The application programmer can define custom events to be # generated by the "notify generate" command. The following events # are generated by the library scripts. [DemoList] notify install [DemoList] notify install [DemoList] notify install [DemoList] notify install [DemoList] notify install [DemoList] notify install [DemoList] notify install [DemoList] notify install [DemoList] notify install [DemoList] notify install [DemoList] notify install [DemoList] notify install ### # This event is generated when a column's visibility is changed by # the context menu. [DemoList] notify install return } proc DemoList {} { return .f2.f1.t } proc demolist args { # console-friendly version uplevel .f2.f1.t $args } proc MakeListPopup {T} { set m [menu $T.mTree -tearoff no] set m2 [menu $m.mCollapse -tearoff no] $m add cascade -label Collapse -menu $m2 set m2 [menu $m.mExpand -tearoff no] $m add cascade -label Expand -menu $m2 set m2 [menu $m.mBgImg -tearoff no] $m2 add radiobutton -label none -variable Popup(bgimg) -value none \ -command {$Popup(T) configure -backgroundimage ""} $m2 add radiobutton -label feather -variable Popup(bgimg) -value feather \ -command {$Popup(T) configure -bgimage $Popup(bgimg) -bgimageopaque no} $m2 add radiobutton -label sky -variable Popup(bgimg) -value sky \ -command {$Popup(T) configure -bgimage $Popup(bgimg) -bgimageopaque yes} $m2 add separator set m3 [menu $m2.mBgImgAnchor -tearoff no] foreach anchor {nw n ne w center e sw s se} { $m3 add radiobutton -label $anchor -variable Popup(bgimganchor) \ -value $anchor \ -command {$Popup(T) configure -bgimageanchor $Popup(bgimganchor)} } $m2 add cascade -label "Anchor" -menu $m3 $m2 add separator $m2 add checkbutton -label "Opaque" -variable Popup(bgimgopaque) \ -command {$Popup(T) configure -bgimageopaque $Popup(bgimgopaque)} $m2 add separator $m2 add checkbutton -label "Scroll X" -variable Popup(bgimgscrollx) \ -onvalue x -offvalue "" -command {$Popup(T) configure -bgimagescroll $Popup(bgimgscrollx)$Popup(bgimgscrolly)} $m2 add checkbutton -label "Scroll Y" -variable Popup(bgimgscrolly) \ -onvalue y -offvalue "" -command {$Popup(T) configure -bgimagescroll $Popup(bgimgscrollx)$Popup(bgimgscrolly)} $m2 add separator $m2 add checkbutton -label "Tile X" -variable Popup(bgimgtilex) \ -onvalue x -offvalue "" -command {$Popup(T) configure -bgimagetile $Popup(bgimgtilex)$Popup(bgimgtiley)} $m2 add checkbutton -label "Tile Y" -variable Popup(bgimgtiley) \ -onvalue y -offvalue "" -command {$Popup(T) configure -bgimagetile $Popup(bgimgtilex)$Popup(bgimgtiley)} $m add cascade -label "Background Image" -menu $m2 set m2 [menu $m.mBgMode -tearoff no] foreach value {column order ordervisible row} { $m2 add radiobutton -label $value -variable Popup(bgmode) -value $value \ -command {$Popup(T) configure -backgroundmode $Popup(bgmode)} } $m add cascade -label "Background Mode" -menu $m2 $m add checkbutton -label "Button Tracking" -variable Popup(buttontracking) \ -command {$Popup(T) configure -buttontracking $Popup(buttontracking)} set m2 [menu $m.mColumns -tearoff no] $m add cascade -label "Columns" -menu $m2 set m2 [menu $m.mHeaders -tearoff no] $m add cascade -label "Headers" -menu $m2 set m2 [menu $m.mColumnResizeMode -tearoff no] $m2 add radiobutton -label proxy -variable Popup(columnresizemode) -value proxy \ -command {$Popup(T) configure -columnresizemode $Popup(columnresizemode)} $m2 add radiobutton -label realtime -variable Popup(columnresizemode) -value realtime \ -command {$Popup(T) configure -columnresizemode $Popup(columnresizemode)} $m add cascade -label "Column Resize Mode" -menu $m2 set m2 [menu $m.mDebug -tearoff no] $m2 add checkbutton -label Data -variable Popup(debug,data) \ -command {$Popup(T) debug configure -data $Popup(debug,data)} $m2 add checkbutton -label Display -variable Popup(debug,display) \ -command {$Popup(T) debug configure -display $Popup(debug,display)} $m2 add checkbutton -label Span -variable Popup(debug,span) \ -command {$Popup(T) debug configure -span $Popup(debug,span)} $m2 add checkbutton -label "Text Layout" -variable Popup(debug,textlayout) \ -command {$Popup(T) debug configure -textlayout $Popup(debug,textlayout)} $m2 add separator set m3 [menu $m2.mDelay -tearoff no] foreach n {10 20 30 40 50 60 70 80 90 100} { $m3 add radiobutton -label $n -variable Popup(debug,displaydelay) -value $n \ -command {$Popup(T) debug configure -displaydelay $Popup(debug,displaydelay)} } $m2 add cascade -label "Display Delay" -menu $m3 $m2 add separator $m2 add checkbutton -label Enable -variable Popup(debug,enable) \ -command {$Popup(T) debug configure -enable $Popup(debug,enable)} $m add cascade -label Debug -menu $m2 if 0 { set m2 [menu $m.mBuffer -tearoff no] $m2 add radiobutton -label "none" -variable Popup(doublebuffer) -value none \ -command {$Popup(T) configure -doublebuffer $Popup(doublebuffer)} $m2 add radiobutton -label "item" -variable Popup(doublebuffer) -value item \ -command {$Popup(T) configure -doublebuffer $Popup(doublebuffer)} $m2 add radiobutton -label "window" -variable Popup(doublebuffer) -value window \ -command {$Popup(T) configure -doublebuffer $Popup(doublebuffer)} $m add cascade -label Buffering -menu $m2 } set m2 [menu $m.mItemWrap -tearoff no] $m add cascade -label "Item Wrap" -menu $m2 set m2 [menu $m.mLineStyle -tearoff no] $m2 add radiobutton -label "dot" -variable Popup(linestyle) -value dot \ -command {$Popup(T) configure -linestyle $Popup(linestyle)} $m2 add radiobutton -label "solid" -variable Popup(linestyle) -value solid \ -command {$Popup(T) configure -linestyle $Popup(linestyle)} $m add cascade -label "Line style" -menu $m2 set m2 [menu $m.mOrient -tearoff no] $m2 add radiobutton -label "Horizontal" -variable Popup(orient) -value horizontal \ -command {$Popup(T) configure -orient $Popup(orient)} $m2 add radiobutton -label "Vertical" -variable Popup(orient) -value vertical \ -command {$Popup(T) configure -orient $Popup(orient)} $m add cascade -label Orient -menu $m2 set m2 [menu $m.mSmoothing -tearoff no] $m2 add checkbutton -label X -variable Popup(xscrollsmoothing) \ -command {$Popup(T) configure -xscrollsmoothing $Popup(xscrollsmoothing)} $m2 add checkbutton -label Y -variable Popup(yscrollsmoothing) \ -command {$Popup(T) configure -yscrollsmoothing $Popup(yscrollsmoothing)} $m add cascade -label "Scroll Smoothing" -menu $m2 set m2 [menu $m.mSelectMode -tearoff no] foreach mode [list browse extended multiple single] { $m2 add radiobutton -label $mode -variable Popup(selectmode) -value $mode \ -command {$Popup(T) configure -selectmode $Popup(selectmode)} } $m add cascade -label Selectmode -menu $m2 set m2 [menu $m.mShow -tearoff no] $m2 add checkbutton -label "Buttons" -variable Popup(showbuttons) \ -command {$Popup(T) configure -showbuttons $Popup(showbuttons)} $m2 add checkbutton -label "Header" -variable Popup(showheader) \ -command {$Popup(T) configure -showheader $Popup(showheader)} $m2 add checkbutton -label "Lines" -variable Popup(showlines) \ -command {$Popup(T) configure -showlines $Popup(showlines)} $m2 add checkbutton -label "Root" -variable Popup(showroot) \ -command {$Popup(T) configure -showroot $Popup(showroot)} $m2 add checkbutton -label "Root Button" -variable Popup(showrootbutton) \ -command {$Popup(T) configure -showrootbutton $Popup(showrootbutton)} $m2 add checkbutton -label "Root Child Buttons" -variable Popup(showrootchildbuttons) \ -command {$Popup(T) configure -showrootchildbuttons $Popup(showrootchildbuttons)} $m2 add checkbutton -label "Root Child Lines" -variable Popup(showrootlines) \ -command {$Popup(T) configure -showrootlines $Popup(showrootlines)} $m add cascade -label Show -menu $m2 set m2 [menu $m.mSpan -tearoff no] $m add cascade -label Span -menu $m2 $m add checkbutton -label "Use Theme" -variable Popup(usetheme) \ -command {$Popup(T) configure -usetheme $Popup(usetheme)} return } proc MakeHeaderPopup {T} { set m [menu $T.mColumn -tearoff no] ### Header set m1 [menu $m.mHeader -tearoff no] $m add cascade -label "Header" -menu $m1 $m1 add checkbutton -label "Visible" -variable Popup(header,visible) \ -command [list eval $T header configure \$Popup(header) -visible \$Popup(header,visible)] set m2 [menu $m1.mDnD -tearoff no] $m1 add cascade -label "Drag and Drop" -menu $m2 $m2 add checkbutton -label "Draw" -variable Popup(header,drag,draw) \ -command [list eval $T header dragconfigure \$Popup(header) -draw \$Popup(header,drag,draw)] $m2 add checkbutton -label "Enable" -variable Popup(header,drag,enable) \ -command [list eval $T header dragconfigure \$Popup(header) -enable \$Popup(header,drag,enable)] ### Header column set m1 [menu $m.mHeaderColumn -tearoff no] $m add cascade -label "Header Column" -menu $m1 set m2 [menu $m1.mArrow -tearoff no] $m1 add cascade -label Arrow -menu $m2 $m2 add radiobutton -label "None" -variable Popup(arrow) -value none \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -arrow none} $m2 add radiobutton -label "Up" -variable Popup(arrow) -value up \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -arrow up} $m2 add radiobutton -label "Down" -variable Popup(arrow) -value down \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -arrow down} $m2 add separator $m2 add radiobutton -label "Side Left" -variable Popup(arrow,side) -value left \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -arrowside left} $m2 add radiobutton -label "Side Right" -variable Popup(arrow,side) -value right \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -arrowside right} $m2 add separator $m2 add radiobutton -label "Gravity Left" -variable Popup(arrow,gravity) -value left \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -arrowgravity left} $m2 add radiobutton -label "Gravity Right" -variable Popup(arrow,gravity) -value right \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -arrowgravity right} $m1 add checkbutton -label "Button" -variable Popup(button) \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -button $Popup(button)} set m2 [menu $m1.mJustify -tearoff no] $m1 add cascade -label "Justify" -menu $m2 $m2 add radiobutton -label "Left" -variable Popup(header,justify) -value left \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -justify left} $m2 add radiobutton -label "Center" -variable Popup(header,justify) -value center \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -justify center} $m2 add radiobutton -label "Right" -variable Popup(header,justify) -value right \ -command {$Popup(T) header configure $Popup(header) $Popup(column) -justify right} set m2 [menu $m1.mSpan -tearoff no] $m1 add cascade -label Span -menu $m2 ### Tree column $m add command -label "Column" return } proc MakeHeaderSubmenu {T H parentMenu} { ### Header set m1 [menu $parentMenu.mHeader$H -tearoff no] $m1 add checkbutton -label "Visible" -variable Popup(header,visible,$H) \ -command [list eval $T header configure $H -visible \$Popup(header,visible,$H)] return $m1 } proc MakeColumnSubmenu {T C parentMenu {menuName ""}} { ### Tree-column if 1 { if {$menuName ne ""} { set m1 [menu $parentMenu.mColumn$menuName -tearoff no] } else { set m1 [menu $parentMenu.mColumn$C -tearoff no] } } else { set m1 $parentMenu.mColumn$C $m1 delete 0 end } $m1 add checkbutton -label "Expand" -variable Popup(column,expand,$C) \ -command [list eval $T column configure $C -expand \$Popup(column,expand,$C)] set m2 [menu $m1.mItemJustify -tearoff no] $m1 add cascade -label "Item Justify" -menu $m2 $m2 add radiobutton -label "Left" -variable Popup(column,itemjustify,$C) -value left \ -command [list $T column configure $C -itemjustify left] $m2 add radiobutton -label "Center" -variable Popup(column,itemjustify,$C) -value center \ -command [list $T column configure $C -itemjustify center] $m2 add radiobutton -label "Right" -variable Popup(column,itemjustify,$C) -value right \ -command [list $T column configure $C -itemjustify right] $m2 add radiobutton -label "Unspecified" -variable Popup(column,itemjustify,$C) -value none \ -command [list $T column configure $C -itemjustify {}] set m2 [menu $m1.mJustify -tearoff no] $m1 add cascade -label "Justify" -menu $m2 $m2 add radiobutton -label "Left" -variable Popup(column,justify,$C) -value left \ -command [list $T column configure $C -justify left] $m2 add radiobutton -label "Center" -variable Popup(column,justify,$C) -value center \ -command [list $T column configure $C -justify center] $m2 add radiobutton -label "Right" -variable Popup(column,justify,$C) -value right \ -command [list $T column configure $C -justify right] set m2 [menu $m1.mLock -tearoff no] $m1 add cascade -label Lock -menu $m2 $m2 add radiobutton -label "Left" -variable Popup(column,lock,$C) -value left \ -command [list $T column configure $C -lock left] $m2 add radiobutton -label "None" -variable Popup(column,lock,$C) -value none \ -command [list $T column configure $C -lock none] $m2 add radiobutton -label "Right" -variable Popup(column,lock,$C) -value right \ -command [list $T column configure $C -lock right] $m1 add checkbutton -label "Resize" -variable Popup(column,resize,$C) \ -command [list eval $T column configure $C -resize \$Popup(column,resize,$C)] $m1 add checkbutton -label "Squeeze" -variable Popup(column,squeeze,$C) \ -command [list eval $T column configure $C -squeeze \$Popup(column,squeeze,$C)] $m1 add checkbutton -label "Tree Column" -variable Popup(column,treecolumn,$C) \ -command [list eval $T configure -treecolumn "\[expr {\$Popup(column,treecolumn,$C) ? $C : {}}\]"] $m1 add checkbutton -label "Visible" -variable Popup(column,visible,$C) \ -command [list eval $T column configure $C -visible \$Popup(column,visible,$C) \; \ TreeCtrl::TryEvent $T DemoColumnVisibility {} [list C $C] ] return $m1 } proc AddBindTag {w tag} { if {[lsearch -exact [bindtags $w] $tag] == -1} { bindtags $w [concat [bindtags $w] $tag] } foreach child [winfo children $w] { AddBindTag $child $tag } return } MakeMainWindow InitPics sky feather proc ShowPopup {T x y X Y} { global Popup set Popup(T) $T $T identify -array id $x $y if {$id(where) ne ""} { if {$id(where) eq "header"} { set H $id(header) set C $id(column) set Popup(header) $H set Popup(column) $C set Popup(arrow) [$T header cget $H $C -arrow] set Popup(arrow,side) [$T header cget $H $C -arrowside] set Popup(arrow,gravity) [$T header cget $H $C -arrowgravity] set Popup(button) [$T header cget $H $C -button] set Popup(header,justify) [$T header cget $H $C -justify] set Popup(header,visible) [$T header cget $H -visible] set Popup(header,drag,draw) [$T header dragcget $H -draw] set Popup(header,drag,enable) [$T header dragcget $H -enable] set Popup(column,expand,$C) [$T column cget $C -expand] set Popup(column,resize,$C) [$T column cget $C -resize] set Popup(column,squeeze,$C) [$T column cget $C -squeeze] set Popup(column,itemjustify,$C) [$T column cget $C -itemjustify] if {$Popup(column,itemjustify,$C) eq ""} { set Popup(column,itemjustify) none } set Popup(column,justify,$C) [$T column cget $C -justify] set Popup(column,lock,$C) [$T column cget $C -lock] set Popup(column,treecolumn,$C) [expr {[$T column id tree] eq $C}] $T.mColumn delete "Column" destroy $T.mColumn.mColumnX set m1 [MakeColumnSubmenu $T $C $T.mColumn "X"] $T.mColumn add cascade -label "Column" -menu $m1 set m $T.mColumn.mHeaderColumn.mSpan $m delete 0 end if {[$T column compare $C == tail]} { $m add checkbutton -label 1 -variable Popup(span) set Popup(span) 1 } else { set lock [$T column cget $C -lock] set last [expr {[$T column order "last lock $lock"] - [$T column order $C] + 1}] for {set i 1} {$i <= $last} {incr i} { set break [expr {!(($i - 1) % 20)}] $m add radiobutton -label $i -command "$T header span $H $C $i" \ -variable Popup(span) -value $i -columnbreak $break } set Popup(span) [$T header span $H $C] } tk_popup $T.mColumn $X $Y return } } set menu $T.mTree set m $menu.mCollapse $m delete 0 end $m add command -label "All" -command {$Popup(T) item collapse all} if {$id(where) eq "item"} { set item $id(item) $m add command -label "Item $item" -command "$T item collapse $item" $m add command -label "Item $item (recurse)" -command "$T item collapse $item -recurse" } set m $menu.mExpand $m delete 0 end $m add command -label "All" -command {$Popup(T) item expand all} if {$id(where) eq "item"} { set item $id(item) $m add command -label "Item $item" -command "$T item expand $item" $m add command -label "Item $item (recurse)" -command "$T item expand $item -recurse" } foreach option {data display displaydelay enable span textlayout} { set Popup(debug,$option) [$T debug cget -$option] } set Popup(bgimg) [$T cget -backgroundimage] set Popup(bgimganchor) [$T cget -bgimageanchor] set Popup(bgimgopaque) [$T cget -bgimageopaque] set Popup(bgimgscrollx) [string trim [$T cget -bgimagescroll] y] set Popup(bgimgscrolly) [string trim [$T cget -bgimagescroll] x] set Popup(bgimgtilex) [string trim [$T cget -bgimagetile] y] set Popup(bgimgtiley) [string trim [$T cget -bgimagetile] x] if {$Popup(bgimg) eq ""} { set Popup(bgimg) none } set Popup(bgmode) [$T cget -backgroundmode] set Popup(buttontracking) [$T cget -buttontracking] set Popup(columnresizemode) [$T cget -columnresizemode] set Popup(doublebuffer) [$T cget -doublebuffer] set Popup(linestyle) [$T cget -linestyle] set Popup(orient) [$T cget -orient] set Popup(selectmode) [$T cget -selectmode] set Popup(xscrollsmoothing) [$T cget -xscrollsmoothing] set Popup(yscrollsmoothing) [$T cget -yscrollsmoothing] set Popup(showbuttons) [$T cget -showbuttons] set Popup(showheader) [$T cget -showheader] set Popup(showlines) [$T cget -showlines] set Popup(showroot) [$T cget -showroot] set Popup(showrootbutton) [$T cget -showrootbutton] set Popup(showrootchildbuttons) [$T cget -showrootchildbuttons] set Popup(showrootlines) [$T cget -showrootlines] set m $menu.mColumns eval destroy [winfo children $m] $m delete 0 end foreach C [$T column list] { set break [expr {!([$T column order $C] % 20)}] set m1 [MakeColumnSubmenu $T $C $m] # set m1 [menu $m.mColumn$C -postcommand [list PostColumnSubmenu $T $C $m]] $m add cascade -menu $m1 -columnbreak $break \ -label "Column $C \"[$T column cget $C -text]\" \[[$T column cget $C -image]\]" set Popup(column,expand,$C) [$T column cget $C -expand] set Popup(column,justify,$C) [$T column cget $C -justify] set Popup(column,itemjustify,$C) [$T column cget $C -itemjustify] if {$Popup(column,itemjustify,$C) eq ""} { set Popup(column,itemjustify,$C) none } set Popup(column,lock,$C) [$T column cget $C -lock] set Popup(column,squeeze,$C) [$T column cget $C -squeeze] set Popup(column,visible,$C) [$T column cget $C -visible] set Popup(treecolumn,$C) no if {[$T column id tree] ne ""} { set Popup(treecolumn,$C) [$T column compare [$T column id tree] == $C] } } set m $menu.mHeaders eval destroy [winfo children $m] $m delete 0 end foreach H [$T header id all] { set m1 [MakeHeaderSubmenu $T $H $m] $m add cascade -menu $m1 -label "Header $H" set Popup(header,visible,$H) [$T header cget $H -visible] } set m $menu.mItemWrap $m delete 0 end $m add command -label "All Off" -command {$Popup(T) item configure all -wrap off} $m add command -label "All On" -command {$Popup(T) item configure all -wrap on} if {$id(where) eq "item"} { set item $id(item) if {[$T item cget $item -wrap]} { $m add command -label "Item $item Off" -command "$T item configure $item -wrap off" } else { $m add command -label "Item $item On" -command "$T item configure $item -wrap on" } } set m $menu.mSpan $m delete 0 end if {$id(where) eq "item" && $id(column) ne ""} { set item $id(item) set column $id(column) set lock [$T column cget $column -lock] for {set i 1} {$i <= [$T column order "last lock $lock"] - [$T column order $column] + 1} {incr i} { set break [expr {!(($i - 1) % 20)}] $m add radiobutton -label $i -command "$T item span $item $column $i" \ -variable Popup(span) -value $i -columnbreak $break } set Popup(span) [$T item span $item $column] } else { $m add command -label "no item column" -state disabled } set Popup(usetheme) [$T cget -usetheme] tk_popup $menu $X $Y return } # Allow "scan" bindings if {$::thisPlatform eq "windows"} { bind [DemoList] { } } # # List of demos # proc InitDemoList {} { global DemoCmd global DemoFile set t .f1.t $t element create e1 text -fill [list $::SystemHighlightText {selected focus}] $t element create e2 rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ -showfocus yes $t style create s1 $t style elements s1 {e2 e1} # Tk listbox has linespace + 1 height $t style layout s1 e2 -union [list e1] -ipadx 2 -ipady {0 1} -iexpand e $t column configure C0 -itemstyle s1 # "Picture Catalog" DemoPictureCatalog # "Picture Catalog 2" DemoPictureCatalog2 # "Folder Contents (Vertical)" DemoExplorerFilesV foreach {label command file} [list \ "Random $::RandomN Items" DemoRandom random.tcl \ "Random $::RandomN Items, Button Images" DemoRandom2 random.tcl \ "Outlook Express (Folders)" DemoOutlookFolders outlook-folders.tcl \ "Outlook Express (Newsgroup)" DemoOutlookNewsgroup outlook-newgroup.tcl \ "Explorer (Details, Win98)" DemoExplorerDetails explorer.tcl \ "Explorer (Details, Win7)" DemoExplorerDetailsWin7 explorer.tcl \ "Explorer (List)" DemoExplorerList explorer.tcl \ "Explorer (Large icons, Win98)" DemoExplorerLargeIcons explorer.tcl \ "Explorer (Large icons, Win7)" DemoExplorerLargeIconsWin7 explorer.tcl \ "Explorer (Small icons)" DemoExplorerSmallIcons explorer.tcl \ "Internet Options" DemoInternetOptions www-options.tcl \ "Help Contents" DemoHelpContents help.tcl \ "Layout" DemoLayout layout.tcl \ "MailWasher" DemoMailWasher mailwasher.tcl \ "Bitmaps" DemoBitmaps bitmaps.tcl \ "iMovie" DemoIMovie imovie.tcl \ "iMovie (Wrap)" DemoIMovieWrap imovie.tcl \ "Firefox Privacy" DemoFirefoxPrivacy firefox.tcl \ "Textvariable" DemoTextvariable textvariable.tcl \ "Big List" DemoBigList biglist.tcl \ "Column Spanning" DemoSpan span.tcl \ "My Computer" DemoMyComputer mycomputer.tcl \ "Column Locking" DemoColumnLock column-lock.tcl \ "Gradients" DemoGradients gradients.tcl \ "Gradients II" DemoGradients2 gradients2.tcl \ "Gradients III" DemoGradients3 gradients3.tcl \ "Headers" DemoHeaders headers.tcl \ "Table" DemoTable table.tcl \ ] { set item [$t item create] $t item lastchild root $item # $t item style set $item C0 s1 $t item text $item C0 $label set DemoCmd($item) $command set DemoFile($item) $file } $t yview moveto 0.0 return } InitDemoList proc TimerStart {} { if {[info tclversion] < 8.5} { return [set ::gStartTime [clock clicks -milliseconds]] } return [set ::gStartTime [clock microseconds]] } proc TimerStop {{startTime ""}} { if {[info tclversion] < 8.5} { set endTime [clock clicks -milliseconds] if {$startTime eq ""} { set startTime $::gStartTime } return [format "%.2g" [expr {($endTime - $startTime) / 1000.0}]] } set endTime [clock microseconds] if {$startTime eq ""} { set startTime $::gStartTime } return [format "%.2g" [expr {($endTime - $startTime) / 1000000.0}]] } proc DemoSet {namespace file} { DemoClear TimerStart uplevel #0 ${namespace}::Init [DemoList] dbwin "set list in [TimerStop] seconds\n" [DemoList] xview moveto 0 [DemoList] yview moveto 0 update DisplayStylesInList SourceWindow::ShowSource $file catch { if {[winfo ismapped .styleEditor]} { StyleEditor::SetListOfStyles } } AddBindTag [DemoList] TagIdentify return } .f1.t notify bind .f1.t { if {%c == 1} { set item [%T selection get 0] DemoSet $DemoCmd($item) $DemoFile($item) } } proc DisplayStylesInList {} { set T [DemoList] set t .f4.t # Create elements and styles the first time this is called if {[llength [$t style names]] == 0} { $t element create e1 text -fill [list $::SystemHighlightText {selected focus}] $t element create e2 text -fill [list $::SystemHighlightText {selected focus} "" {selected !focus} blue {}] $t element create e3 rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ -showfocus yes $t style create s1 $t style elements s1 {e3 e1} $t style layout s1 e3 -union [list e1] -ipadx 1 -ipady {0 1} $t style create s2 $t style elements s2 {e3 e1 e2} $t style layout s2 e1 -padx {0 4} $t style layout s2 e3 -union [list e1 e2] -ipadx 1 -ipady {0 1} } # Clear the list $t item delete all # One item for each element in the demo list foreach elem [lsort -dictionary [$T element names]] { set item [$t item create -button yes -open no] $t item style set $item C0 s1 $t item text $item C0 "Element $elem ([$T element type $elem])" # One item for each configuration option for this element foreach list [$T element configure $elem] { lassign $list name x y default current set item2 [$t item create] if {[string equal $default $current]} { $t item style set $item2 C0 s1 $t item element configure $item2 C0 e1 -text [list $name $current] } else { $t item style set $item2 C0 s2 $t item element configure $item2 C0 e1 -text $name + e2 -text [list $current] } $t item lastchild $item $item2 } $t item lastchild root $item } # One item for each style in the demo list foreach style [lsort -dictionary [$T style names]] { set item [$t item create -button yes -open no] $t item style set $item C0 s1 $t item text $item C0 "Style $style" # One item for each element in the style foreach elem [$T style elements $style] { set item2 [$t item create -button yes -open no] $t item style set $item2 C0 s1 $t item text $item2 C0 "Element $elem ([$T element type $elem])" # One item for each layout option for this element in this style foreach {option value} [$T style layout $style $elem] { set item3 [$t item create] # $t item hasbutton $item3 no $t item style set $item3 C0 s1 $t item text $item3 C0 [list $option $value] $t item lastchild $item2 $item3 } $t item lastchild $item $item2 } $t item lastchild root $item } $t xview moveto 0 $t yview moveto 0 return } proc DisplayStylesInItem {item} { set T [DemoList] set t .f3.t $t column configure C0 -text "Styles in item [$T item id $item]" # Create elements and styles the first time this is called if {[llength [$t style names]] == 0} { $t element create e1 text -fill [list $::SystemHighlightText {selected focus}] $t element create e2 text -fill [list $::SystemHighlightText {selected focus} "" {selected !focus} blue {}] $t element create e3 rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ -showfocus yes $t style create s1 $t style elements s1 {e3 e1} $t style layout s1 e3 -union [list e1] -ipadx {1 2} -ipady {0 1} $t style create s2 $t style elements s2 {e3 e1 e2} $t style layout s2 e1 -padx {0 4} $t style layout s2 e3 -union [list e1 e2] -ipadx 1 -ipady {0 1} } # Clear the list $t item delete all # One item for each item-column foreach style [$T item style set $item] column [$T column list] { set item2 [$t item create -open no] $t item style set $item2 C0 s1 if {$style ne ""} { $t item element configure $item2 C0 e1 \ -text "Column $column: Style $style" } else { $t item element configure $item2 C0 e1 \ -text "Column $column: no style" } # One item for each element in this style if {[string length $style]} { set button 0 foreach elem [$T item style elements $item $column] { set button 1 set item3 [$t item create -button yes -open no] $t item style set $item3 C0 s1 $t item element configure $item3 C0 e1 \ -text "Element $elem ([$T element type $elem])" # One item for each configuration option in this element foreach list [$T item element configure $item $column $elem] { lassign $list name x y default current set item4 [$t item create] set masterDefault [$T element cget $elem $name] set sameAsMaster [string equal $masterDefault $current] if {!$sameAsMaster && ![string length $current]} { set sameAsMaster 1 set current $masterDefault } if {$sameAsMaster} { $t item style set $item4 C0 s1 $t item element configure $item4 C0 e1 -text "$name [list $current]" } else { $t item style set $item4 C0 s2 $t item element configure $item4 C0 e1 -text $name + e2 -text [list $current] } $t item lastchild $item3 $item4 } $t item lastchild $item2 $item3 } if {$button} { $t item configure $item2 -button yes } } $t item lastchild root $item2 } $t xview moveto 0 $t yview moveto 0 return } # When one item is selected in the demo list, display the styles in that item. # See DemoClear for why the tag "DontDelete" is used. set DisplayStylesInItem(item) "" set MouseIsDown 0 bind [DemoList] { set MouseIsDown 1 } bind [DemoList] { set MouseIsDown 0 if {$DisplayStylesInItem(item) ne ""} { DisplayStylesInItem $DisplayStylesInItem(item) set DisplayStylesInItem(item) "" } } [DemoList] notify bind DontDelete { if {%c == 1} { if {$MouseIsDown} { set DisplayStylesInItem(item) [%T selection get 0] } else { DisplayStylesInItem [%T selection get 0] } } } # Move columns when ColumnDrag-receive is generated. # See DemoClear for why the tag "DontDelete" is used. [DemoList] notify bind DontDelete { %T column move %C %b } proc DemoClear {} { set T [DemoList] # Delete all the items (except the root item, it never gets deleted). $T item delete all # Delete all the headers (except the first header, it never gets deleted). $T header delete all # Clear all bindings on the demo list added by the previous demo. # The bindings are removed from the tag $T only. For those # bindings that should not be deleted we use the tag DontDelete. # DontDelete is not a special name it just needs to be different # than $T. $T notify unbind $T # Clear all run-time states eval $T header state undefine [$T header state names] eval $T item state undefine [$T item state names] # Clear the styles-in-item list .f3.t item delete all # Delete columns in demo list $T column delete all # Delete all styles in demo list eval $T style delete [$T style names] # Delete all elements in demo list eval $T element delete [$T element names] # Delete -window windows foreach child [winfo children $T] { if {[string equal $child $T.mTree] || [string equal $child $T.mColumn]} continue destroy $child } # Restore defaults to marquee $T marquee configure -fill {} -outline {} -outlinewidth 1 # Delete gradients eval $T gradient delete [$T gradient names] $T item configure root -button no -wrap no $T item expand root # Restore header defaults foreach spec [$T header configure 0] { if {[llength $spec] == 2} continue lassign $spec name x y default current $T header configure all $name $default } # Restore some happy defaults to the demo list foreach spec [$T configure] { if {[llength $spec] == 2} continue lassign $spec name x y default current $T configure $name $default } $T configure -background white $T configure -borderwidth [expr {$::tileFull ? 0 : 6}] $T configure -font DemoFont if {[Platform unix]} { $T configure -headerfont DemoFont } $T configure -highlightthickness [expr {$::tileFull ? 0 : 3}] $T configure -relief ridge switch -- [$T theme platform] { visualstyles { $T theme setwindowtheme "" } } # Restore defaults to the tail column foreach spec [$T column configure tail] { if {[llength $spec] == 2} continue lassign $spec name x y default current $T column configure tail $name $default } # Enable drag-and-drop column reordering. This also requires the # event be installed. $T header dragconfigure -enable yes $T header dragconfigure all -enable yes -draw yes # Re-active the column drag-and-drop binding in case the previous demo # deactivated it. $T notify configure DontDelete -active yes # Restore default bindings to the demo list bindtags $T [list $T TreeCtrl [winfo toplevel $T] all DisplayStylesInItemBindTag] catch {destroy $T.entry} catch {destroy $T.text} return } # # Demo: Picture catalog # proc DemoPictureCatalog {} { set T [DemoList] $T configure -showroot no -showbuttons no -showlines no \ -selectmode multiple -orient horizontal -wrap window \ -yscrollincrement 50 -showheader no $T column create $T element create elemTxt text -fill {SystemHighlightText {selected focus}} $T element create elemSelTxt rect -fill {SystemHighlight {selected focus}} $T element create elemSelImg rect -outline {SystemHighlight {selected focus}} \ -outlinewidth 4 $T element create elemImg rect -fill gray -width 80 -height 120 set S [$T style create STYLE -orient vertical] $T style elements $S {elemSelImg elemImg elemSelTxt elemTxt} $T style layout $S elemSelImg -union elemImg -ipadx 6 -ipady 6 $T style layout $S elemSelTxt -union elemTxt $T style layout $S elemImg -pady {0 6} for {set i 1} {$i <= 10} {incr i} { set I [$T item create] $T item style set $I 0 $S $T item text $I 0 "Picture #$i" $T item lastchild root $I } return } # # Demo: Picture catalog # proc DemoPictureCatalog2 {} { set T [DemoList] $T configure -showroot no -showbuttons no -showlines no \ -selectmode multiple -orient horizontal -wrap window \ -yscrollincrement 50 -showheader no $T column create $T element create elemTxt text -fill {SystemHighlightText {selected focus}} \ -justify left -wrap word -lines 3 $T element create elemSelTxt rect -fill {SystemHighlight {selected focus}} $T element create elemSelImg rect -outline {SystemHighlight {selected focus}} \ -outlinewidth 4 $T element create elemImg rect -fill gray set S [$T style create STYLE -orient vertical] $T style elements $S {elemSelImg elemImg elemSelTxt elemTxt} $T style layout $S elemSelImg -union elemImg \ -ipadx 6 -ipady 6 $T style layout $S elemSelTxt -union elemTxt $T style layout $S elemImg -pady {0 6} $T style layout $S elemImg -expand n $T style layout $S elemTxt -expand s for {set i 1} {$i <= 10} {incr i} { set I [$T item create] $T item style set $I 0 $S $T item text $I 0 "This is\nPicture\n#$i" $T item element configure $I 0 elemImg -width [expr int(20 + rand() * 80)] \ -height [expr int(20 + rand() * 120)] $T item lastchild root $I } return } proc CursorWindow {} { set w .cursors if {[winfo exists $w]} { destroy $w } toplevel $w set c [canvas $w.canvas -background white -width [expr {50 * 10}] \ -highlightthickness 0 -borderwidth 0] pack $c -expand yes -fill both set cursors { X_cursor arrow based_arrow_down based_arrow_up boat bogosity bottom_left_corner bottom_right_corner bottom_side bottom_tee box_spiral center_ptr circle clock coffee_mug cross cross_reverse crosshair diamond_cross dot dotbox double_arrow draft_large draft_small draped_box exchange fleur gobbler gumby hand1 hand2 heart icon iron_cross left_ptr left_side left_tee leftbutton ll_angle lr_angle man middlebutton mouse pencil pirate plus question_arrow right_ptr right_side right_tee rightbutton rtl_logo sailboat sb_down_arrow sb_h_double_arrow sb_left_arrow sb_right_arrow sb_up_arrow sb_v_double_arrow shuttle sizing spider spraycan star target tcross top_left_arrow top_left_corner top_right_corner top_side top_tee trek ul_angle umbrella ur_angle watch xterm } set col 0 set row 0 foreach cursor $cursors { set x [expr {$col * 50}] set y [expr {$row * 40}] $c create rectangle $x $y [expr {$x + 50}] [expr {$y + 40}] \ -fill gray90 -outline black -width 2 -tags $cursor.rect $c create text [expr {$x + 50 / 2}] [expr {$y + 4}] -text $cursor \ -anchor n -width 42 -tags $cursor.text if {[incr col] == 10} { set col 0 incr row } $c bind $cursor.rect " $c configure -cursor $cursor $c itemconfigure $cursor.rect -fill linen " $c bind $cursor.rect " $c configure -cursor {} $c itemconfigure $cursor.rect -fill gray90 " $c bind $cursor.text " $c configure -cursor $cursor " $c bind $cursor.text " $c configure -cursor {} " } $c configure -height [expr {($row + 1) * 40}] return } # A little screen magnifier if {[llength [info commands loupe]]} { namespace eval LoupeWindow { variable Priv set Priv(zoom) 2 set Priv(x) 0 set Priv(y) 0 set Priv(auto) 1 set Priv(afterId) "" set Priv(image) ::LoupeWindow::Image set Priv(delay) 500 } proc LoupeWindow::After {} { variable Priv set x [winfo pointerx .] set y [winfo pointery .] if {$Priv(auto) || ($Priv(x) != $x) || ($Priv(y) != $y)} { set w [image width $Priv(image)] set h [image height $Priv(image)] loupe $Priv(image) $x $y $w $h $Priv(zoom) set Priv(x) $x set Priv(y) $y } set Priv(afterId) [after $Priv(delay) LoupeWindow::After] return } proc LoupeWindow::Init {} { variable Priv set w [toplevel .loupe] wm title $w "TreeCtrl Magnifier" wm withdraw $w if {[Platform macintosh macosx]} { wm geometry $w +6+30 } else { wm geometry $w -0+0 } image create photo $Priv(image) -width 280 -height 150 pack [label $w.label -image $Priv(image) -borderwidth 1 -relief sunken] \ -expand yes -fill both set f [frame $w.zoom -borderwidth 0] radiobutton $f.r1 -text "1x" -variable ::LoupeWindow::Priv(zoom) -value 1 radiobutton $f.r2 -text "2x" -variable ::LoupeWindow::Priv(zoom) -value 2 radiobutton $f.r4 -text "4x" -variable ::LoupeWindow::Priv(zoom) -value 4 radiobutton $f.r8 -text "8x" -variable ::LoupeWindow::Priv(zoom) -value 8 pack $f.r1 $f.r2 $f.r4 $f.r8 -side left pack $f -side bottom -anchor center # Resize the image with the window bind LoupeWindow { LoupeWindow::ResizeImage %w %h } bindtags $w.label [concat [bindtags .loupe] LoupeWindow] wm protocol $w WM_DELETE_WINDOW "LoupeWindow::ToggleWindowVisibility" return } proc LoupeWindow::ResizeImage {w h} { variable Priv set w [expr {$w - 2}] set h [expr {$h - 2}] if {$w != [$Priv(image) cget -width] || $h != [$Priv(image) cget -height]} { $Priv(image) configure -width $w -height $h loupe $Priv(image) $Priv(x) $Priv(y) $w $h $Priv(zoom) } return } proc LoupeWindow::ToggleWindowVisibility {} { variable Priv set w .loupe if {![winfo exists $w]} { LoupeWindow::Init } if {[winfo ismapped $w]} { after cancel $Priv(afterId) wm withdraw $w } else { After wm deiconify $w raise $w } return } } proc RandomPerfTest {} { set ::RandomN 15000 DemoSet DemoRandom random.tcl [DemoList] item expand all [DemoList] style layout styFolder elemTxtName -squeeze x [DemoList] style layout styFile elemTxtName -squeeze x [DemoList] elem conf elemTxtName -lines 1 update puts [time {[DemoList] colu conf 0 -width 160 ; update}] return } tktreectrl-2.4.1/demos/explorer.tcl0000644000076400010400000012110211573564254017677 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker set Dir [file dirname [file dirname [info script]]] set shellicon 0 # Might work on other windows versions, but only tested on XP and Win7 if {$tcl_platform(os) eq "Windows NT" && ($tcl_platform(osVersion) == 5.1 || $tcl_platform(osVersion) == 6.1)} { catch { lappend auto_path $treectrl_library package require shellicon $VERSION set shellicon 1 } } set macBitmap 0 if {[info commands ::tk::mac::iconBitmap] ne {}} { set macBitmap 1 } namespace eval DemoExplorer {} # DemoExplorer::SetList # # Gets sorted lists of directory and file names in the ::Dir directory and # calls a script to add items to the demo list. # # Arguments: # scriptDir Script to eval to add directories to the demo list. # scriptFile Script to eval to add files to the demo list. # scriptFollowup Script to eval after the first two. proc DemoExplorer::SetList {T scriptDir scriptFile {scriptFollowup ""}} { variable Priv global Dir TimerStart set globDirs [glob -nocomplain -types d -dir $Dir *] set secondsGlobDirs [TimerStop] TimerStart set list [lsort -dictionary $globDirs] set secondsSortDirs [TimerStop] if {[file dirname $Dir] ne $Dir} { lappend globDirs ".." set list [concat ".." $list] } TimerStart foreach file $list $scriptDir set secondsAddDirs [TimerStop] $T item tag add "root children" directory TimerStart set globFiles [glob -nocomplain -types f -dir $Dir *] set secondsGlobFiles [TimerStop] TimerStart set list [lsort -dictionary $globFiles] set secondsSortFiles [TimerStop] TimerStart foreach file $list $scriptFile set secondsAddFiles [TimerStop] set gd $secondsGlobDirs set sd $secondsSortDirs set ad $secondsAddDirs set gf $secondsGlobFiles set sf $secondsSortFiles set af $secondsAddFiles puts "dirs([llength $globDirs]) glob/sort/add $gd/$sd/$ad\nfiles([llength $globFiles]) glob/sort/add $gf/$sf/$af" # Accessing a private variable in the filelist-bindings.tcl library script. # Most of the code in that file should have been a part of this demo. set ::TreeCtrl::Priv(DirCnt,$T) [llength $globDirs] eval $scriptFollowup # Double-clicking a directory displays its contents. set Priv(scriptDir) $scriptDir set Priv(scriptFile) $scriptFile set Priv(scriptFollowup) $scriptFollowup return } # DemoExplorer::SetBindings # # Sets some bindings on the demo list. # # Arguments: # T The demo list. # win7 Boolean, true if Windows 7 behavior is desired. proc DemoExplorer::SetBindings {T {win7 0}} { variable Priv # Double-clicking a directory displays its contents. bind DemoExplorer { DemoExplorer::DoubleButton1 %W %x %y } TreeCtrl::FileListEmulateWin7 $T $win7 if {$win7} { set Priv(prev) "" $T notify bind $T { if {[lsearch -exact %i $DemoExplorer::Priv(prev)] != -1} { set DemoExplorer::Priv(prev) "" } } bind DemoExplorerWin7 { DemoExplorer::Motion %W %x %y } bind DemoExplorerWin7 { DemoExplorer::Motion %W -1 -1 } } return } # # Demo: explorer files # namespace eval DemoExplorerDetails { proc Init {T} { DemoExplorer::InitDetails $T } } proc DemoExplorer::InitDetails {T} { variable Priv set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no -itemheight $height \ -selectmode extended -xscrollincrement 20 -xscrollsmoothing yes \ -scrollmargin 16 -xscrolldelay "500 50" -yscrolldelay "500 50" InitPics small-* # # Create columns # $T column create -text Name -tags {C0 name} -width 200 \ -arrow up -itembackground #F7F7F7 $T column create -text Size -tags size -justify right -width 60 \ -arrowside left -arrowgravity right $T column create -text Type -tags type -width 120 $T column create -text Modified -tags modified -width 120 # Demonstration of per-state column options and configure "all" $T column configure all -background {gray90 active gray70 normal gray50 pressed} # # Create elements # if {$::shellicon} { $T element create elemImg shellicon -size small } elseif {$::macBitmap} { $T element create elemImg bitmap } else { $T element create elemImg image -image {small-folderSel {selected} small-folder {}} } $T element create txtName text -fill [list $::SystemHighlightText {selected focus}] \ -lines 1 $T element create txtType text -lines 1 $T element create txtSize text -datatype integer -format "%dKB" -lines 1 $T element create txtDate text -datatype time -format "%d/%m/%y %I:%M %p" -lines 1 $T element create elemRectSel rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] -showfocus yes # # Create styles using the elements # # column 0: image + text set S [$T style create styName -orient horizontal] $T style elements $S {elemRectSel elemImg txtName} $T style layout $S elemImg -padx {2 0} -expand ns $T style layout $S txtName -squeeze x -expand ns $T style layout $S elemRectSel -union [list txtName] -ipadx 2 -iexpand ns # column 1: text set S [$T style create stySize] $T style elements $S txtSize $T style layout $S txtSize -padx 6 -squeeze x -expand ns # column 2: text set S [$T style create styType] $T style elements $S txtType $T style layout $S txtType -padx 6 -squeeze x -expand ns # column 3: text set S [$T style create styDate] $T style elements $S txtDate $T style layout $S txtDate -padx 6 -squeeze x -expand ns # List of lists: {column style element ...} specifying text elements # the user can edit. TreeCtrl::SetEditable $T { {name styName txtName} } # List of lists: {column style element ...} specifying elements # the user can click on. TreeCtrl::SetSensitive $T { {name styName elemImg txtName} } # List of lists: {column style element ...} specifying elements # the user can select with the selection rectangle. Empty means # use the same list passed to TreeCtrl::SetSensitive. TreeCtrl::SetSensitiveMarquee $T {} # List of lists: {column style element ...} specifying elements # added to the drag image when dragging selected items TreeCtrl::SetDragImage $T { {name styName elemImg txtName} } # During editing, hide the text and selection-rectangle elements. $T item state define edit $T style layout styName txtName -draw {no edit} $T style layout styName elemRectSel -draw {no edit} $T notify bind $T { %T item state set %I ~edit } $T notify bind $T { %T item element configure %I %C %E -text %t } $T notify bind $T { %T item state set %I ~edit } # # Create items and assign styles # set scriptDir { set item [$T item create -open no] $T item style set $item name styName type styType modified styDate $T item element configure $item \ name txtName -text [file tail $file] , \ type txtType -text "Folder" , \ modified txtDate -data [file mtime $file] if {$::shellicon} { # The shellicon extension fails randomly (by putting GDB into the # background!?) if the filename is not valid. MSDN says "relative # paths are valid" but perhaps that is misinformation. if {$file eq ".."} { set file [file dirname $::Dir] } $T item element configure $item \ name elemImg -path $file } if {$::macBitmap} { if {$file eq ".."} { set file [file dirname $::Dir] } ::tk::mac::iconBitmap $file 16 16 -file $file $T item element configure $item \ name elemImg -bitmap [list $file] } $T item lastchild root $item } set scriptFile { set item [$T item create -open no] $T item style set $item name styName size stySize type styType modified styDate switch [file extension $file] { .dll { set img small-dll } .exe { set img small-exe } .txt { set img small-txt } default { set img small-file } } set type [string toupper [file extension $file]] if {$type ne ""} { set type "[string range $type 1 end] " } append type "File" if {$::shellicon} { $T item element configure $item \ name elemImg -path $file + txtName -text [file tail $file] , \ size txtSize -data [expr {[file size $file] / 1024 + 1}] , \ type txtType -text $type , \ modified txtDate -data [file mtime $file] } elseif {$::macBitmap} { if {$file eq ".."} { set file [file dirname $::Dir] } ::tk::mac::iconBitmap $file 16 16 -file $file $T item element configure $item \ name elemImg -bitmap [list $file] + txtName -text [file tail $file] , \ size txtSize -data [expr {[file size $file] / 1024 + 1}] , \ type txtType -text $type , \ modified txtDate -data [file mtime $file] } else { $T item element configure $item \ name elemImg -image [list ${img}Sel {selected} $img {}] + txtName -text [file tail $file] , \ size txtSize -data [expr {[file size $file] / 1024 + 1}] , \ type txtType -text $type , \ modified txtDate -data [file mtime $file] } $T item lastchild root $item } SetList $T $scriptDir $scriptFile SetBindings $T set Priv(sortColumn) name set Priv(sortColor) #F7F7F7 $T notify bind $T { DemoExplorer::HeaderInvoke %T %C } bindtags $T [list $T DemoExplorer TreeCtrlFileList TreeCtrl [winfo toplevel $T] all] return } # DemoExplorer::HeaderInvoke # # This procedure is called to handle the event generated by # the treectrl.tcl library script. Items in the demo list are sorted # according to the column involved. # # Arguments: # T The demo list. # C The column whose header was clicked. proc DemoExplorer::HeaderInvoke {T C} { variable Priv if {[$T column compare $C == $Priv(sortColumn)]} { if {[$T column cget $Priv(sortColumn) -arrow] eq "down"} { set order -increasing set arrow up } else { set order -decreasing set arrow down } } else { if {[$T column cget $Priv(sortColumn) -arrow] eq "down"} { set order -decreasing set arrow down } else { set order -increasing set arrow up } $T column configure $Priv(sortColumn) -arrow none -itembackground {} set Priv(sortColumn) $C } $T column configure $C -arrow $arrow -itembackground $Priv(sortColor) set dirCount $::TreeCtrl::Priv(DirCnt,$T) set fileCount [expr {[$T item count] - 1 - $dirCount}] set lastDir [expr {$dirCount - 1}] switch -glob [$T column cget $C -tags] { *name* { if {$dirCount} { $T item sort root $order -last "root child $lastDir" -column $C -dictionary } if {$fileCount} { $T item sort root $order -first "root child $dirCount" -column $C -dictionary } } size { if {$fileCount} { $T item sort root $order -first "root child $dirCount" -column $C -integer -column name -dictionary } } type { if {$fileCount} { $T item sort root $order -first "root child $dirCount" -column $C -dictionary -column name -dictionary } } modified { if {$dirCount} { $T item sort root $order -last "root child $lastDir" -column $C -integer -column name -dictionary } if {$fileCount} { $T item sort root $order -first "root child $dirCount" -column $C -integer -column name -dictionary } } } return } namespace eval DemoExplorerLargeIcons { proc Init {T} { DemoExplorer::InitLargeIcons $T } } proc DemoExplorer::InitLargeIcons {T} { # Item height is 32 for icon, 4 padding, 3 lines of text set itemHeight [expr {32 + 4 + [font metrics [$T cget -font] -linespace] * 3}] # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no \ -selectmode extended -wrap window -orient horizontal \ -itemheight $itemHeight -itemwidth 75 -showheader no \ -scrollmargin 16 -xscrolldelay "500 50" -yscrolldelay "500 50" InitPics big-* # # Create columns # $T column create -tags C0 # # Create elements # if {$::shellicon} { $T element create elemImg shellicon -size large } elseif {$::macBitmap} { $T element create elemImg bitmap } else { $T element create elemImg image -image {big-folderSel {selected} big-folder {}} } $T element create elemTxt text -fill [list $::SystemHighlightText {selected focus}] \ -justify center -lines 1 -width 71 -wrap word $T element create elemSel rect -fill [list $::SystemHighlight {selected focus} gray {selected}] -showfocus yes # # Create styles using the elements # # image + text set S [$T style create STYLE -orient vertical] $T style elements $S {elemSel elemImg elemTxt} $T style layout $S elemImg -expand we $T style layout $S elemTxt -pady {4 0} -squeeze x -expand we $T style layout $S elemSel -union [list elemTxt] -ipadx 2 # List of lists: {column style element ...} specifying text elements # the user can edit TreeCtrl::SetEditable $T { {C0 STYLE elemTxt} } # List of lists: {column style element ...} specifying elements # the user can click on. TreeCtrl::SetSensitive $T { {C0 STYLE elemImg elemTxt} } # List of lists: {column style element ...} specifying elements # the user can select with the selection rectangle. Empty means # use the same list passed to TreeCtrl::SetSensitive. TreeCtrl::SetSensitiveMarquee $T {} # List of lists: {column style element ...} specifying elements # added to the drag image when dragging selected items. TreeCtrl::SetDragImage $T { {C0 STYLE elemImg elemTxt} } # During editing, hide the text and selection-rectangle elements. $T item state define edit $T style layout STYLE elemTxt -draw {no edit} $T style layout STYLE elemSel -draw {no edit} $T notify bind $T { %T item state set %I ~edit } $T notify bind $T { %T item element configure %I %C %E -text %t } $T notify bind $T { %T item state set %I ~edit } # # Create items and assign styles # set scriptDir { set item [$T item create -open no] $T item style set $item C0 STYLE $T item text $item C0 [file tail $file] if {$::shellicon} { # The shellicon extension fails randomly (by putting GDB into the # background!?) if the filename is not valid. MSDN says "relative # paths are valid" but perhaps that is misinformation. if {$file eq ".."} { set file [file dirname $::Dir] } $T item element configure $item C0 \ elemImg -path $file } if {$::macBitmap} { if {$file eq ".."} { set file [file dirname $::Dir] } ::tk::mac::iconBitmap $file 32 32 -file $file $T item element configure $item C0 \ elemImg -bitmap [list $file] } $T item lastchild root $item } set scriptFile { set item [$T item create -open no] $T item style set $item C0 STYLE switch [file extension $file] { .dll { set img big-dll } .exe { set img big-exe } .txt { set img big-txt } default { set img big-file } } set type [string toupper [file extension $file]] if {$type ne ""} { set type "[string range $type 1 end] " } append type "File" if {$::shellicon} { $T item element configure $item C0 \ elemImg -path $file + \ elemTxt -text [file tail $file] } elseif {$::macBitmap} { ::tk::mac::iconBitmap $file 32 32 -file $file $T item element configure $item C0 \ elemImg -bitmap [list $file] + \ elemTxt -text [file tail $file] } else { $T item element configure $item C0 \ elemImg -image [list ${img}Sel {selected} $img {}] + \ elemTxt -text [file tail $file] } $T item lastchild root $item } SetList $T $scriptDir $scriptFile SetBindings $T $T activate [$T item id "root firstchild"] $T notify bind $T { if {[%T item compare %p != root]} { %T item element configure %p C0 elemTxt -lines {} } if {[%T item compare %c != root]} { %T item element configure %c C0 elemTxt -lines 3 } } $T item element configure active C0 elemTxt -lines 3 bindtags $T [list $T DemoExplorer TreeCtrlFileList TreeCtrl [winfo toplevel $T] all] return } # Tree is horizontal, wrapping occurs at right edge of window, each item # is as wide as the smallest needed multiple of 110 pixels namespace eval DemoExplorerSmallIcons { proc Init {T} { DemoExplorer::InitSmallIcons $T } } proc DemoExplorer::InitSmallIcons {T} { InitList $T $T configure -orient horizontal \ -itemwidthmultiple 110 -itemwidthequal no return } # Tree is vertical, wrapping occurs at bottom of window, each range has the # same width (as wide as the longest item), xscrollincrement is by range namespace eval DemoExplorerList { proc Init {T} { DemoExplorer::InitList $T } } proc DemoExplorer::InitList {T} { set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no -itemheight $height \ -selectmode extended -wrap window -showheader no \ -scrollmargin 16 -xscrolldelay "500 50" -yscrolldelay "500 50" \ -itemwidthequal yes InitPics small-* # # Create columns # $T column create -tags C0 # # Create elements # if {$::shellicon} { $T element create elemImg shellicon -size small } elseif {$::macBitmap} { $T element create elemImg bitmap } else { $T element create elemImg image -image {small-folderSel {selected} small-folder {}} } $T element create elemTxt text -fill [list $::SystemHighlightText {selected focus}] \ -lines 1 $T element create elemSel rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] -showfocus yes # # Create styles using the elements # # image + text set S [$T style create STYLE] $T style elements $S {elemSel elemImg elemTxt} $T style layout $S elemImg -expand ns $T style layout $S elemTxt -squeeze x -expand ns -padx {2 0} $T style layout $S elemSel -union [list elemTxt] -iexpand ns -ipadx 2 # List of lists: {column style element ...} specifying text elements # the user can edit TreeCtrl::SetEditable $T { {C0 STYLE elemTxt} } # List of lists: {column style element ...} specifying elements # the user can click on. TreeCtrl::SetSensitive $T { {C0 STYLE elemImg elemTxt} } # List of lists: {column style element ...} specifying elements # the user can select with the selection rectangle. Empty means # use the same list passed to TreeCtrl::SetSensitive. TreeCtrl::SetSensitiveMarquee $T {} # List of lists: {column style element ...} specifying elements # added to the drag image when dragging selected items. TreeCtrl::SetDragImage $T { {C0 STYLE elemImg elemTxt} } # During editing, hide the text and selection-rectangle elements. $T item state define edit $T style layout STYLE elemTxt -draw {no edit} $T style layout STYLE elemSel -draw {no edit} $T notify bind $T { %T item state set %I ~edit } $T notify bind $T { %T item element configure %I %C %E -text %t } $T notify bind $T { %T item state set %I ~edit } # # Create items and assign styles # set scriptDir { set item [$T item create -open no] $T item style set $item C0 STYLE $T item text $item C0 [file tail $file] if {$::shellicon} { # The shellicon extension fails randomly (by putting GDB into the # background!?) if the filename is not valid. MSDN says "relative # paths are valid" but perhaps that is misinformation. if {$file eq ".."} { set file [file dirname $::Dir] } $T item element configure $item C0 \ elemImg -path $file } if {$::macBitmap} { if {$file eq ".."} { set file [file dirname $::Dir] } ::tk::mac::iconBitmap $file 16 16 -file $file $T item element configure $item C0 \ elemImg -bitmap [list $file] } $T item lastchild root $item } set scriptFile { set item [$T item create -open no] $T item style set $item C0 STYLE switch [file extension $file] { .dll { set img small-dll } .exe { set img small-exe } .txt { set img small-txt } default { set img small-file } } set type [string toupper [file extension $file]] if {$type ne ""} { set type "[string range $type 1 end] " } append type "File" if {$::shellicon} { $T item element configure $item C0 \ elemImg -path $file + \ elemTxt -text [file tail $file] } elseif {$::macBitmap} { ::tk::mac::iconBitmap $file 16 16 -file $file $T item element configure $item C0 \ elemImg -bitmap [list $file] + \ elemTxt -text [file tail $file] } else { $T item element configure $item C0 \ elemImg -image [list ${img}Sel {selected} $img {}] + \ elemTxt -text [file tail $file] } $T item lastchild root $item } SetList $T $scriptDir $scriptFile SetBindings $T $T activate [$T item firstchild root] bindtags $T [list $T DemoExplorer TreeCtrlFileList TreeCtrl [winfo toplevel $T] all] return } # DemoExplorer::DoubleButton1 # # Handle the event in the demo list. If a directory # item is double-clicked, display that directory. # # Arguments: # T The demo list. # x Widget x coordinate. # y Widget y coordinate. proc DemoExplorer::DoubleButton1 {T x y} { variable Priv global Dir $T identify -array id $x $y set sensitive [TreeCtrl::IsSensitive $T $x $y] if {[TreeCtrl::FileListEmulateWin7 $T] && [TreeCtrl::IsSensitiveMarquee $T $x $y]} { set sensitive 1 } if {$sensitive} { set item $id(item) set column $id(column) if {[$T item tag expr $item directory]} { set name [$T item text $item {tag C0}] if {$name eq ".."} { set Dir [file dirname $Dir] } else { set Dir [file join $Dir $name] } $T item delete all SetList $T $Priv(scriptDir) $Priv(scriptFile) $Priv(scriptFollowup) if {![TreeCtrl::FileListEmulateWin7 $T]} { $T activate "root firstchild" } $T xview moveto 0.0 $T yview moveto 0.0 } } return } # DemoExplorer::DragStyleInit # # NOT USED. # Experimental code to create a style that is used with drag-and-drop proc DemoExplorer::DragStyleInit {} { set T [DemoList] set boxW 100 set boxH 100 set imgW 32 set imgH 32 $T element create DragStyleElemRect rect -fill #D0ffff -width $boxW -height $boxH $T element create DragStyleElemImg image -image big-file $T element create DragStyleElemTxt text -text DragImage! $T element create DragStyleElemTxtBg rect -fill white -outline black -outlinewidth 1 $T style create DragStyle -orient vertical $T style elements DragStyle {DragStyleElemRect DragStyleElemImg DragStyleElemTxtBg DragStyleElemTxt} set cursorW 16 $T style layout DragStyle DragStyleElemRect -detach yes set dx [expr {($boxW - $imgW) / 2}] set dy [expr {($boxH - $imgH) / 2}] $T style layout DragStyle DragStyleElemImg -detach yes -padx "$dx 0" -pady "$dy 0" set dx [expr {$boxW / 2 + $cursorW}] set dy $boxH $T style layout DragStyle DragStyleElemTxt -detach yes -padx "$dx 0" -pady "$dy 0" $T style layout DragStyle DragStyleElemTxtBg -union DragStyleElemTxt -ipadx 3 -ipady 2 $T dragimage configure -style DragStyle set x [expr {$boxW / 2 - 0 * $cursorW / 2}] set y [expr {$boxH - $cursorW * 2/3}] $T dragimage stylehotspot $x $y return } # DemoExplorer::ConfigTransparentMarquee # # Configure the marquee for a modern transparent selection rectangle # where transparent gradients are supported. # # Arguments: # T The demo list. proc DemoExplorer::ConfigTransparentMarquee {T} { if {!$::NativeGradients} return if {![$T gradient native]} return if {[winfo depth $T] < 15} return set outline #3399ff set stops [list [list 0.0 #3399ff 0.3] [list 1.0 #3399ff 0.3]] $T gradient create G_marquee -stops $stops $T marquee configure -fill G_marquee -outline $outline return } # # Demo: explorer files with Windows-7-like gradients # namespace eval DemoExplorerDetailsWin7 { proc Init {T} { DemoExplorer::InitDetailsWin7 $T } } proc DemoExplorer::InitDetailsWin7 {T} { variable Priv set height [font metrics [$T cget -font] -linespace] if {$height < 16} { set height 16 ; # small icon height } incr height 5 # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no -itemheight $height \ -selectmode extended -xscrollincrement 20 -xscrollsmoothing yes \ -scrollmargin 16 -xscrolldelay "500 50" -yscrolldelay "500 50" $T configure -canvaspadx {12 0} -canvaspady {6 0} InitPics small-* # # Create columns # $T column create -text Name -tags {C0 name} -width 200 \ -arrow up $T column create -text Size -tags size -justify right -width 60 \ -arrowside left -arrowgravity right $T column create -text Type -tags type -width 120 $T column create -text Modified -tags modified -width 120 # Demonstration of per-state column options and configure "all" $T column configure all -background {gray90 active gray70 normal gray50 pressed} # # Create gradients # set steps [expr {($height - 5)/2}] $T gradient create G_mouseover -steps $steps -stops {{0.0 white} {1.0 #ebf3fd}} -orient vertical $T gradient create G_selected_active -steps $steps -stops {{0.0 #dcebfc} {1.0 #c1dbfc}} -orient vertical $T gradient create G_selected -steps $steps -stops {{0.0 #ebf4fe} {1.0 #cfe4fe}} -orient vertical $T gradient create G_focusout -steps $steps -stops {{0.0 #f8f8f8} {1.0 #e5e5e5}} -orient vertical # With gdiplus this gives similar results # $T gradient configure G_mouseover -stops {{0.0 SystemHighlight 0.0} {1.0 SystemHighlight 0.1}} -orient vertical # # Create elements # if {$::shellicon} { $T element create elemImg shellicon -size small -useselected never } elseif {$::macBitmap} { $T element create elemImg bitmap } else { $T element create elemImg image -image small-folder } $T element create txtName text -lines 1 $T element create txtType text -lines 1 -fill #6d6d6d $T element create txtSize text -datatype integer -format "%dKB" -lines 1 -fill #6d6d6d $T element create txtDate text -datatype time -format "%d/%m/%y %I:%M %p" -lines 1 -fill #6d6d6d $T item state define mouseover $T item state define openW $T item state define openE $T item state define openWE $T element create elemRectGradient rect \ -fill [list G_selected_active {selected mouseover} \ G_focusout {selected !focus} \ G_selected_active {selected active} \ G_selected selected \ G_mouseover mouseover] $T element create elemRectOutline rect -rx 1 \ -open [list we openWE w openW e openE] \ -outline [list #7da2ce {selected mouseover} \ #d9d9d9 {selected !focus} \ #7da2ce selected \ #7da2ce {active focus} \ #b8d6fb mouseover] -outlinewidth 1 # # Create styles using the elements # # column 0: image + text set S [$T style create styName -orient horizontal] $T style elements $S {elemRectGradient elemRectOutline elemImg txtName} $T style layout $S elemRectGradient -detach yes -padx {2 0} -pady {2 3} -iexpand xy $T style layout $S elemRectOutline -detach yes -pady {0 1} -iexpand xy $T style layout $S elemImg -padx {6 2} -pady {2 3} -expand ns $T style layout $S txtName -pady {2 3} -squeeze x -expand ns # column 1: text set S [$T style create stySize] $T style elements $S {elemRectGradient elemRectOutline txtSize} $T style layout $S elemRectGradient -detach yes -padx 0 -pady {2 3} -iexpand xy $T style layout $S elemRectOutline -detach yes -pady {0 1} -iexpand xy $T style layout $S txtSize -padx 6 -pady {2 3} -squeeze x -expand ns # column 2: text set S [$T style create styType] $T style elements $S {elemRectGradient elemRectOutline txtType} $T style layout $S elemRectGradient -detach yes -padx 0 -pady {2 3} -iexpand xy $T style layout $S elemRectOutline -detach yes -pady {0 1} -iexpand xy $T style layout $S txtType -padx 6 -pady {2 3} -squeeze x -expand ns # column 3: text set S [$T style create styDate] $T style elements $S {elemRectGradient elemRectOutline txtDate} $T style layout $S elemRectGradient -detach yes -padx {0 2} -pady {2 3} -iexpand xy $T style layout $S elemRectOutline -detach yes -pady {0 1} -iexpand xy $T style layout $S txtDate -padx 6 -pady {2 3} -squeeze x -expand ns # List of lists: {column style element ...} specifying text elements # the user can edit. TreeCtrl::SetEditable $T { {name styName txtName} } # List of lists: {column style element ...} specifying elements # the user can click on. TreeCtrl::SetSensitive $T { {name styName elemImg txtName} {size stySize txtSize} {type styType txtType} {modified styDate txtDate} } # List of lists: {column style element ...} specifying elements # the user can select with the selection rectangle. Empty means # use the same list passed to TreeCtrl::SetSensitive. TreeCtrl::SetSensitiveMarquee $T { {name styName elemRectOutline elemImg txtName} {size stySize elemRectOutline txtSize} {type styType elemRectOutline txtType} {modified styDate elemRectOutline txtDate} } # List of lists: {column style element ...} specifying elements # added to the drag image when dragging selected items. TreeCtrl::SetDragImage $T { {name styName elemImg txtName} } # During editing, hide the text $T item state define edit $T style layout styName txtName -draw {no edit} $T notify bind $T { %T item state set %I ~edit } $T notify bind $T { %T item element configure %I %C %E -text %t } $T notify bind $T { %T item state set %I ~edit } # # Create items and assign styles # set scriptDir { set item [$T item create -open no] $T item style set $item name styName size stySize type styType modified styDate $T item element configure $item \ name txtName -text [file tail $file] , \ type txtType -text "Folder" , \ modified txtDate -data [file mtime $file] if {$::shellicon} { # The shellicon extension fails randomly (by putting GDB into the # background!?) if the filename is not valid. MSDN says "relative # paths are valid" but perhaps that is misinformation. if {$file eq ".."} { set file [file dirname $::Dir] } $T item element configure $item \ name elemImg -path $file } if {$::macBitmap} { if {$file eq ".."} { set file [file dirname $::Dir] } ::tk::mac::iconBitmap $file 16 16 -file $file $T item element configure $item \ name elemImg -bitmap [list $file] } $T item lastchild root $item } set scriptFile { set item [$T item create -open no] $T item style set $item name styName size stySize type styType modified styDate switch [file extension $file] { .dll { set img small-dll } .exe { set img small-exe } .txt { set img small-txt } default { set img small-file } } set type [string toupper [file extension $file]] if {$type ne ""} { set type "[string range $type 1 end] " } append type "File" if {$::shellicon} { $T item element configure $item \ name elemImg -path $file + txtName -text [file tail $file] , \ size txtSize -data [expr {[file size $file] / 1024 + 1}] , \ type txtType -text $type , \ modified txtDate -data [file mtime $file] } elseif {$::macBitmap} { ::tk::mac::iconBitmap $file 16 16 -file $file $T item element configure $item \ name elemImg -bitmap [list $file] + txtName -text [file tail $file] , \ size txtSize -data [expr {[file size $file] / 1024 + 1}] , \ type txtType -text $type , \ modified txtDate -data [file mtime $file] } else { $T item element configure $item \ name elemImg -image $img + txtName -text [file tail $file] , \ size txtSize -data [expr {[file size $file] / 1024 + 1}] , \ type txtType -text $type , \ modified txtDate -data [file mtime $file] } $T item lastchild root $item } set scriptFollowup { DemoExplorer::DetailsWin7_FixItemStyles $T } SetList $T $scriptDir $scriptFile $scriptFollowup SetBindings $T true ConfigTransparentMarquee $T # Fix the display when a column is dragged $T notify bind $T { %T column move %C %b DemoExplorer::DetailsWin7_FixItemStyles %T } # Fix the display when a column's visibility changes $T notify bind $T { DemoExplorer::DetailsWin7_FixItemStyles %T } set Priv(sortColumn) name set Priv(sortColor) "" $T notify bind $T { DemoExplorer::HeaderInvoke %T %C } bindtags $T [list $T DemoExplorerWin7 DemoExplorer TreeCtrlFileList TreeCtrl [winfo toplevel $T] all] return } # DemoExplorer::DetailsWin7_FixItemStyles # # Configures item states and style layouts so that selection rectangles # appear to span multiple columns. # # Arguments: # T The demo list. proc DemoExplorer::DetailsWin7_FixItemStyles {T} { foreach C [$T column id "visible !tail"] { if {[$T column compare $C == "first visible"]} { set padx {2 0} set state openE } elseif {[$T column compare $C == "last visible"]} { set padx {0 2} set state openW } else { set padx {0 0} set state openWE } switch -glob [$T column cget $C -tags] { *name* { set style styName set padelem elemImg set padelemX {6 2} } size { set style stySize } type { set style styType } modified { set style styDate } } $T item state forcolumn all $C [list !openW !openE !openWE $state] $T style layout $style elemRectGradient -padx $padx } return } namespace eval DemoExplorerLargeIconsWin7 { proc Init {T} { DemoExplorer::InitLargeIconsWin7 $T } } proc DemoExplorer::InitLargeIconsWin7 {T} { # Item height is 2 + 32 for icon + 4 pad + 3 lines of text + 3 set fontHeight [font metrics [$T cget -font] -linespace] set itemHeight [expr {2 + 32 + 4 + $fontHeight * 3 + 3}] # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no \ -selectmode extended -wrap window -orient horizontal \ -itemwidth 74 -showheader no -yscrollsmoothing yes \ -scrollmargin 16 -yscrolldelay "500 200" $T configure -canvaspadx {15 0} -canvaspady {6 0} -itemgapx 1 -itemgapy 1 InitPics big-* # # Create columns # $T column create -tags C0 # # Create gradients # set steps 8 $T gradient create G_mouseover -steps $steps -stops {{0.0 white} {1.0 #ebf3fd}} -orient vertical $T gradient create G_selected_active -steps $steps -stops {{0.0 #dcebfc} {1.0 #c1dbfc}} -orient vertical $T gradient create G_selected -steps $steps -stops {{0.0 #ebf4fe} {1.0 #cfe4fe}} -orient vertical $T gradient create G_focusout -steps $steps -stops {{0.0 #f8f8f8} {1.0 #e5e5e5}} -orient vertical # # Create elements # $T item state define mouseover $T item state define openW $T item state define openE $T item state define openWE $T element create elemRectGradient rect \ -fill [list G_selected_active {selected mouseover} \ G_focusout {selected !focus} \ G_selected_active {selected active} \ G_selected selected \ G_mouseover mouseover] $T element create elemRectOutline rect -rx 3 \ -open [list we openWE w openW e openE] \ -outline [list #7da2ce {selected mouseover} \ #d9d9d9 {selected !focus} \ #7da2ce selected \ #7da2ce {active focus} \ #b8d6fb mouseover] -outlinewidth 1 if {$::shellicon} { $T element create elemImg shellicon -size large -useselect never } elseif {$::macBitmap} { $T element create elemImg bitmap } else { $T element create elemImg image -image big-folder } $T element create elemTxt text \ -justify center -lines 3 -width 70 -wrap word # # Create styles using the elements # # image + text set S [$T style create STYLE -orient vertical] $T style elements $S {elemRectGradient elemRectOutline elemImg elemTxt} $T style layout $S elemRectGradient -union {elemImg elemTxt} -iexpand we $T style layout $S elemRectOutline -union elemRectGradient -ipadx 2 -ipady 2 $T style layout $S elemImg -expand we $T style layout $S elemTxt -pady {4 0} -squeeze x -expand we # List of lists: {column style element ...} specifying text elements # the user can edit. TreeCtrl::SetEditable $T { {C0 STYLE elemTxt} } # List of lists: {column style element ...} specifying elements # the user can click on. TreeCtrl::SetSensitive $T { {C0 STYLE elemImg elemTxt} } # List of lists: {column style element ...} specifying elements # the user can select with the selection rectangle. Empty means # use the same list passed to TreeCtrl::SetSensitive. TreeCtrl::SetSensitiveMarquee $T { {C0 STYLE elemRectOutline elemImg elemTxt} } # List of lists: {column style element ...} specifying elements # added to the drag image when dragging selected items. TreeCtrl::SetDragImage $T { {C0 STYLE elemImg elemTxt} } # During editing, hide the text and selection-rectangle elements. $T item state define edit $T style layout STYLE elemTxt -draw {no edit} $T notify bind $T { %T item state set %I ~edit } $T notify bind $T { %T item element configure %I %C %E -text %t } $T notify bind $T { %T item state set %I ~edit } # # Create items and assign styles # set scriptDir { set item [$T item create -open no] $T item style set $item C0 STYLE $T item text $item C0 [file tail $file] if {$::shellicon} { # The shellicon extension fails randomly (by putting GDB into the # background!?) if the filename is not valid. MSDN says "relative # paths are valid" but perhaps that is misinformation. if {$file eq ".."} { set file [file dirname $::Dir] } $T item element configure $item C0 \ elemImg -path $file } if {$::macBitmap} { if {$file eq ".."} { set file [file dirname $::Dir] } ::tk::mac::iconBitmap $file 32 32 -file $file $T item element configure $item C0 \ elemImg -bitmap [list $file] } $T item lastchild root $item } set scriptFile { set item [$T item create -open no] $T item style set $item C0 STYLE switch [file extension $file] { .dll { set img big-dll } .exe { set img big-exe } .txt { set img big-txt } default { set img big-file } } set type [string toupper [file extension $file]] if {$type ne ""} { set type "[string range $type 1 end] " } append type "File" if {$::shellicon} { $T item element configure $item C0 \ elemImg -path $file + \ elemTxt -text [file tail $file] } elseif {$::macBitmap} { ::tk::mac::iconBitmap $file 32 32 -file $file $T item element configure $item C0 \ elemImg -bitmap [list $file] + \ elemTxt -text [file tail $file] } else { $T item element configure $item C0 \ elemImg -image [list $img] + \ elemTxt -text [file tail $file] } $T item lastchild root $item } SetList $T $scriptDir $scriptFile SetBindings $T true ConfigTransparentMarquee $T $T activate [$T item id "root firstchild"] $T notify bind $T { if {[%T item compare %p != root]} { %T item element configure %p C0 elemTxt -lines {} } if {[%T item compare %c != root]} { %T item element configure %c C0 elemTxt -lines 3 } } $T item element configure active C0 elemTxt -lines 3 bindtags $T [list $T DemoExplorerWin7 DemoExplorer TreeCtrlFileList TreeCtrl [winfo toplevel $T] all] return } # DemoExplorer::Motion # # Handle and events. In the Windows 7 demos, this highlights # the item under the mouse pointer. # # Arguments: # T The demo list. # x Widget x coordinate. # y Widget y coordinate. proc DemoExplorer::Motion {T x y} { variable Priv # Check for Win7 'mouseover' state if {[lsearch -exact [$T item state names] mouseover] == -1} return if {[info exists TreeCtrl::Priv(buttonMode)] && $TreeCtrl::Priv(buttonMode) ne ""} { set x [set y -1] } $T identify -array id $x $y if {$id(where) eq ""} { # nothing } elseif {$id(where) eq "header"} { # nothing } elseif {$id(where) eq "item" && $id(element) ne ""} { set item $id(item) if {$item ne $Priv(prev)} { if {$Priv(prev) ne ""} { $T item state set $Priv(prev) !mouseover } $T item state set $item mouseover set Priv(prev) $item } return } if {$Priv(prev) ne ""} { if {[$T item id $Priv(prev)] ne ""} { $T item state set $Priv(prev) !mouseover } set Priv(prev) "" } return } tktreectrl-2.4.1/demos/firefox.tcl0000644000076400010400000003631611573564403017511 0ustar TimAdministrators# Copyright (c) 2005-2011 Tim Baker namespace eval DemoFirefoxPrivacy {} proc DemoFirefoxPrivacy::Init {T} { variable Priv # # Configure the treectrl widget # $T configure -showroot no -showbuttons yes -showlines no \ -selectmode extended -xscrollincrement 20 -showheader yes if {$::clip} { $T configure -xscrollincrement 4 -yscrollincrement 4 } else { # Hide the borders because child windows appear on top of them $T configure -borderwidth 0 -highlightthickness 0 } # # Create columns # # Create 2 new images for the button sort arrow if {[lsearch -exact [image names] arrow-up] == -1} { set color #ACA899 ; # WinXP arrow color set img arrow-down image create photo $img $img put [list [string repeat "$color " 9]] -to 0 0 $img put [list [string repeat "$color " 7]] -to 1 1 $img put [list [string repeat "$color " 5]] -to 2 2 $img put [list [string repeat "$color " 3]] -to 3 3 $img put [list [string repeat "$color " 1]] -to 4 4 set img arrow-up image create photo $img $img put [list [string repeat "$color " 1]] -to 4 0 $img put [list [string repeat "$color " 3]] -to 3 1 $img put [list [string repeat "$color " 5]] -to 2 2 $img put [list [string repeat "$color " 7]] -to 1 3 $img put [list [string repeat "$color " 9]] -to 0 4 } $T column create -expand yes -arrowimage {arrow-down !up arrow-up {}} \ -arrow up -arrowpadx {10 2} -textlines 0 -tags C0 \ -text "This is a multi-line column title\nwith an image for the arrow" $T configure -treecolumn C0 # This binding toggles the sort arrow $T notify bind $T { if {[%T column cget %C -arrow] eq "up"} { %T column configure %C -arrow down } else { %T column configure %C -arrow up } } # # Create elements # $T element create eWindow window if {$::clip} { $T element configure eWindow -clip yes } $T element create eText1 text -font [list DemoFontBold] $T element create eRectTop rect -outline black -fill #FFFFCC \ -outlinewidth 1 -open s $T element create eRectBottom rect -outline black -fill #FFFFCC \ -outlinewidth 1 -open n # Destroy the window when the element is deleted. Could also bind to the # event. $T element configure eWindow -destroy yes # # Create styles using the elements # set S [$T style create styCategory -orient horizontal] $T style elements $S {eRectTop eText1 eWindow} $T style layout $S eRectTop -detach yes -indent no -iexpand xy -draw {yes open no {}} # note: using -iexpand x so clicking in the text works better $T style layout $S eText1 -expand ns -iexpand x -sticky w $T style layout $S eWindow -expand ns -padx 10 -pady 6 set S [$T style create styFrame -orient horizontal] $T style elements $S {eRectBottom eWindow} $T style layout $S eRectBottom -detach yes -indent no -iexpand xy $T style layout $S eWindow -iexpand x -squeeze x -padx {0 2} -pady {0 8} # # Create items and assign styles # foreach category { "History" "Saved Form Information" "Saved Passwords" "Download Manager History" "Cookies" "Cache"} { set I [$T item create -button yes] $T item style set $I C0 styCategory $T item element configure $I C0 eText1 -text $category if {$::clip} { set wClip [frame $T.clip$I -background red] set b [$::buttonCmd $wClip.b$I -text "Clear" -command "" -width 11] $T item element configure $I C0 eWindow -window $wClip } else { set b [$::buttonCmd $T.b$I -text "Clear" -command "" -width 11] $T item element configure $I C0 eWindow -window $b } $T item lastchild root $I } set bg #FFFFCC set textBg $bg if {$::tile} { ttk::style configure DemoCheckbutton -background $bg ttk::style layout DemoCheckbutton [ttk::style layout TCheckbutton] } # History set I [$T item create] $T item style set $I C0 styFrame if {$::clip} { set wClip [frame $T.clip$I -background red] set f [frame $wClip.f$I -borderwidth 0 -background $bg] } else { set f [frame $T.f$I -borderwidth 0 -background $bg] } label $f.l1 -background $bg -text "Remember visited pages for the last" $::entryCmd $f.e1 -width 6 $f.e1 insert end 20 label $f.l2 -background $bg -text "days" -background $bg pack $f.l1 -side left pack $f.e1 -side left -padx 8 pack $f.l2 -side left if {$::clip} { $T item element configure $I C0 eWindow -window $wClip } else { $T item element configure $I C0 eWindow -window $f } $T item lastchild "root child 0" $I # Saved Form Information set I [$T item create] $T item style set $I C0 styFrame if {$::clip} { set wClip [frame $T.clip$I -background red] set f [frame $wClip.f$I -borderwidth 0 -background $bg] } else { set f [frame $T.f$I -borderwidth 0 -background $bg] } text $f.t1 -background $textBg -borderwidth 0 -highlightthickness 0 \ -width 10 -height 1 -wrap word -cursor "" $f.t1 insert end "Information entered in web page forms and the Search\ Bar is saved to make filling out forms and searching faster." bindtags $f.t1 TextWrapBindTag if {$::tile} { $::checkbuttonCmd $f.cb1 -text "Save information I enter in web page forms and the Search Bar" \ -variable ::DemoFirefoxPrivacy::Priv(cbvar,$f.cb1) -style DemoCheckbutton } else { checkbutton $f.cb1 -background $bg -highlightthickness 0 -text "Save\ information I enter in web page forms and the Search Bar" \ -variable ::DemoFirefoxPrivacy::Priv(cbvar,$f.cb1) } set Priv(cbvar,$f.cb1) 1 pack $f.t1 -side top -anchor w -fill x -padx {0 8} -pady {0 4} pack $f.cb1 -side top -anchor w if {$::clip} { $T item element configure $I C0 eWindow -window $wClip } else { $T item element configure $I C0 eWindow -window $f } $T item lastchild "root child 1" $I # Saved Passwords set I [$T item create] $T item style set $I C0 styFrame if {$::clip} { set wClip [frame $T.clip$I -background red] set f [frame $wClip.f$I -borderwidth 0 -background $bg] } else { set f [frame $T.f$I -borderwidth 0 -background $bg] } set fLeft [frame $f.fLeft -borderwidth 0 -background $bg] text $fLeft.t1 -background $textBg -borderwidth 0 -highlightthickness 0 \ -width 10 -height 1 -wrap word -cursor "" $fLeft.t1 insert end "Login information for web pages can be kept in the\ Password Manager so that you do not need to re-enter your login\ details every time you visit." bindtags $fLeft.t1 TextWrapBindTag if {$::tile} { $::checkbuttonCmd $fLeft.cb1 -text "Remember Passwords" \ -variable ::DemoFirefoxPrivacy::Priv(cbvar,$fLeft.cb1) -style DemoCheckbutton } else { checkbutton $fLeft.cb1 -background $bg -highlightthickness 0 \ -text "Remember Passwords" -variable ::DemoFirefoxPrivacy::Priv(cbvar,$fLeft.cb1) } set Priv(cbvar,$fLeft.cb1) 1 pack $fLeft.t1 -side top -expand yes -fill x -pady {0 6} pack $fLeft.cb1 -side top -anchor w set fRight [frame $f.fRight -borderwidth 0 -background $bg] $::buttonCmd $fRight.b1 -text "View Saved Passwords" $::buttonCmd $fRight.b2 -text "Change Master Password..." pack $fRight.b1 -side top -expand yes -fill x pack $fRight.b2 -side top -expand yes -fill x -pady {8 0} pack $fLeft -side left -expand yes -fill x pack $fRight -side right -padx 12 -anchor n if {$::clip} { $T item element configure $I C0 eWindow -window $wClip } else { $T item element configure $I C0 eWindow -window $f } $T item lastchild "root child 2" $I # Download Manager History set I [$T item create] $T item style set $I C0 styFrame if {$::clip} { set wClip [frame $T.clip$I -background red] set f [frame $wClip.f$I -borderwidth 0 -background $bg] } else { set f [frame $T.f$I -borderwidth 0 -background $bg] } text $f.t1 -background $textBg -borderwidth 0 -highlightthickness 0 \ -width 10 -height 1 -wrap word -cursor "" $f.t1 insert end "The Download Manager keeps track of recently downloaded files." bindtags $f.t1 TextWrapBindTag set f1 [frame $f.f1 -borderwidth 0 -background $bg] label $f1.l1 -background $bg -text "Remove files from the Download Manager:" if {$::tile} { ttk::combobox $f1.mb1 -values { "Upon successful download" "When firefox exits" Manually } -state readonly -width [string length "Upon successful download"] $f1.mb1 current 2 } else { menubutton $f1.mb1 -indicatoron yes -menu $f1.mb1.m -text Manually \ -width [string length "Upon successful download"] -justify left set m [menu $f1.mb1.m -tearoff no] foreach label { "Upon successful download" "When firefox exits" Manually} { $m add command -label $label -command [list $f1.mb1 configure\ -text $label] } } pack $f1.l1 -side left pack $f1.mb1 -side left -padx {8 10} pack $f.t1 -side top -expand yes -fill x -padx {0 10} pack $f1 -side top -anchor w if {$::clip} { $T item element configure $I C0 eWindow -window $wClip } else { $T item element configure $I C0 eWindow -window $f } $T item lastchild "root child 3" $I # Cookies set I [$T item create] $T item style set $I C0 styFrame if {$::clip} { set wClip [frame $T.clip$I -background red] set f [frame $wClip.f$I -borderwidth 0 -background $bg] } else { set f [frame $T.f$I -borderwidth 0 -background $bg] } text $f.t1 -background $textBg -borderwidth 0 -highlightthickness 0 \ -width 10 -height 1 -wrap word -cursor "" $f.t1 insert end "Cookies are pieces of information stored by web pages\ on your computer. They are used to remember login information and\ other data." bindtags $f.t1 TextWrapBindTag set fLeft [frame $f.fLeft -borderwidth 0 -background $bg] if {$::tile} { $::checkbuttonCmd $fLeft.cb1 -style DemoCheckbutton \ -text "Allow sites to set cookies" -variable ::DemoFirefoxPrivacy::Priv(cbvar,$fLeft.cb1) } else { checkbutton $fLeft.cb1 -background $bg -highlightthickness 0 \ -text "Allow sites to set cookies" -variable ::DemoFirefoxPrivacy::Priv(cbvar,$fLeft.cb1) } set Priv(cbvar,$fLeft.cb1) 1 if {$::tile} { $::checkbuttonCmd $fLeft.cb2 -style DemoCheckbutton \ -text "for the originating web site only" \ -variable ::DemoFirefoxPrivacy::Priv(cbvar,$fLeft.cb2) } else { checkbutton $fLeft.cb2 -background $bg -highlightthickness 0 \ -text "for the originating web site only" \ -variable ::DemoFirefoxPrivacy::Priv(cbvar,$fLeft.cb2) } set Priv(cbvar,$fLeft.cb2) 0 pack $fLeft.cb1 -side top -anchor w pack $fLeft.cb2 -side top -anchor w -padx {20 0} set fRight [frame $f.fRight -borderwidth 0 -background $bg] $::buttonCmd $fRight.b1 -text "Exceptions" $::buttonCmd $fRight.b2 -text "View Cookies" pack $fRight.b1 -side left -padx {0 10} pack $fRight.b2 -side left set f1 [frame $fLeft.f1 -borderwidth 0 -background $bg] label $f1.l1 -background $bg -text "Keep Cookies:" if {$::tile} { ttk::combobox $f1.mb1 -values { "until they expire" "until I close Firefox" "ask me every time" } -state readonly -width [string length "until I close Firefox"] $f1.mb1 current 0 } else { menubutton $f1.mb1 -indicatoron yes -menu $f1.mb1.m \ -text "until they expire" \ -width [string length "until I close Firefox"] -justify left set m [menu $f1.mb1.m -tearoff no] foreach label { "until they expire" "until I close Firefox" "ask me every time" } { $m add command -label $label -command [list $f1.mb1 configure -text $label] } } pack $f1.l1 -side left pack $f1.mb1 -side left -padx {8 0} pack $f1 -side top -anchor w pack $f.t1 -side top -expand yes -fill x -padx {0 10} -pady {0 8} pack $fLeft -side left -expand yes -fill x pack $fRight -side right -padx 14 -anchor n if {$::clip} { $T item element configure $I C0 eWindow -window $wClip } else { $T item element configure $I C0 eWindow -window $f } $T item lastchild "root child 4" $I # Cache set I [$T item create] $T item style set $I C0 styFrame if {$::clip} { set wClip [frame $T.clip$I -background red] set f [frame $wClip.f$I -borderwidth 0 -background $bg] } else { set f [frame $T.f$I -borderwidth 0 -background $bg] } text $f.t1 -background $textBg -borderwidth 0 -highlightthickness 0 \ -width 10 -height 1 -wrap word -cursor "" $f.t1 insert end "Pages you view are stored in the cache for quicker\ viewing later on." bindtags $f.t1 TextWrapBindTag set f1 [frame $f.f1 -borderwidth 0 -background $bg] label $f1.l1 -background $bg -text "Use up to:" $::entryCmd $f1.e1 -width 10 $f1.e1 insert end 50000 label $f1.l2 -background $bg -text "KB of disk space for the cache." \ -background $bg pack $f1.l1 -side left pack $f1.e1 -side left -padx 8 pack $f1.l2 -side left pack $f.t1 -side top -expand yes -fill x -padx {0 10} pack $f1 -side top -anchor w if {$::clip} { $T item element configure $I C0 eWindow -window $wClip } else { $T item element configure $I C0 eWindow -window $f } $T item lastchild "root child 5" $I # This binding configures the -height option of a Text widget to the # number of lines it is displaying bind TextWrapBindTag { scan [textlayout [%W cget -font] [%W get 1.0 "end - 1 chars"] \ -width %w] "%%d %%d" width height set height [expr {$height / [font metrics [%W cget -font] -linespace]}] if {$height != [%W cget -height]} { %W configure -height $height } } # This binding collapses all items before expanding a new one $T notify bind $T { %T item collapse all } $T item collapse all bind DemoFirefoxPrivacy { if {[lindex [%W identify %x %y] 0] eq "header"} { TreeCtrl::DoubleButton1 %W %x %y } else { DemoFirefoxPrivacy::Button1 %W %x %y } break } bind DemoFirefoxPrivacy { DemoFirefoxPrivacy::Button1 %W %x %y break } bind DemoFirefoxPrivacy { # noop } bind DemoFirefoxPrivacy { # noop } bind DemoFirefoxPrivacy { DemoFirefoxPrivacy::Motion %W %x %y } bind DemoFirefoxPrivacy { DemoFirefoxPrivacy::Motion %W %x %y } if {$::tile} { bind DemoFirefoxPrivacy <> { ttk::style configure DemoCheckbutton -background #FFFFCC ttk::style layout DemoCheckbutton [ttk::style layout TCheckbutton] } } set Priv(prev) "" bindtags $T [list $T DemoFirefoxPrivacy TreeCtrl [winfo toplevel $T] all] return } proc DemoFirefoxPrivacy::Button1 {w x y} { variable ::TreeCtrl::Priv focus $w $w identify -array id $x $y set Priv(buttonMode) "" if {$id(where) eq "header"} { TreeCtrl::ButtonPress1 $w $x $y } elseif {$id(where) eq "item"} { set item $id(item) # click a button if {$id(element) eq ""} { TreeCtrl::ButtonPress1 $w $x $y return } if {$id(element) eq "eText1"} { $w item toggle $item DisplayStylesInItem $item } } return } proc DemoFirefoxPrivacy::Motion {w x y} { variable Priv $w identify -array id $x $y if {$id(where) eq "item"} { set item $id(item) if {$id(element) eq "eText1"} { if {$item ne $Priv(prev)} { $w configure -cursor hand2 set Priv(prev) $item } return } } if {$Priv(prev) ne ""} { $w configure -cursor "" set Priv(prev) "" } return } tktreectrl-2.4.1/demos/gradients.tcl0000644000076400010400000003215011573534307020017 0ustar TimAdministrators# Copyright (c) 2010-2011 Tim Baker namespace eval DemoGradients {} proc DemoGradients::Init {T} { if {[lsearch -exact [font names] DemoGradientFont] == -1} { array set fontInfo [font actual [$T cget -font]] set fontInfo(-weight) bold eval font create DemoGradientFont [array get fontInfo] } # # Configure the treectrl widget # $T configure \ -showbuttons no -showlines no -showroot no \ -xscrollincrement 20 -yscrollincrement 20 \ -xscrollsmoothing yes -yscrollsmoothing yes \ -canvaspadx 20 # # Create columns # for {set i 0} {$i < 6} {incr i} { $T column create -text "Column $i" -width 100 -tags C$i } # # Define new states # $T item state define openW $T item state define openN # # Create elements # $T element create elemTextIntro text -font DemoGradientFont $T element create elemText text $T element create elemBox rect -height 30 \ -outline black -outlinewidth 2 -open {wn {openW openN} w openW n openN} # # Create styles using the elements # set S [$T style create styleIntro] $T style elements $S elemTextIntro $T style layout $S elemTextIntro -padx 4 -pady {3 0} -squeeze x set S [$T style create styleText] $T style elements $S elemText $T style layout $S elemText -padx 4 -pady {15 6} -squeeze x set S [$T style create styleBox] $T style elements $S elemBox $T style layout $S elemBox -iexpand x # # Create items and assign styles # set stops {{0.0 blue} {0.5 green} {1.0 red}} set steps 10 set I [$T item create -parent root] $T item style set $I C0 styleIntro $T item span $I C0 6 $T item text $I C0 "In all the examples below, each item has the same\ style in every column painted with a gradient. Every gradient has\ exactly the same colors. The items appear different only because of\ the different coordinates specified for each gradient." # Example 1: no gradient coords specified $T gradient create G1 -stops $stops -steps $steps $T gradient configure G1 -left {} -right {} -top {} -bottom {} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 1: A single item with a single horizontal\ gradient. The coordinates are unspecified, so the gradient brush has the\ same bounds as each rectangle being painted\n\ G1 -left { } -right { } -top { } -bottom { }" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G1 # Example 2: -left {0.0 item} -right {0.5 item} $T gradient create G2 -stops $stops -steps $steps $T gradient configure G2 -left {0.0 item} -right {0.5 item} -top {} -bottom {} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 2: A single item with a single horizontal\ gradient. The right side of the gradient is set to 1/2 the width\ of the item, which results in the gradient pattern being tiled when\ painting the other half of the item.\n\ G2 -left {0.0 item} -right {0.5 item} -top { } -bottom { }" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G2 # Example 3: -left {0.0 item} -right {1.0 item} $T gradient create G3 -stops $stops -steps $steps $T gradient configure G3 -left {0.0 item} -right {1.0 item} -top {} -bottom {} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 3: A single item with a single horizontal \ gradient. The gradient extends from the left side to the right side\ of the item.\n\ G3 -left {0.0 item} -right {1.0 item} -top { } -bottom { }" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G3 # Example 4: 3 items, vertical gradient, no gradient coords specified $T gradient create G4 -stops $stops -steps $steps -orient vertical $T gradient configure G4 -left {} -right {} -top {} -bottom {} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 4: 3 items with a single vertical gradient. \ The coordinates are unspecified, so the gradient brush has the\ same bounds as each rectangle being painted\n\ G4 -left { } -right { } -top { } -bottom { }" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G4 set I [$T item create -parent root] $T item state set $I openN $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G4 set I [$T item create -parent root] $T item state set $I openN $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G4 # Example 5: 3 items, 3 vertical gradients $T gradient create G5.1 -stops $stops -steps $steps -orient vertical $T gradient configure G5.1 -left {} -right {} -top {} -bottom {3.0 item} $T gradient create G5.2 -stops $stops -steps $steps -orient vertical $T gradient configure G5.2 -left {} -right {} -top {-1.0 item} -bottom {2.0 item} $T gradient create G5.3 -stops $stops -steps $steps -orient vertical $T gradient configure G5.3 -left {} -right {} -top {-2.0 item} -bottom {} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 5: 3 items with 3 vertical gradients. Each\ gradient uses item-relative coordinates to give the appearance of\ a single seamless gradient.\n\ G5.1 -left { } -right { } -top { } -bottom {3.0 item}\n\ G5.2 -left { } -right { } -top {-1.0 item} -bottom {2.0 item}\n\ G5.3 -left { } -right { } -top {-2.0 item} -bottom { }" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G5.1 set I [$T item create -parent root] $T item state set $I openN $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G5.2 set I [$T item create -parent root] $T item state set $I openN $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G5.3 # Example 6: 3 items, 1 vertical gradient $T gradient create G6 -stops $stops -steps $steps -orient vertical set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 6: 3 items with a single vertical gradient. \ The -top and -bottom coordinates specify the first and third items\ respectively. The appearance is exactly the same as the previous\ example, but uses only 1 gradient instead of 3. The words \"I6.1\"\ and \"I6.3\" are item -tags.\n\ G6 -top {0.0 item I6.1} -bottom {1.0 item I6.3}" set I1 [$T item create -parent root -tags I6.1] $T item state forcolumn $I1 {range 1 end} openW $T item style set $I1 all styleBox $T item element configure $I1 all elemBox -fill G6 set I2 [$T item create -parent root -tags I6.2] $T item state set $I2 openN $T item state forcolumn $I2 {range 1 end} openW $T item style set $I2 all styleBox $T item element configure $I2 all elemBox -fill G6 set I3 [$T item create -parent root -tags I6.3] $T item state set $I3 openN $T item state forcolumn $I3 {range 1 end} openW $T item style set $I3 all styleBox $T item element configure $I3 all elemBox -fill G6 $T gradient configure G6 -top {0.0 item I6.1} -bottom {1.0 item I6.3} # Example 7: column-relative $T gradient create G7 -stops $stops -steps $steps $T gradient configure G7 -left {0.0 column} -right {1.0 column} -top {} -bottom {} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 7: A single item with a single horizontal\ gradient. The gradient brush starts at the left edge of each column\ and extends to the right edge of the same column.\n\ G7 -left {0.0 column} -right {1.0 column} -top { } -bottom { }" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G7 # Example 8: column-relative $T gradient create G8 -stops $stops -steps $steps $T gradient configure G8 -left {0.0 column} -right {1.5 column} -top {} -bottom {} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 8: A single item with a single horizontal\ gradient. The gradient brush starts at the left edge of each column\ and extends to the half-way point of the next visible column. Notice\ that the right-most column shows all of the gradient since there\ is no visible column to the right of it.\n\ G8 -left {0.0 column} -right {1.5 column} -top { } -bottom { }" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G8 # Example 9: column-relative $T gradient create G9 -stops $stops -steps $steps $T gradient configure G9 -left {-0.5 column} -right {1.0 column} -top {} -bottom {} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 9: A single item with a single horizontal\ gradient. The gradient brush starts at the half-way point of the\ previous visible column and extends to the right edge of each column. \ Notice that the left-most column shows all of the gradient since there\ is no visible column to the left of it.\n\ G9 -left {-0.5 column} -right {1.0 column} -top { } -bottom { }" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G9 # Example 10: column-relative $T gradient create G10 -stops $stops -steps $steps $T gradient configure G10 -left {0.0 column C0} -right {1.0 column C2} -top {} -bottom {} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 10: A single item with a single horizontal\ gradient. The gradient brush starts at the left edge of column 0\ and extends to the right edge of column 2. The gradient pattern is\ tiled when painting the other half of the item. The words \"C0\" and\ \"C2\" are column -tags.\n\ G10 -left {0.0 column C0} -right {1.0 column C2} -top { } -bottom { }" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G10 # Example 11: content-relative $T gradient create G11 -stops $stops -steps $steps $T gradient configure G11 -left {0.0 area content} -right {1.0 area content} -top {} -bottom {} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 11: A single item with a single horizontal\ gradient. The gradient brush starts inside the left window border and\ extends to the inside edge of the right window border (the 'content'\ area). The gradient brush changes width as the demo window is resized.\n\ G11 -left {0.0 area content} -right {1.0 area content} -top { } -bottom { }" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G11 # Example 12: content-relative $T gradient create G12 -stops $stops -steps $steps -orient vertical $T gradient configure G12 -left {} -right {} -top {0.0 area content} -bottom {1.0 area content} set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 6 $T item text $I C0 "Example 12: A single item with a single vertical\ gradient. The gradient brush starts inside the top window border and\ extends to the inside edge of the bottom window border (the 'content'\ area). The gradient brush changes height as the demo window is resized,\ and scrolling the list vertically changes which part of the gradient is\ painted in the item.\n\ G12 -left { } -right { } -top {0.0 area content} -bottom {1.0 area content}" set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox $T item element configure $I all elemBox -fill G12 return } tktreectrl-2.4.1/demos/gradients2.tcl0000644000076400010400000000767511573534332020115 0ustar TimAdministrators# Copyright (c) 2010-2011 Tim Baker namespace eval DemoGradients2 {} proc DemoGradients2::Init {T} { # # Configure the treectrl widget # $T configure \ -showbuttons no -showlines no -showroot no \ -xscrollincrement 20 -yscrollincrement 20 \ -xscrollsmoothing yes -yscrollsmoothing yes \ # # Create columns # for {set i 0} {$i < 6} {incr i} { $T column create -text "Column $i" -width 100 -tags C$i } set steps 25 set stops {{0.0 "light green"} {1.0 white}} $T gradient create G_C0 -stops $stops -steps $steps -orient vertical $T column configure C0 -itembackground G_C0 $T gradient create G_C1 -stops $stops -steps $steps -orient vertical $T gradient configure G_C1 -top {0.0 area content} -bottom {1.0 area content} $T column configure C1 -itembackground G_C1 $T gradient create G_C2 -stops $stops -steps $steps -orient vertical $T gradient configure G_C2 -top {0.0 canvas} -bottom {1.0 canvas} $T column configure C2 -itembackground G_C2 $T gradient create G_C3 -stops $stops -steps $steps -orient horizontal $T gradient configure G_C3 -left {} -right {} $T column configure C3 -itembackground G_C3 $T gradient create G_C4 -stops $stops -steps $steps -orient horizontal $T gradient configure G_C4 -left {0.0 area content} -right {1.0 area content} $T column configure C4 -itembackground G_C4 $T gradient create G_C5 -stops $stops -steps $steps -orient horizontal $T gradient configure G_C5 -left {0.0 canvas} -right {1.0 canvas} $T column configure C5 -itembackground G_C5 # # Define new states # $T item state define openW $T item state define openN # # Create elements # $T element create elemTextIntro text $T element create elemBox rect -height 50 \ -outline gray -outlinewidth 1 -open {wn {openW openN} w openW n openN} # # Create styles using the elements # $T style create styleIntro $T style elements styleIntro elemTextIntro $T style layout styleIntro elemTextIntro -padx 4 -pady {3 0} -squeeze x $T style create styleBox $T style elements styleBox elemBox $T style layout styleBox elemBox -iexpand x # # Create items and assign styles # set I [$T item create -parent root] $T item style set $I C0 styleIntro $T item span $I C0 6 $T item text $I C0 "This demonstrates column -itembackground colors with gradients.\n Column 0 has a vertical gradient with unspecified bounds, so the gradient\ is as tall as each item.\n \ G_C0 -top { } -bottom { }\n Column 1 has a vertical gradient as tall as the content area. The colors\ remain 'locked in place' as the list is scrolled up and down.\n \ G_C1 -top {0.0 area content} -bottom {1.0 area content}\n Column 2 has a vertical gradient as tall as the canvas. The first stop color\ begins at the top of the first item and the last stop color ends at the\ bottom of the last item.\n \ G_C2 -top {0.0 canvas} -bottom {1.0 canvas}\n Column 3 has a horizontal gradient with unspecified bounds, so the gradient\ is as wide as the column.\n \ G_C3 -left {} -right {}\n Column 4 has a horizontal gradient as wide as the content area. The colors\ remain 'locked in place' as the list is scrolled left and right, and\ resizing the window changes the part of the gradient in that column.\n \ G_C4 -left {0.0 area content} -right {1.0 area content}\n Column 5 has a horizontal gradient as wide as the canvas. The first stop color\ begins at the left edge of the first column and the last stop color ends at the\ right edge of the last column. If the window is wider than the items then\ the gradient ends at the window border.\n \ G_C5 -left {0.0 canvas} -right {1.0 canvas}" for {set i 0} {$i < 25} {incr i} { set I [$T item create -parent root] $T item state forcolumn $I {range 1 end} openW $T item style set $I all styleBox } return } tktreectrl-2.4.1/demos/gradients3.tcl0000644000076400010400000002207111573535030020075 0ustar TimAdministrators# Copyright (c) 2010-2011 Tim Baker namespace eval DemoGradients3 {} proc DemoGradients3::Init {T} { variable Priv # # Configure the treectrl widget # $T configure \ -showbuttons no -showlines no -showroot no \ -xscrollincrement 20 -yscrollincrement 20 \ -xscrollsmoothing yes -yscrollsmoothing yes \ -canvaspady 5 -itemgapy 8 # # Create columns # $T column create -text "Column 0" -width 110 -tags C0 $T column create -text "Column 1" -width 110 -tags C1 $T column create -text "Column 2" -width 110 -tags C2 # # Create elements # $T element create elemBox rect -height 30 -fill gray95 $T element create elemText text # # Create styles using the elements # $T style create styleText $T style elements styleText elemText $T style layout styleText elemText -padx 4 -pady 6 -squeeze x $T style create styleBox $T style elements styleBox elemBox $T style layout styleBox elemBox -padx 5 -iexpand x $T column configure {all !tail} -itemstyle styleBox # # Create items and assign styles # $T gradient create G1 -stops {{0.0 blue} {1.0 green}} -steps 15 $T gradient create G2 -stops {{0.0 green} {1.0 red}} -steps 15 $T gradient create G3 -stops {{0.0 red} {1.0 blue}} -steps 15 set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 3 $T item text $I C0 "Outlined rectangles\nThis also demonstrates the -open\ option of rect elements." foreach open {"" w nw n ne e se s sw we ns} { set I [$T item create -parent root] $T item element configure $I C0 elemBox -outline G1 -outlinewidth 1 -open $open $T item element configure $I C1 elemBox -outline G2 -outlinewidth 2 -open $open $T item element configure $I C2 elemBox -outline G3 -outlinewidth 3 -open $open } set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 3 $T item text $I C0 "Outlined rounded rectangles\nNote that rounded rectangles\ will not be filled or outlined with gradients unless the platform supports gradients\ natively." foreach open {"" w nw n ne e se s sw we ns} { set I [$T item create -parent root] $T item element configure $I C0 elemBox -outline G1 -outlinewidth 1 -open $open -rx 5 $T item element configure $I C1 elemBox -outline G2 -outlinewidth 2 -open $open -rx 5 $T item element configure $I C2 elemBox -outline G3 -outlinewidth 3 -open $open -rx 5 } set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 3 $T item text $I C0 "Filled rectangles" set I [$T item create -parent root] $T item element configure $I C0 elemBox -fill G1 -open $open $T item element configure $I C1 elemBox -fill G2 -open $open $T item element configure $I C2 elemBox -fill G3 -open $open set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 3 $T item text $I C0 "Filled rounded rectangles" foreach open {"" w nw n ne e se s sw we ns} { set I [$T item create -parent root] $T item element configure $I C0 elemBox -fill G1 -open $open -rx 7 $T item element configure $I C1 elemBox -fill G2 -open $open -rx 7 $T item element configure $I C2 elemBox -fill G3 -open $open -rx 7 } set I [$T item create -parent root] $T item style set $I C0 styleText $T item span $I C0 3 $T item text $I C0 "Eyecandy" ##### set height 30 set steps [expr {($height - 5)/2}] $T gradient create G_mouseover -steps $steps -stops {{0.0 white} {1.0 #ebf3fd}} -orient vertical $T gradient create G_selected_active -steps $steps -stops {{0.0 #dcebfc} {1.0 #c1dbfc}} -orient vertical $T gradient create G_selected -steps $steps -stops {{0.0 #ebf4fe} {1.0 #cfe4fe}} -orient vertical $T gradient create G_focusout -steps $steps -stops {{0.0 #f8f8f8} {1.0 #e5e5e5}} -orient vertical $T item state define mouseover $T element create elemRectGradient rect \ -fill [list G_selected_active {mouseover} \ G_focusout {!focus} \ G_selected {}] $T element create elemRectOutline rect -rx 1 \ -outline [list #7da2ce {mouseover} \ #d9d9d9 {!focus} \ #7da2ce {}] -outlinewidth 1 set S [$T style create styleExplorer] $T style elements $S {elemRectGradient elemRectOutline} $T style layout $S elemRectGradient -padx 0 -pady {2 3} -iexpand xy $T style layout $S elemRectOutline -union elemRectGradient -ipadx 2 -ipady 2 -padx 5 set I [$T item create -parent root -height $height] $T item style set $I C0 styleExplorer $T item style set $I C1 styleExplorer $T item style set $I C2 styleExplorer ##### $T gradient create G_green -orient vertical -steps 4 \ -stops {{0 #00680a} {0.05 #00680a} {0.1 #197622} {0.45 #197622} {0.5 #00680a} {0.6 #00680a} {1 #00c82c}} set I [$T item create -parent root] $T item span $I C0 3 $T item element configure $I C0 elemBox -fill G_green ##### $T gradient create G_orange1 -orient vertical -steps 4 \ -stops {{0 #fde8d1} {0.3 #fde8d1} {0.3 #ffce69} {0.6 #ffce69} {1 #fff3c3}} $T gradient create G_orange2 -orient vertical -steps 4 \ -stops {{0 #fffef6} {0.3 #fffef6} {0.3 #ffef9a} {0.6 #ffef9a} {1 #fffce8}} set height 40 $T element create elemOrangeOutline rect -outline #ffb700 -outlinewidth 1 -rx 1 $T element create elemOrangeBox rect -fill {G_orange1 mouseover G_orange2 {}} \ -height [expr {$height - 2 * 2}] set S [$T style create styleOrange] $T style elements $S {elemOrangeOutline elemOrangeBox} $T style layout $S elemOrangeBox -iexpand x $T style layout $S elemOrangeOutline -union elemOrangeBox -ipadx 2 -ipady 2 -padx 5 set I [$T item create -parent root] $T item span $I C0 3 $T item style set $I C0 $S ##### $T gradient create G_progressFG -orient vertical -steps 2 \ -stops {{0 #cdffcd} {0.2 #cdffcd} {0.25 #a2efaf} {0.45 #a2efaf} {0.5 #00d428} {1.0 #1ce233}} $T gradient create G_progressBG -orient vertical -steps 2 \ -stops {{0 white} {0.45 #dbdbdb} {0.5 #cacaca} {1.0 #cacaca}} $T element create elemProgressOutline rect -rx 1 -outline gray -outlinewidth 1 $T element create elemProgressBG rect -fill G_progressBG -height 12 \ -outline #eaeaea -outlinewidth 1 $T element create elemProgressFG rect -fill G_progressFG -height 12 set S [$T style create styleProgress] $T style elements $S {elemProgressOutline elemProgressBG elemProgressFG} $T style layout $S elemProgressBG -iexpand x $T style layout $S elemProgressOutline -union elemProgressBG -padx 5 -ipadx 1 -ipady 1 $T style layout $S elemProgressFG -detach yes -padx 6 -pady 1 set I [$T item create -parent root -tags progress] $T item span $I C0 3 $T item style set $I C0 $S C1 "" C2 "" set Priv(progressItem) $I set Priv(percent) 0.0 set Priv(afterId) "" # Pause/resume animating when the progress bar's visibility changes $T notify bind $T { DemoGradients3::ItemVisibility %T %v %h } # Stop animating when the item is deleted $T notify bind $T { after cancel $DemoGradients3::Priv(afterId) dbwin "progressbar deleted" } ##### set Priv(prev) "" bind DemoGradients3 { DemoGradients3::Motion %W %x %y } bind DemoGradients3 { DemoGradients3::Motion %W -1 -1 } bindtags $T [concat DemoGradients3 [bindtags $T]] return } proc DemoGradients3::Motion {T x y} { variable Priv if {[lsearch -exact [$T item state names] mouseover] == -1} return set id [$T identify $x $y] if {$id eq ""} { } elseif {[lindex $id 0] eq "header"} { } elseif {[lindex $id 0] eq "item" && [llength $id] > 4} { set item [lindex $id 1] set column [lindex $id 3] set curr [list $item $column] if {$curr ne $Priv(prev)} { if {$Priv(prev) ne ""} { eval $T item state forcolumn $Priv(prev) !mouseover } $T item state forcolumn $item $column mouseover set Priv(prev) $curr } return } if {$Priv(prev) ne ""} { eval $T item state forcolumn $Priv(prev) !mouseover set Priv(prev) "" } return } proc DemoGradients3::Progress {T} { variable Priv set percent $Priv(percent) if {$percent > 1.0} { set percent 1.0 set Priv(percent) 0.0 } else { set Priv(percent) [expr {$percent + 0.025}] } scan [$T item bbox $Priv(progressItem)] "%d %d %d %d" x1 y1 x2 y2 set width [expr {($x2 - $x1) - 2 * 1 - 10}] $T element configure elemProgressFG -width [expr {$width * $percent}] set Priv(afterId) [after 100 [list DemoGradients3::Progress $T]] return } proc DemoGradients3::ItemVisibility {T visible hidden} { variable Priv foreach I $visible { if {[$T item tag expr $I progress]} { set Priv(afterId) [after 100 [list DemoGradients3::Progress $T]] dbwin "progress resumed" return } } foreach I $hidden { if {[$T item tag expr $I progress]} { after cancel $Priv(afterId) set Priv(afterId) "" dbwin "progress paused" return } } return } proc rgb {r g b} { format #%.2x%.2x%.2x $r $g $b } tktreectrl-2.4.1/demos/headers.tcl0000644000076400010400000004706211573535361017463 0ustar TimAdministrators# Copyright (c) 2011 Tim Baker namespace eval DemoHeaders {} proc DemoHeaders::Init {T} { $T configure \ -showroot no -xscrollsmoothing yes -yscrollsmoothing yes \ -selectmode multiple -xscrollincrement 20 -canvaspadx 0 # # Create one locked column on each side plus 8 non-locked columns # set itembg {linen {} #e0e8f0 {}} $T column create -text "Left" -tags Cleft -width 80 -justify center \ -gridrightcolor gray90 -itembackground $itembg \ -lock left -arrow none -arrowside left \ -visible no for {set i 1} {$i <= 8} {incr i} { $T column create -text "C$i" -tags C$i -width 80 -justify center \ -gridrightcolor gray90 -itembackground $itembg } $T column create -text "Right" -tags Cright -width 80 -justify center \ -gridrightcolor gray90 -itembackground $itembg \ -lock right -visible no # # Create an image element to use as the sort arrow for some header # styles. # InitSortImages blue 5 $T element create header.sort image -statedomain header \ -image {::DemoHeaders::arrow-down down ::DemoHeaders::arrow-up up} # # Create a style for our custom headers, # a raised border with centered text. # $T element create header.border border -statedomain header \ -background $::SystemButtonFace \ -relief {sunken pressed raised {}} -thickness 2 -filled yes $T element create header.text text -statedomain header \ -lines 1 -fill black set S [$T style create header1 -orient horizontal -statedomain header] $T style elements $S {header.border header.text header.sort} $T style layout $S header.border -detach yes -indent no -iexpand xy $T style layout $S header.text -center xy -padx 6 -pady 2 -squeeze x $T style layout $S header.sort -expand nws -padx {0 6} \ -visible {no {!down !up}} # # Create a style for our custom headers, # a light-blue rounded rectangle with centered text. # set radius 9 if {[Platform unix]} { set radius 7 } $T element create header.rrect rect -statedomain header \ -rx $radius -fill { #cee8f0 active #87c6da pressed #87c6da up #87c6da down {light blue} {} } set S [$T style create header2 -orient horizontal -statedomain header] $T style elements $S {header.rrect header.text header.sort} $T style layout $S header.rrect -detach yes -iexpand xy -padx {1 0} -pady 1 $T style layout $S header.text -center xy -padx 6 -pady 4 -squeeze x $T style layout $S header.sort -expand nws -padx {0 6} \ -visible {no {!down !up}} # # Create a style for our custom headers, # Window 7 Explorer type headers. # $T gradient create G.header3.fill.active -orient vertical \ -stops {{0.0 #f3f8fd} {1.0 #eff3f9}} -steps 8 $T gradient create G.header3.fill.pressed -orient vertical \ -stops {{0.0 #c1ccda} {0.2 white} {1.0 white}} -steps 8 $T gradient create G.header3.outline.normal -orient vertical \ -stops {{0.0 #e3e8ee} {1.0 white}} -steps 8 $T element create header.outline3 rect -statedomain header \ -outline {#e3e8ee active #c0cbd9 pressed G.header3.outline.normal normal} \ -outlinewidth 1 -open {w normal} $T element create header.rect3 rect -statedomain header \ -fill G.header3.fill.active $T element create header.rect3.pressed rect -statedomain header \ -fill G.header3.fill.pressed set S [$T style create header3 -orient horizontal -statedomain header] $T style elements $S {header.rect3.pressed header.outline3 header.rect3 header.text header.sort} $T style layout $S header.outline3 -detach yes -iexpand xy $T style layout $S header.rect3 -detach yes -iexpand xy \ -padx 2 -pady 2 -visible {no !active} $T style layout $S header.rect3.pressed -detach yes -iexpand xy \ -visible {no !pressed} $T style layout $S header.text -center xy -padx 6 -pady {6 3} -squeeze x $T style layout $S header.sort -detach yes -expand we -pady 2 # # Create a style for our custom headers, # a header element with a checkbox image and centered text. # InitPics *checked $T header state define CHECK $T element create header.header header -statedomain header $T element create header.check image -statedomain header \ -image {checked CHECK unchecked {}} set S [$T style create header4 -statedomain header] $T style elements $S {header.header header.check header.text} $T style layout $S header.header -union {header.check header.text} -iexpand news $T style layout $S header.check -expand nes -padx {6 0} $T style layout $S header.text -center xy -padx 6 -squeeze x # # Create a style for our custom headers, # Mac OS X type headers. # $T gradient create Gnormal -orient vertical -stops {{0.0 white} {0.5 gray87} {1.0 white}} -steps 6 $T gradient create Gactive -orient vertical -stops {{0.0 white} {0.5 gray90} {1.0 white}} -steps 6 $T gradient create Gpressed -orient vertical -stops {{0.0 white} {0.5 gray82} {1.0 white}} -steps 6 $T gradient create Gsorted -orient vertical -stops {{0.0 white} {0.5 {sky blue}} {1.0 white}} -steps 6 $T gradient create Gactive_sorted -orient vertical -stops {{0.0 white} {0.5 {light blue}} {1.0 white}} -steps 6 $T gradient create Gpressed_sorted -orient vertical -stops {{0.0 white} {0.5 {sky blue}} {1.0 white}} -steps 6 $T element create header.rect5 rect -statedomain header \ -fill { Gactive_sorted {active up} Gpressed_sorted {pressed up} Gactive_sorted {active down} Gpressed_sorted {pressed down} Gsorted up Gsorted down Gactive active Gpressed pressed Gnormal {} } -outline { {sky blue} up {sky blue} down gray {} } -outlinewidth 1 -open { nw !pressed } set S [$T style create header5 -orient horizontal -statedomain header] $T style elements $S {header.rect5 header.text header.sort} $T style layout $S header.rect5 -detach yes -iexpand xy $T style layout $S header.text -center xy -padx 6 -pady 2 -squeeze x $T style layout $S header.sort -expand nws -padx {0 6} \ -visible {no {!down !up}} # # Create a style for our custom headers, # a gradient-filled rectangle with centered text. # $T gradient create G_orange1 -orient vertical -steps 4 \ -stops {{0 #fde8d1} {0.3 #fde8d1} {0.3 #ffce69} {0.6 #ffce69} {1 #fff3c3}} $T gradient create G_orange2 -orient vertical -steps 4 \ -stops {{0 #fffef6} {0.3 #fffef6} {0.3 #ffef9a} {0.6 #ffef9a} {1 #fffce8}} $T element create orange.outline rect -statedomain header \ -outline #ffb700 -outlinewidth 1 \ -rx 1 -open { nw !pressed } $T element create orange.box rect -statedomain header \ -fill { G_orange1 active G_orange1 up G_orange1 down G_orange2 {} } set S [$T style create header6 -orient horizontal -statedomain header] $T style elements $S {orange.outline orange.box header.text header.sort} $T style layout $S orange.outline -union orange.box -ipadx 2 -ipady 2 $T style layout $S orange.box -detach yes -iexpand xy $T style layout $S header.text -center xy -padx 6 -pady 4 -squeeze x $T style layout $S header.sort -expand nws -padx {0 6} \ -visible {no {!down !up}} # # Configure 3 rows of column headers # set S header2 $T header configure first -tags header1 set H header1 $T header configure $H all -arrowgravity right -justify center $T header style set $H all $S $T header span $H all 4 foreach {C text} [list Cleft Left C1 A C5 H Cright Right] { $T header configure $H $C -text $text $T header text $H $C $text } set H [$T header create -tags header2] $T header configure $H all -arrowgravity right -justify center $T header style set $H all $S $T header span $H all 2 foreach {C text} [list Cleft Left C1 B C3 C C5 I C7 J Cright Right] { $T header configure $H $C -text $text $T header text $H $C $text } set H [$T header create -tags header3] $T header configure $H all -arrowgravity right -justify center $T header style set $H all $S foreach {C text} [list Cleft Left C1 D C2 E C3 F C4 G C5 K C6 L C7 M C8 N Cright Right] { $T header configure $H $C -text $text $T header text $H $C $text } # # Create a 4th row of column headers to test embedded windows. # $T element create header.window window -statedomain header -clip yes $T element create header.divider rect -statedomain header -fill gray -height 2 set S [$T style create headerWin -orient horizontal -statedomain header] $T style elements $S {header.divider header.window} $T style layout $S header.divider -detach yes -expand n -iexpand x $T style layout $S header.window -iexpand x -squeeze x -padx 1 -pady {0 2} set H [$T header create -tags header4] $T header dragconfigure $H -enable no $T header style set $H all $S foreach C [$T column list] { set f [frame $T.frame${H}_$C -borderwidth 0] set w [entry $f.entry -highlightthickness 1] $w insert end $C $T header element configure $H $C header.window -window $f } # # # $T item state define current $T element create theme.rect rect \ -fill {{light blue} current white {}} \ -outline gray50 -outlinewidth 2 -open s $T element create theme.text text \ -lines 0 $T element create theme.button window -clip yes set S [$T style create theme -orient vertical] $T style elements $S {theme.rect theme.text theme.button} $T style layout $S theme.rect -detach yes -iexpand xy $T style layout $S theme.text -padx 6 -pady 3 -squeeze x $T style layout $S theme.button -expand we -pady {3 6} NewButtonItem "" \ "Use no style, just the built-in header background, sort arrow and text." NewButtonItem header1 \ "Use the 'header1' style, consisting of a border element for the background and an image for the sort arrow." \ black black NewButtonItem header2 \ "Use the 'header2' style, consisting of a rounded rectangle element for the background and an image for the sort arrow." \ black blue NewButtonItem header3 \ "Use the 'header3' style, consisting of a gradient-filled rectangle element for the background and an image for the sort arrow." \ #6d6d6d win7 NewButtonItem header4 \ "Use the 'header4' style, consisting of a header element to display the background and sort arrow, and an image element serving as a checkbutton." NewButtonItem header5 \ "Use the 'header5' style, consisting of a gradient-filled rectangle element for the background and an image for the sort arrow." \ black #0080FF NewButtonItem header6 \ "Use the 'header6' style, consisting of a gradient-filled rectangle element for the background and an image for the sort arrow." \ red orange $T item state set styleheader2 current # # Create 100 regular non-locked items # $T element create item.sel rect \ -fill {gray {selected !focus} blue selected} $T element create item.text text \ -text "Item" -fill {white selected} set S [$T style create item] $T style elements $S {item.sel item.text} $T style layout $S item.sel -detach yes -iexpand xy $T style layout $S item.text -expand news -padx 2 -pady 2 $T column configure !tail -itemstyle $S $T item create -count 100 -parent root # Remember which column header is displaying the sort arrow, and # initialize the sort order in each column. variable Sort set Sort(header) "" set Sort(column) "" foreach C [$T column list] { set Sort(direction,$C) down } # The event is generated in response to Motion and # Button events in headers. $T notify install $T notify bind $T { DemoHeaders::HeaderState %H %C %s } # The event is generated when the left mouse button is # pressed and released over a column header. $T notify bind $T { DemoHeaders::HeaderInvoke %H %C } $T notify bind $T { DemoHeaders::ColumnDragBegin %H %C } # Disable the demo.tcl binding on and install our # own to deal with multiple rows of column headers. $T notify configure DontDelete -active no $T notify bind $T { DemoHeaders::ColumnDragReceive %H %C %b } bindtags $T [list $T DemoHeaders TreeCtrl [winfo toplevel $T] all] bind DemoHeaders { DemoHeaders::ButtonPress1 %x %y } return } # This procedure creates a new item with descriptive text and a pushbutton # to change the style used in the column headers. proc DemoHeaders::NewButtonItem {S text args} { set T [DemoList] set I [$T item create -parent root -tags [list style$S config]] $T item style set $I C1 theme $T item span $I all [$T column count {lock none}] $T item text $I C1 $text frame $T.frame$I -borderwidth 0 $::buttonCmd $T.frame$I.button -text "Configure headers" \ -command [eval list [list DemoHeaders::ChangeHeaderStyle $S] $args] $T item element configure $I C1 theme.button -window $T.frame$I return } proc DemoHeaders::InitSortImages {color height} { set img ::DemoHeaders::arrow-down image create photo $img if {$color eq "win7"} { $img put {{#3c5e72 #629ab9 #70a9c6 #72abca #83bad9 #95c6e0 #9ac7e0}} -to 0 0 $img put {{ #528bab #73b2d8 #99d0ee #b3dbf1 #c4e3f4 }} -to 1 1 $img put {{ #67acd3 #a6d8f3 #c4e3f4 }} -to 2 2 $img put {{ #9acbe6 }} -to 3 3 } else { for {set i 0} {$i < $height} {incr i} { set width [expr {2 * $height - ($i * 2 + 1)}] $img put [list [string repeat "$color " $width]] -to $i $i } } set img ::DemoHeaders::arrow-up image create photo $img if {$color eq "win7"} { $img put {{ #406274 }} -to 3 0 $img put {{ #3c5e72 #569bc0 #5e88a1 }} -to 2 1 $img put {{ #3c596c #6196b6 #86c8eb #91cbec #9ab6c5 }} -to 1 2 $img put {{#435f6f #87b1c5 #bae2f4 #b5ddf2 #c4e3f4 #cae6f5 #c3e4f5}} -to 0 3 } else { for {set i 0} {$i < $height} {incr i} { set width [expr {($i * 2 + 1)}] $img put [list [string repeat "$color " $width]] -to [expr {$height - $i - 1}] $i } } return } proc DemoHeaders::ChangeHeaderStyle {style {textColor ""} {sortColor ""} {imgHeight 5}} { variable HeaderStyle variable Sort set T [DemoList] # To override the system theme color on Gtk+, set the header element color # and not the widget's -headerforeground color. $T element configure header.text -fill $textColor if {$sortColor ne ""} { InitSortImages $sortColor $imgHeight } set HeaderStyle $style set S $HeaderStyle foreach H [$T header id !header4] { $T header style set $H all $S if {$S ne ""} { $T header configure all all -textpadx 6 foreach C [$T column list] { $T header text $H $C [$T header cget $H $C -text] } } } if {$Sort(header) ne ""} { ShowSortArrow $Sort(header) $Sort(column) } $T item state set {state current} !current $T item state set style$style current return } # This procedure is called to handle the event generated by # the treectrl.tcl library script. proc DemoHeaders::HeaderState {H C state} { return } # This procedure is called to handle the event generated by # the treectrl.tcl library script. # If the given column header is already displaying a sort arrow, the sort # arrow direction is toggled. Otherwise the sort arrow is removed from all # other column headers and displayed in the given column header. proc DemoHeaders::HeaderInvoke {H C} { variable Sort set T [DemoList] # if {![$T item tag expr $I header3]} return if {$Sort(header) eq ""} { ShowSortArrow $H $C } else { if {[$T header compare $H == $Sort(header)] && [$T column compare $C == $Sort(column)]} { ToggleSortArrow $H $C } else { HideSortArrow $Sort(header) $Sort(column) ShowSortArrow $H $C } } set Sort(header) $H set Sort(column) $C return } # Sets the -arrow option of a column header to 'up' or 'down'. proc DemoHeaders::ShowSortArrow {H C} { variable Sort set T [DemoList] $T header configure $H $C -arrow $Sort(direction,$C) return } # Sets the -arrow option of a column header to 'none'. proc DemoHeaders::HideSortArrow {H C} { set T [DemoList] $T header configure $H $C -arrow none return } # Toggles a sort arrow between up and down proc DemoHeaders::ToggleSortArrow {H C} { variable Sort if {$Sort(direction,$C) eq "up"} { set Sort(direction,$C) down } else { set Sort(direction,$C) up } ShowSortArrow $H $C return } # This procedure is called to handle the event generated # by the treectrl.tcl library script. # When dragging in the top row, all header-rows provide feedback. # When dragging in the second row, the 2nd, 3rd and 4th rows provide feedback. # When dragging in the third row, only the 3rd and 4rd row provides feedback. proc DemoHeaders::ColumnDragBegin {H C} { set T [DemoList] $T header dragconfigure all -draw yes if {[$T header compare $H > header1]} { $T header dragconfigure header1 -draw no } if {[$T header compare $H > header2]} { $T header dragconfigure header2 -draw no } return } # This procedure is called to handle the event generated # by the treectrl.tcl library script. proc DemoHeaders::ColumnDragReceive {H C b} { set T [DemoList] # Get the range of columns in the span of the dragged header. set span [$T header span $H $C] set last [$T column id "$C span $span"] set columns [$T column id "range $C $last"] set span1 [$T header span header1] set span2 [$T header span header2] set text1 [$T header text header1] set text2 [$T header text header2] set columnLeft [$T column id "first lock none"] foreach C $columns { $T column move $C $b } # Restore the appearance of the top row if dragging happened below if {[$T header compare $H > header1]} { foreach span $span1 text $text1 C [$T column list] { $T header span header1 $C $span $T header text header1 $C $text $T header configure header1 $C -text $text } } # Restore the appearance of the second row if dragging happened below if {[$T header compare $H > header2]} { foreach span $span2 text $text2 C [$T column list] { $T header span header2 $C $span $T header text header2 $C $text $T header configure header2 $C -text $text } } # For each of the items displaying a button widget to change the header # style, transfer the style from the old left-most column to the new # left-most column. if {[$T column compare $columnLeft != "first lock none"]} { foreach I [$T item id "tag config"] { TransferItemStyle $T $I $columnLeft "first lock none" } } return } # Copy the style and element configuration from one column of an item to # another. proc DemoHeaders::TransferItemStyle {T I Cfrom Cto} { set S [$T item style set $I $Cfrom] $T item style set $I $Cto $S foreach E [$T item style elements $I $Cfrom] { foreach info [$T item element configure $I $Cfrom $E] { lassign $info option x y z value $T item element configure $I $Cto $E $option $value } } $T item style set $I $Cfrom "" return } # This procedure is called to handle the event. # If the click was in the checkbutton image element, toggle the CHECK state. proc DemoHeaders::ButtonPress1 {x y} { set T [DemoList] $T identify -array id $x $y if {$id(where) eq "header" && $id(element) eq "header.check"} { $T header state forcolumn $id(header) $id(column) ~CHECK return -code break } return } tktreectrl-2.4.1/demos/help.tcl0000644000076400010400000002350111573536316016771 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker # # Demo: Help contents # namespace eval DemoHelpContents {} proc DemoHelpContents::Init {T} { variable Priv set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no -itemheight $height \ -selectmode browse $T configure -canvaspadx {4 0} -canvaspady {2 0} InitPics help-* # # Create columns # $T column create -text "Help Contents" -tags C0 $T configure -treecolumn C0 # # Create elements # # Define a new item state $T item state define mouseover $T element create elemImgPage image -image help-page $T element create elemImgBook image -image {help-book-open {open} help-book-closed {}} $T element create elemTxt text -fill [list $::SystemHighlightText {selected focus} blue {mouseover}] \ -font [list DemoFontUnderline {mouseover}] -lines 1 $T element create elemRectSel rect -fill [list $::SystemHighlight {selected focus}] -showfocus yes # # Create styles using the elements # # book set S [$T style create styBook] $T style elements $S {elemRectSel elemImgBook elemTxt} $T style layout $S elemImgBook -padx {0 4} -expand ns $T style layout $S elemTxt -expand ns -squeeze x $T style layout $S elemRectSel -union [list elemTxt] -iexpand ns -ipadx 2 # page set S [$T style create styPage] $T style elements $S {elemRectSel elemImgPage elemTxt} $T style layout $S elemImgPage -padx {0 4} -expand ns $T style layout $S elemTxt -expand ns -squeeze x $T style layout $S elemRectSel -union [list elemTxt] -iexpand ns -ipadx 2 # # Create items and assign styles # set parentList [list root {} {} {} {} {} {}] set parent root foreach {depth style text} { 0 styPage "Welcome to Help" 0 styBook "Introducing Windows 98" 1 styBook "How to Use Help" 2 styPage "Find a topic" 2 styPage "Get more out of help" 1 styBook "Register Your Software" 2 styPage "Registering Windows 98 online" 1 styBook "What's New in Windows 98" 2 styPage "Innovative, easy-to-use features" 2 styPage "Improved reliability" 2 styPage "A faster operating system" 2 styPage "True Web integration" 2 styPage "More entertaining and fun" 1 styBook "If You're New to Windows 98" 2 styBook "Tips for Macintosh Users" 3 styPage "Why does the mouse have two buttons?" } { set item [$T item create -open no] $T item style set $item C0 $style $T item element configure $item C0 elemTxt -text $text $T item lastchild [lindex $parentList $depth] $item incr depth set parentList [lreplace $parentList $depth $depth $item] } bind DemoHelpContents { if {[lindex [%W identify %x %y] 0] eq "header"} { TreeCtrl::DoubleButton1 %W %x %y } else { DemoHelpContents::Button1 %W %x %y } break } bind DemoHelpContents { DemoHelpContents::Button1 %W %x %y break } bind DemoHelpContents { # noop } bind DemoHelpContents { # noop } bind DemoHelpContents { DemoHelpContents::Motion %W %x %y } bind DemoHelpContents { DemoHelpContents::Motion %W %x %y } bind DemoHelpContents { if {[%W selection count] == 1} { %W item toggle [%W selection get 0] } break } set Priv(prev) "" bindtags $T [list $T DemoHelpContents TreeCtrl [winfo toplevel $T] all] return } # This is an alternate implementation that does not define a new item state # to change the appearance of the item under the cursor. proc DemoHelpContents::Init_2 {T} { variable Priv set T [DemoList] set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no -itemheight $height \ -selectmode browse InitPics help-* # # Create columns # $T column create -text "Help Contents" # # Create elements # $T element create elemImgPage image -image help-page $T element create elemImgBook image -image {help-book-open {open} help-book-closed {}} $T element create elemTxt text -fill [list $::SystemHighlightText {selected focus}] $T element create elemRectSel rect -fill [list $::SystemHighlight {selected focus}] -showfocus yes $T element create elemTxtOver text -fill [list $::SystemHighlightText {selected focus} blue {}] \ -font "[$T cget -font] underline" # # Create styles using the elements # # book set S [$T style create styBook] $T style elements $S {elemRectSel elemImgBook elemTxt} $T style layout $S elemImgBook -padx {0 4} -expand ns $T style layout $S elemTxt -expand ns $T style layout $S elemRectSel -union [list elemTxt] -iexpand ns -ipadx 2 # page set S [$T style create styPage] $T style elements $S {elemRectSel elemImgPage elemTxt} $T style layout $S elemImgPage -padx {0 4} -expand ns $T style layout $S elemTxt -expand ns $T style layout $S elemRectSel -union [list elemTxt] -iexpand ns -ipadx 2 # book (focus) set S [$T style create styBook.f] $T style elements $S {elemRectSel elemImgBook elemTxtOver} $T style layout $S elemImgBook -padx {0 4} -expand ns $T style layout $S elemTxtOver -expand ns $T style layout $S elemRectSel -union [list elemTxtOver] -iexpand ns -ipadx {1 2} # page (focus) set S [$T style create styPage.f] $T style elements $S {elemRectSel elemImgPage elemTxtOver} $T style layout $S elemImgPage -padx {0 4} -expand ns $T style layout $S elemTxtOver -expand ns $T style layout $S elemRectSel -union [list elemTxtOver] -iexpand ns -ipadx {1 2} # # Create items and assign styles # set parentList [list root {} {} {} {} {} {}] set parent root foreach {depth style text} { 0 styPage "Welcome to Help" 0 styBook "Introducing Windows 98" 1 styBook "How to Use Help" 2 styPage "Find a topic" 2 styPage "Get more out of help" 1 styBook "Register Your Software" 2 styPage "Registering Windows 98 online" 1 styBook "What's New in Windows 98" 2 styPage "Innovative, easy-to-use features" 2 styPage "Improved reliability" 2 styPage "A faster operating system" 2 styPage "True Web integration" 2 styPage "More entertaining and fun" 1 styBook "If You're New to Windows 98" 2 styBook "Tips for Macintosh Users" 3 styPage "Why does the mouse have two buttons?" } { set item [$T item create -open no] $T item style set $item 0 $style $T item element configure $item 0 elemTxt -text $text $T item lastchild [lindex $parentList $depth] $item incr depth set parentList [lreplace $parentList $depth $depth $item] } bind DemoHelpContents { if {[lindex [%W identify %x %y] 0] eq "header"} { TreeCtrl::DoubleButton1 %W %x %y } else { DemoHelpContents::Button1 %W %x %y } break } bind DemoHelpContents { DemoHelpContents::Button1 %W %x %y break } bind DemoHelpContents { # noop } bind DemoHelpContents { # noop } bind DemoHelpContents { DemoHelpContents::Motion_2 %W %x %y } bind DemoHelpContents { DemoHelpContents::Motion_2 %W %x %y } bind DemoHelpContents { if {[%W selection count] == 1} { %W item toggle [%W selection get 0] } break } set Priv(prev) "" bindtags $T [list $T DemoHelpContents TreeCtrl [winfo toplevel $T] all] return } proc DemoHelpContents::Button1 {w x y} { variable ::TreeCtrl::Priv focus $w set id [$w identify $x $y] set Priv(buttonMode) "" if {[lindex $id 0] eq "header"} { TreeCtrl::ButtonPress1 $w $x $y } elseif {[lindex $id 0] eq "item"} { set item [lindex $id 1] # didn't click an element if {[llength $id] != 6} return if {[$w selection includes $item]} { $w item toggle $item return } if {[$w selection count]} { set item2 [$w selection get 0] $w item collapse $item2 foreach item2 [$w item ancestors $item2] { if {[$w item compare $item != $item2]} { $w item collapse $item2 } } } $w activate $item $w item expand [list $item ancestors] $w item toggle $item $w selection modify $item all } return } proc DemoHelpContents::Motion {w x y} { variable Priv set id [$w identify $x $y] if {$id eq ""} { } elseif {[lindex $id 0] eq "header"} { } elseif {[lindex $id 0] eq "item"} { set item [lindex $id 1] if {[llength $id] == 6} { if {$item ne $Priv(prev)} { if {$Priv(prev) ne ""} { $w item state set $Priv(prev) !mouseover } $w item state set $item mouseover $w configure -cursor hand2 set Priv(prev) $item } return } } if {$Priv(prev) ne ""} { $w item state set $Priv(prev) !mouseover $w configure -cursor "" set Priv(prev) "" } return } # Alternate implementation that does not rely on run-time states proc DemoHelpContents::Motion_2 {w x y} { variable Priv set id [$w identify $x $y] if {[lindex $id 0] eq "header"} { } elseif {$id ne ""} { set item [lindex $id 1] if {[llength $id] == 6} { if {$item ne $Priv(prev)} { if {$Priv(prev) ne ""} { set style [$w item style set $Priv(prev) 0] set style [string trim $style .f] $w item style map $Priv(prev) 0 $style {elemTxtOver elemTxt} } set style [$w item style set $item 0] $w item style map $item 0 $style.f {elemTxt elemTxtOver} set Priv(prev) $item } return } } if {$Priv(prev) ne ""} { set style [$w item style set $Priv(prev) 0] set style [string trim $style .f] $w item style map $Priv(prev) 0 $style {elemTxtOver elemTxt} set Priv(prev) "" } return } tktreectrl-2.4.1/demos/imovie.tcl0000644000076400010400000001021011573536552017324 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker # # Demo: iMovie # namespace eval DemoIMovie {} proc DemoIMovie::Init {T} { # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no \ -selectmode browse -orient horizontal -wrap window \ -showheader no -background #dcdcdc -yscrollsmoothing yes $T configure -canvaspadx 8 -canvaspady 8 \ -itemgapx 8 -itemgapy 8 # # Create columns # $T column create -tags C0 InitPics imovie-* switch -- $::thisPlatform { macintosh - macosx { set font1 {Geneva 10} set font2 {Geneva 11} } unix { set font1 {Helvetica 12} set font2 {Helvetica 14} } default { set font1 {Helvetica 8} set font2 {Helvetica 10} } } # # Create elements # $T element create elemTime text -font [list $font1] $T element create elemName text -font [list $font2] -lines 1 -width 80 $T element create elemRect rect -fill {#ffdc5a {selected} white {}} \ -outline #827878 -outlinewidth 1 $T element create elemImg image $T element create elemShadow rect -outline gray -outlinewidth 1 -open wn # # Create styles using the elements # set S [$T style create STYLE -orient vertical] $T style elements $S {elemShadow elemRect elemTime elemImg elemName} $T style layout $S elemShadow -detach yes -padx {1 0} -pady {1 0} -iexpand xy $T style layout $S elemTime -padx {2 0} $T style layout $S elemImg -pady {0 1} $T style layout $S elemName -expand we -ipady {0 2} -padx {0 3} -squeeze x $T style layout $S elemRect -union {elemTime elemImg elemName} \ -ipadx 6 -padx {0 1} -pady {0 1} # Set default item style $T column configure C0 -itemstyle $S # # Create items and assign styles # for {set i 0} {$i < 5} {incr i} { foreach {time name image} { 15:20 "Clip 1" imovie-01 19:18 "Clip 2" imovie-02 07:20 "Clip 3" imovie-03 07:20 "Clip 4" imovie-04 07:20 "Clip 5" imovie-05 07:20 "Clip 6" imovie-06 07:20 "Clip 7" imovie-07 } { set I [$T item create] # $T item style set $I C0 $S $T item element configure $I C0 \ elemTime -text $time + \ elemImg -image $image + \ elemName -text $name $T item lastchild root $I } } $T notify bind $T { %T item element configure %I %C %E -text %t } bind DemoIMovie { DemoIMovie::Button1 %W %x %y } bindtags $T [list $T DemoIMovie TreeCtrl [winfo toplevel $T] all] return } proc DemoIMovie::Button1 {T x y} { focus $T set id [$T identify $x $y] # Click outside any item if {$id eq ""} { # Click in header } elseif {[lindex $id 0] eq "header"} { ::TreeCtrl::ButtonPress1 $T $x $y # Click in item } elseif {[lindex $id 0] eq "item"} { ::TreeCtrl::ButtonPress1 $T $x $y update lassign $id where item arg1 arg2 arg3 arg4 switch $arg1 { column { set I [lindex $id 1] if {[llength $id] == 6} { set E [lindex $id end] if {$E eq "elemName"} { set exists [winfo exists $T.entry] ::TreeCtrl::EntryOpen $T $I C0 $E if {!$exists} { $T.entry configure -borderwidth 0 -justify center \ -background #ffdc5a scan [$T item bbox $I C0 $E] "%d %d %d %d" x1 y1 x2 y2 place $T.entry -y [expr {$y1 - 1}] } $T.entry selection clear scan [$T item bbox $I C0 elemImg] "%d %d %d %d" x1 y1 x2 y2 set left $x1 set right $x2 place $T.entry -x $left -width [expr {$right - $left}] $T.entry icursor [$T.entry index @[expr {$x - ($x1 + 1)}]] # Disable mouse tracking unset ::TreeCtrl::Priv(buttonMode) } } } } } return -code break } # # Demo: iMovie (Wrap) # namespace eval DemoIMovieWrap {} proc DemoIMovieWrap::Init {T} { DemoIMovie::Init $T $T configure -wrap "" -xscrollsmoothing yes $T item configure "root child 4" -wrap yes $T item configure "root child 5" -wrap yes $T item configure "root child 8" -wrap yes $T item configure "root child 10" -wrap yes $T item configure "root child 15" -wrap yes # $T item configure "root child 15" -wrap yes $T item configure "root child 25" -wrap yes return } tktreectrl-2.4.1/demos/layout.tcl0000644000076400010400000001147211573536722017363 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker # # Demo: Layout # namespace eval DemoLayout {} proc DemoLayout::Init {T} { # # Configure the treectrl widget # $T configure -showroot no -showrootbutton yes -showbuttons yes \ -showlines [ShouldShowLines $T] -itemheight 0 -selectmode browse # # Create columns # $T column create -text Layout -itemjustify left -justify center -tags C0 $T configure -treecolumn C0 # # Create elements # $T element create e1 rect -width 30 -height 30 -fill gray20 $T element create e2 rect -width 30 -height 30 -fill gray40 \ -outline blue -outlinewidth 3 $T element create e3 rect -fill gray60 $T element create e4 rect -fill [list $::SystemHighlight {selected focus} gray80 {}] \ -showfocus yes $T element create e5 rect -fill {"sky blue"} -width 20 -height 20 $T element create e6 rect -fill {"sea green"} -width 30 -height 16 $T element create e7 rect -fill {"sky blue"} -width 30 -height 16 $T element create e8 rect -fill gray70 -height 1 # # Create styles using the elements # set S [$T style create s1] $T style elements $S {e4 e3 e1 e2 e5 e6 e7} $T style layout $S e1 -padx {28 4} -pady 4 $T style layout $S e2 -expand es -padx {0 38} $T style layout $S e3 -union [list e1 e2] -ipadx 4 -ipady 4 -pady 2 $T style layout $S e4 -detach yes -iexpand xy $T style layout $S e5 -detach yes -padx {2 0} -pady 2 -iexpand y $T style layout $S e6 -detach yes -expand ws -padx {0 2} -pady {2 0} $T style layout $S e7 -detach yes -expand wn -padx {0 2} -pady {0 2} # # Create items and assign styles # set I [$T item create -button yes] $T item style set $I C0 $S $T item lastchild root $I set parent $I set I [$T item create] $T item style set $I C0 $S $T item lastchild $parent $I ### set S [$T style create s2] $T style elements $S {e4 e3 e1} $T style layout $S e1 -padx 8 -pady 8 -iexpand x $T style layout $S e3 -union e1 -ipadx {20 4} -ipady {4 12} $T style layout $S e4 -detach yes -iexpand xy set I [$T item create -button yes] $T item style set $I C0 $S $T item lastchild root $I set I2 [$T item create] $T item style set $I2 C0 $S $T item lastchild $I $I2 ### set S [$T style create s3] $T style elements $S {e4 e3 e1 e5 e6} $T style layout $S e4 -union {e1 e6} -ipadx 8 -ipady {8 0} $T style layout $S e3 -union {e1 e5} -ipadx 4 -ipady 4 $T style layout $S e5 -height 40 set I [$T item create -button yes] $T item style set $I C0 $S $T item lastchild root $I set I2 [$T item create] $T item style set $I2 C0 $S $T item lastchild $I $I2 ### $T element create eb border -background $::SystemButtonFace \ -relief {sunken {selected} raised {}} -thickness 2 -filled yes $T element create et text -lmargin2 20 set text "Here is a text element surrounded by a border element.\nResize the column to watch me wrap." set S [$T style create s4] $T style elements $S {eb et} $T style layout $S eb -union et -ipadx 2 -ipady 2 $T style layout $S et -squeeze x set I [$T item create -button yes] $T item style set $I C0 $S $T item text $I C0 $text $T item lastchild root $I set parent $I set I [$T item create] $T item style set $I C0 $S $T item text $I C0 $text $T item lastchild $parent $I ### set S [$T style create s5] $T style elements $S {e1 e2 e3 e4 e5 e6 e7 e8} $T style layout $S e1 -union e2 -ipadx 4 -ipady 4 $T style layout $S e2 -union e3 -ipadx 4 -ipady 4 -visible {no selected} $T style layout $S e3 -union e4 -ipadx 4 -ipady 4 $T style layout $S e4 -width 30 -height 30 $T style layout $S e5 -union e6 -ipadx 4 -ipady 4 $T style layout $S e6 -union e7 -ipadx 4 -ipady 4 -visible {no selected} $T style layout $S e7 -union e8 -ipadx 4 -ipady 4 $T style layout $S e8 -width 30 -height 30 -padx {24 0} set I [$T item create -button yes] $T item style set $I C0 $S $T item lastchild root $I set I2 [$T item create] $T item style set $I2 C0 $S $T item lastchild $I $I2 ### set styleNum 6 foreach {orient expandList} {horizontal {s ns n} vertical {e we w}} { foreach expand $expandList { set S [$T style create s$styleNum -orient $orient] $T style elements $S {e4 e8 e3 e2 e5 e6} $T style layout $S e4 -detach yes -iexpand xy $T style layout $S e8 -detach yes -expand n -iexpand x $T style layout $S e3 -union {e2 e5 e6} -ipadx 5 -ipady 5 $T style layout $S e2 -expand $expand $T style layout $S e5 -expand $expand -visible {no !selected} $T style layout $S e6 -expand $expand incr styleNum set I [$T item create] $T item style set $I C0 $S $T item lastchild root $I } } return } tktreectrl-2.4.1/demos/mailwasher.tcl0000644000076400010400000001470511573537006020200 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker # # Demo: MailWasher # namespace eval DemoMailWasher {} proc DemoMailWasher::Init {T} { InitPics *checked set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -showroot no -showrootbutton no -showbuttons no \ -showlines no -itemheight $height -selectmode browse \ -xscrollincrement 20 -xscrollsmoothing yes # # Create columns # set pad 4 $T column create -text Delete -textpadx $pad -justify center -tags delete $T column create -text Bounce -textpadx $pad -justify center -tags bounce $T column create -text Status -width 80 -textpadx $pad -tags status $T column create -text Size -width 40 -textpadx $pad -justify right -tags size $T column create -text From -width 140 -textpadx $pad -tags from $T column create -text Subject -width 240 -textpadx $pad -tags subject $T column create -text Received -textpadx $pad -arrow up -tags received $T column create -text Attachments -textpadx $pad -tags attachments $T item state define CHECK # # Create elements # $T element create border rect -open nw -outline gray -outlinewidth 1 \ -fill [list $::SystemHighlight {selected}] $T element create imgCheck image -image {checked CHECK unchecked {}} $T element create txtAny text \ -fill [list $::SystemHighlightText {selected}] -lines 1 $T element create txtNone text -text "none" \ -fill [list $::SystemHighlightText {selected}] -lines 1 $T element create txtYes text -text "yes" \ -fill [list $::SystemHighlightText {selected}] -lines 1 $T element create txtNormal text -text "Normal" \ -fill [list $::SystemHighlightText {selected} #006800 {}] -lines 1 $T element create txtPossSpam text -text "Possible Spam" \ -fill [list $::SystemHighlightText {selected} #787800 {}] -lines 1 $T element create txtProbSpam text -text "Probably Spam" \ -fill [list $::SystemHighlightText {selected} #FF9000 {}] -lines 1 $T element create txtBlacklist text -text "Blacklisted" \ -fill [list $::SystemHighlightText {selected} #FF5800 {}] -lines 1 # # Create styles using the elements # set S [$T style create styCheck] $T style elements $S [list border imgCheck] $T style layout $S border -detach yes -iexpand xy $T style layout $S imgCheck -expand news set pad 4 foreach name {Any None Yes Normal PossSpam ProbSpam Blacklist} { set S [$T style create sty$name] $T style elements $S [list border txt$name] $T style layout $S border -detach yes -iexpand xy $T style layout $S txt$name -padx $pad -squeeze x -expand ns } # # Create items and assign styles # for {set i 0} {$i < 1} {incr i} { foreach {from subject} { baldy@spammer.com "Your hair is thinning" flat@spammer.com "Your breasts are too small" tiny@spammer.com "Your penis is too small" dumbass@spammer.com "You are not very smart" bankrobber@spammer.com "You need more money" loser@spammer.com "You need better friends" gossip@spammer.com "Find out what your coworkers think about you" whoami@spammer.com "Find out what you think about yourself" downsized@spammer.com "You need a better job" poorhouse@spammer.com "Your mortgage is a joke" spam4ever@spammer.com "You need more spam" } { set item [$T item create] set status [lindex [list styNormal styPossSpam styProbSpam styBlacklist] [expr int(rand() * 4)]] set delete [expr int(rand() * 2)] set bounce [expr int(rand() * 2)] set attachments [lindex [list styNone styYes] [expr int(rand() * 2)]] $T item style set $item delete styCheck bounce styCheck \ status $status size styAny \ from styAny subject styAny received styAny \ attachments $attachments if {$delete} { $T item state forcolumn $item delete CHECK } if {$bounce} { $T item state forcolumn $item bounce CHECK } set bytes [expr {512 + int(rand() * 1024 * 12)}] set size [expr {$bytes / 1024 + 1}]KB set seconds [expr {[clock seconds] - int(rand() * 100000)}] set received [clock format $seconds -format "%d/%m/%y %I:%M %p"] $T item text $item size $size from $from subject $subject received $received $T item lastchild root $item } } if 0 { $T notify bind MailWasher { %T item style set %I %C styOff } $T notify bind MailWasher { %T item style set %I %C styOn } } set ::SortColumn received $T notify bind $T { if {[%T column compare %C == $SortColumn]} { if {[%T column cget $SortColumn -arrow] eq "down"} { set order -increasing set arrow up } else { set order -decreasing set arrow down } } else { if {[%T column cget $SortColumn -arrow] eq "down"} { set order -decreasing set arrow down } else { set order -increasing set arrow up } %T column configure $SortColumn -arrow none set SortColumn %C } %T column configure %C -arrow $arrow switch [%T column cget %C -tags] { bounce - delete { %T item sort root $order -column %C -command [list DemoMailWasher::CompareOnOff %T %C] -column subject -dictionary } status { %T item sort root $order -column %C -dictionary } from { %T item sort root $order -column %C -dictionary -column subject -dictionary } subject { %T item sort root $order -column %C -dictionary } size { %T item sort root $order -column %C -dictionary -column subject -dictionary } received { %T item sort root $order -column %C -dictionary -column subject -dictionary } attachments { %T item sort root $order -column %C -dictionary -column subject -dictionary } } } bind DemoMailWasher { set id [%W identify %x %y] if {$id eq ""} { } elseif {[lindex $id 0] eq "header"} { } else { lassign $id what item where arg1 arg2 arg3 if {$where eq "column"} { if {[%W column tag expr $arg1 {delete || bounce}]} { %W item state forcolumn $item $arg1 ~CHECK # return -code break } } } } bindtags $T [list $T DemoMailWasher TreeCtrl [winfo toplevel $T] all] return } proc DemoMailWasher::CompareOnOff {T C item1 item2} { set s1 [$T item state forcolumn $item1 $C] set s2 [$T item state forcolumn $item2 $C] if {$s1 eq $s2} { return 0 } if {[lsearch -exact $s1 CHECK] == -1} { return -1 } return 1 } tktreectrl-2.4.1/demos/mycomputer.tcl0000644000076400010400000000767311573537122020255 0ustar TimAdministrators# Copyright (c) 2006-2011 Tim Baker namespace eval DemoMyComputer {} proc DemoMyComputer::Init {T} { set font [.menubar cget -font] if {[lsearch -exact [font names] DemoMyComputerHeaderFont] == -1} { array set fontInfo [font actual $font] set fontInfo(-weight) bold eval font create DemoMyComputerHeaderFont [array get fontInfo] } # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no \ -selectmode browse -xscrollincrement 20 -xscrollsmoothing yes \ -font $font # # Create columns # $T column create -text Name -tags name -width 200 $T column create -text Type -tags type -width 120 $T column create -text "Total Size" -tags size -justify right -width 100 \ -arrowside left -arrowgravity right $T column create -text "Free Space" -tags free -justify right -width 100 $T column create -text Comments -tags comment -width 120 # # Create elements # $T element create txtHeader text -font [list DemoMyComputerHeaderFont] $T element create txtName text -fill [list $::SystemHighlightText {selected focus}] \ -lines 1 $T element create txtOther text -lines 1 $T element create elemRectSel rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] -showfocus yes $T gradient create G_divider -stops {{0.0 blue} {0.8 blue} {1.0 white}} \ -steps 12 $T element create rectDivider rect -fill G_divider -height 1 -width 250 # # Create styles using the elements # # header set S [$T style create styHeader -orient vertical] $T style elements $S {txtHeader rectDivider} $T style layout $S txtHeader -padx 10 -pady {10 0} -expand ns $T style layout $S rectDivider -pady {2 8} # name set S [$T style create styName -orient horizontal] $T style elements $S {elemRectSel txtName} $T style layout $S txtName -padx {16 0} -squeeze x -expand ns $T style layout $S elemRectSel -union [list txtName] -ipadx 2 -pady 1 -iexpand ns # other text set S [$T style create styOther] $T style elements $S txtOther $T style layout $S txtOther -padx 6 -squeeze x -expand ns # # Create items and assign styles # foreach {name type size free comment} { "Files Stored on This Computer" "" "" "" "" "Shared Documents" "File Folder" "" "" "" "Tim's Documents" "File Folder" "" "" "" "Hard Disk Drives" "" "" "" "" "Local Disk (C:)" "Local Disk" "55.8 GB" "1.84 GB" "" "Devices with Removable Storage" "" "" "" "" "3.5 Floppy (A:)" "3.5-Inch Floppy Disk" "" "" "" "DVD Drive (D:)" "CD Drive" "" "" "" "CD-RW Drive (E:)" "CD Drive" "" "" "" "Other" "" "" "" "" "My Logitech Pictures" "System Folder" "" "" "" "Scanners and Cameras" "" "" "" "" "Logitech QuickCam Messenger" "Digital camera" "" "" "" } { set I [$T item create] if {$type eq ""} { $T item style set $I first styHeader $T item span $I first [$T column count] # The headers are disabled so they can't be selected and # keyboard navigation skips over them. $T item enabled $I false $T item text $I name $name } else { $T item style set $I name styName type styOther $T item text $I name $name type $type if {$size ne ""} { $T item style set $I size styOther free styOther $T item text $I size $size free $free } } $T item lastchild root $I } if 0 { # List of lists: {column style element ...} specifying text elements # the user can edit TreeCtrl::SetEditable $T { } # List of lists: {column style element ...} specifying elements # the user can click on or select with the selection rectangle TreeCtrl::SetSensitive $T { {name styName txtName} } # List of lists: {column style element ...} specifying elements # added to the drag image when dragging selected items TreeCtrl::SetDragImage $T { {name styName txtName} } bindtags $T [list $T TreeCtrlFileList TreeCtrl [winfo toplevel $T] all] } return } tktreectrl-2.4.1/demos/outlook-folders.tcl0000644000076400010400000001617111573537335021200 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker # # Demo: Outlook Express folder list # namespace eval DemoOutlookFolders {} proc DemoOutlookFolders::Init {T} { InitPics outlook-* set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -itemheight $height -selectmode browse \ -showroot yes -showrootbutton no -showbuttons yes \ -showlines [ShouldShowLines $T] $T configure -canvaspadx {4 0} -canvaspady {2 0} # # Create columns # $T column create -text Folders -tags C0 $T configure -treecolumn C0 # # Create custom item states. # When an item has the custom "unread" state, the elemTxtName element # uses a bold font and the elemTxtCount element is visible. # $T item state define unread # # Create elements # $T element create elemImg image $T element create elemTxtName text -fill [list $::SystemHighlightText {selected focus}] \ -font [list DemoFontBold unread] -lines 1 $T element create elemTxtCount text -fill blue $T element create elemRectSel rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ -showfocus yes # # Create styles using the elements # # image + text + text set S [$T style create styFolder] $T style elements $S {elemRectSel elemImg elemTxtName elemTxtCount} $T style layout $S elemImg -expand ns $T style layout $S elemTxtName -padx 4 -expand ns -squeeze x $T style layout $S elemTxtCount -expand ns -visible {yes unread no {}} $T style layout $S elemRectSel -union [list elemTxtName] -iexpand ns -ipadx 2 # # Create items and assign styles # $T item style set root C0 $S $T item element configure root C0 \ elemImg -image outlook-main + \ elemTxtName -text "Outlook Express" set parentList [list root {} {} {} {} {} {}] set parent root foreach {depth img text button unread} { 0 local "Local Folders" yes 0 1 inbox Inbox no 5 1 outbox Outbox no 0 1 sent "Sent Items" no 0 1 deleted "Deleted Items" no 50 1 draft Drafts no 0 1 folder "Messages to Dad" no 0 1 folder "Messages to Sis" no 0 1 folder "Messages to Me" yes 5 2 folder "2001" no 0 2 folder "2000" no 0 2 folder "1999" no 0 0 server "news.gmane.org" yes 0 1 group "gmane.comp.lang.lua.general" no 498 } { set item [$T item create -button $button] $T item style set $item C0 $S $T item element configure $item C0 \ elemImg -image outlook-$img + \ elemTxtName -text $text if {$unread} { $T item element configure $item C0 \ elemTxtCount -text "($unread)" $T item state set $item unread } $T item lastchild [lindex $parentList $depth] $item incr depth set parentList [lreplace $parentList $depth $depth $item] } return } # # Here is the original implementation which doesn't use custom states. # It has 4 different item styles and 6 different elements. # proc DemoOutlookFolders::Init.orig {T} { InitPics outlook-* set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -itemheight $height -selectmode browse \ -showroot yes -showrootbutton no -showbuttons yes \ -showlines [ShouldShowLines $T] $T configure -canvaspadx {4 0} -canvaspady {2 0} # # Create columns # $T column create -text Folders -tags C0 $T configure -treecolumn C0 # # Create elements # $T element create elemImgAny image $T element create elemTxtRead text -fill [list $::SystemHighlightText {selected focus}] \ -lines 1 $T element create elemTxtUnread text -fill [list $::SystemHighlightText {selected focus}] \ -font [list DemoFontBold] -lines 1 $T element create elemTxtCount text -fill blue $T element create elemImgFolder image -image outlook-folder $T element create elemRectSel rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ -showfocus yes # # Create styles using the elements # # image + text set S [$T style create styAnyRead] $T style elements $S {elemRectSel elemImgAny elemTxtRead} $T style layout $S elemImgAny -expand ns $T style layout $S elemTxtRead -padx {4 0} -expand ns -squeeze x $T style layout $S elemRectSel -union [list elemTxtRead] -iexpand ns -ipadx 2 # image + text + text set S [$T style create styAnyUnread] $T style elements $S {elemRectSel elemImgAny elemTxtUnread elemTxtCount} $T style layout $S elemImgAny -expand ns $T style layout $S elemTxtUnread -padx 4 -expand ns -squeeze x $T style layout $S elemTxtCount -expand ns $T style layout $S elemRectSel -union [list elemTxtUnread] -iexpand ns -ipadx 2 # folder + text set S [$T style create styFolderRead] $T style elements $S {elemRectSel elemImgFolder elemTxtRead} $T style layout $S elemImgFolder -expand ns $T style layout $S elemTxtRead -padx {4 0} -expand ns -squeeze x $T style layout $S elemRectSel -union [list elemTxtRead] -iexpand ns -ipadx 2 # folder + text + text set S [$T style create styFolderUnread] $T style elements $S {elemRectSel elemImgFolder elemTxtUnread elemTxtCount} $T style layout $S elemImgFolder -expand ns $T style layout $S elemTxtUnread -padx 4 -expand ns -squeeze x $T style layout $S elemTxtCount -expand ns $T style layout $S elemRectSel -union [list elemTxtUnread] -iexpand ns -ipadx 2 # # Create items and assign styles # $T item style set root C0 styAnyRead $T item element configure root C0 \ elemImgAny -image outlook-main + \ elemTxtRead -text "Outlook Express" set parentList [list root {} {} {} {} {} {}] set parent root foreach {depth img text button unread} { 0 local "Local Folders" yes 0 1 inbox Inbox no 5 1 outbox Outbox no 0 1 sent "Sent Items" no 0 1 deleted "Deleted Items" no 50 1 draft Drafts no 0 1 folder "Messages to Dad" no 0 1 folder "Messages to Sis" no 0 1 folder "Messages to Me" yes 5 2 folder "2001" no 0 2 folder "2000" no 0 2 folder "1999" no 0 0 server "news.gmane.org" yes 0 1 group "gmane.comp.lang.lua.general" no 498 } { set item [$T item create -button $button] if {[string equal $img folder]} { if {$unread} { $T item style set $item C0 styFolderUnread $T item element configure $item C0 \ elemTxtUnread -text $text + \ elemTxtCount -text "($unread)" } else { $T item style set $item C0 styFolderRead $T item element configure $item C0 elemTxtRead -text $text } } else { if {$unread} { $T item style set $item C0 styAnyUnread $T item element configure $item C0 \ elemImgAny -image outlook-$img + \ elemTxtUnread -text $text + \ elemTxtCount -text "($unread)" } else { $T item style set $item C0 styAnyRead $T item element configure $item C0 \ elemImgAny -image outlook-$img + \ elemTxtRead -text $text } } $T item lastchild [lindex $parentList $depth] $item incr depth set parentList [lreplace $parentList $depth $depth $item] } return } tktreectrl-2.4.1/demos/outlook-newgroup.tcl0000644000076400010400000003416211573540327021403 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker # # Demo: Outlook Express newsgroup messages # namespace eval DemoOutlookNewsgroup {} proc DemoOutlookNewsgroup::Init {T} { variable Priv InitPics outlook-* set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -itemheight $height -selectmode browse \ -showroot no -showrootbutton no -showbuttons yes -showlines no \ -xscrollincrement 20 -xscrollsmoothing yes switch -- [$T theme platform] { visualstyles { $T theme setwindowtheme "Explorer" } } # # Create columns # $T column create -image outlook-clip -tags clip $T column create -image outlook-arrow -tags arrow $T column create -image outlook-watch -tags watch $T column create -text Subject -width 250 -tags subject $T column create -text From -width 150 -tags from $T column create -text Sent -width 150 -tags sent $T column create -text Size -width 60 -justify right -tags size # $T column configure all -gridrightcolor #ebf4fe # Would be nice if I could specify a column -tag too # *blink* The amazing code Genie makes it so!!! $T configure -treecolumn subject # State for a read message $T item state define read # State for a message with unread descendants $T item state define unread # States for "open" rectangles. This is an ugly hack to get the # active outline to span multiple columns. $T item state define openWE $T item state define openE $T item state define openW # # Create elements # $T element create elemImg image -image { outlook-read-2Sel {selected read unread !open} outlook-read-2 {read unread !open} outlook-readSel {selected read} outlook-read {read} outlook-unreadSel {selected} outlook-unread {} } $T element create elemTxt text -fill [list $::SystemHighlightText {selected focus}] \ -font [list DemoFontBold {read unread !open} DemoFontBold {!read}] -lines 1 $T element create sel rect \ -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ -open {we openWE e openE w openW} -showfocus yes # # Create styles using the elements # # Image + text set S [$T style create s1] $T style elements $S {sel elemImg elemTxt} $T style layout $S elemImg -expand ns $T style layout $S elemTxt -padx {2 6} -squeeze x -expand ns $T style layout $S sel -union [list elemTxt] -iexpand nes -ipadx {2 0} # Text set S [$T style create s2] $T style elements $S {sel elemTxt} $T style layout $S elemTxt -padx 6 -squeeze x -expand ns $T style layout $S sel -detach yes -iexpand xy # Set default item styles $T column configure subject -itemstyle s1 $T column configure from -itemstyle s2 $T column configure sent -itemstyle s2 $T column configure size -itemstyle s2 # # Create items and assign styles # set msgCnt 100 set thread 0 set Priv(count,0) 0 set items [$T item id root] for {set i 1} {$i < $msgCnt} {incr i} { set itemi [$T item create] while 1 { set j [expr {int(rand() * $i)}] set itemj [lindex $items $j] if {$j == 0} break if {[$T depth $itemj] == 5} continue if {$Priv(count,$Priv(thread,$itemj)) == 15} continue break } $T item lastchild $itemj $itemi set Priv(read,$itemi) [expr rand() * 2 > 1] if {$j == 0} { set Priv(thread,$itemi) [incr thread] set Priv(seconds,$itemi) [expr {[clock seconds] - int(rand() * 500000)}] set Priv(seconds2,$itemi) $Priv(seconds,$itemi) set Priv(count,$thread) 1 } else { set Priv(thread,$itemi) $Priv(thread,$itemj) set Priv(seconds,$itemi) [expr {$Priv(seconds2,$itemj) + int(rand() * 10000)}] set Priv(seconds2,$itemi) $Priv(seconds,$itemi) set Priv(seconds2,$itemj) $Priv(seconds,$itemi) incr Priv(count,$Priv(thread,$itemj)) } lappend items $itemi } for {set i 1} {$i < $msgCnt} {incr i} { set itemi [lindex $items $i] set subject "This is thread number $Priv(thread,$itemi)" set from somebody@somewhere.net set sent [clock format $Priv(seconds,$itemi) -format "%d/%m/%y %I:%M %p"] set size [expr {1 + int(rand() * 10)}]KB # This message has been read if {$Priv(read,$itemi)} { $T item state set $itemi read } # This message has unread descendants if {[AnyUnreadDescendants $T $itemi]} { $T item state set $itemi unread } if {[$T item numchildren $itemi]} { $T item configure $itemi -button yes # Collapse some messages if {rand() * 2 > 1} { $T item collapse $itemi } } # $T item style set $i 3 s1 4 s2.we 5 s2.we 6 s2.w $T item text $itemi subject $subject from $from sent $sent size $size $T item state forcolumn $itemi subject openE $T item state forcolumn $itemi from openWE $T item state forcolumn $itemi sent openWE $T item state forcolumn $itemi size openW } # Do something when the selection changes $T notify bind $T { DemoOutlookNewsgroup::Selection %T } # Fix the display when a column is dragged $T notify bind $T { %T column move %C %b DemoOutlookNewsgroup::FixItemStyles %T } # Fix the display when a column's visibility changes $T notify bind $T { DemoOutlookNewsgroup::FixItemStyles %T } return } proc DemoOutlookNewsgroup::Selection {T} { variable Priv # One item is selected if {[$T selection count] == 1} { if {[info exists Priv(afterId)]} { after cancel $Priv(afterId) } set Priv(afterId,item) [$T selection get 0] set Priv(afterId) [after 500 DemoOutlookNewsgroup::MessageReadDelayed] } return } proc DemoOutlookNewsgroup::MessageReadDelayed {} { variable Priv set T [DemoList] unset Priv(afterId) set I $Priv(afterId,item) if {![$T selection includes $I]} return # This message is not read if {!$Priv(read,$I)} { # Read the message $T item state set $I read set Priv(read,$I) 1 # Check ancestors (except root) foreach I2 [lrange [$T item ancestors $I] 0 end-1] { # This ancestor has no more unread descendants if {![AnyUnreadDescendants $T $I2]} { $T item state set $I2 !unread } } } return } # Alternate implementation that does not rely on run-time states proc DemoOutlookNewsgroup::Init_2 {T} { global Message InitPics outlook-* set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -itemheight $height -selectmode browse \ -showroot no -showrootbutton no -showbuttons yes -showlines no # # Create columns # $T column create -image outlook-clip -tags clip $T column create -image outlook-arrow -tags arrow $T column create -image outlook-watch -tags watch $T column create -text Subject -width 250 -tags subject $T column create -text From -width 150 -tags from $T column create -text Sent -width 150 -tags sent $T column create -text Size -width 60 -justify right -tags size $T configure -treecolumn 3 # # Create elements # $T element create image.unread image -image outlook-unread $T element create image.read image -image outlook-read $T element create image.read2 image -image outlook-read-2 $T element create text.read text -fill [list $::SystemHighlightText {selected focus}] \ -lines 1 $T element create text.unread text -fill [list $::SystemHighlightText {selected focus}] \ -font [list DemoFontBold] -lines 1 $T element create sel.e rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] -open e -showfocus yes $T element create sel.w rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] -open w -showfocus yes $T element create sel.we rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] -open we -showfocus yes # # Create styles using the elements # # Image + text set S [$T style create unread] $T style elements $S {sel.e image.unread text.unread} $T style layout $S image.unread -expand ns $T style layout $S text.unread -padx {2 6} -squeeze x -expand ns $T style layout $S sel.e -union [list text.unread] -iexpand nes -ipadx {2 0} # Image + text set S [$T style create read] $T style elements $S {sel.e image.read text.read} $T style layout $S image.read -expand ns $T style layout $S text.read -padx {2 6} -squeeze x -expand ns $T style layout $S sel.e -union [list text.read] -iexpand nes -ipadx {2 0} # Image + text set S [$T style create read2] $T style elements $S {sel.e image.read2 text.unread} $T style layout $S image.read2 -expand ns $T style layout $S text.unread -padx {2 6} -squeeze x -expand ns $T style layout $S sel.e -union [list text.unread] -iexpand nes -ipadx {2 0} # Text set S [$T style create unread.we] $T style elements $S {sel.we text.unread} $T style layout $S text.unread -padx 6 -squeeze x -expand ns $T style layout $S sel.we -detach yes -iexpand xy # Text set S [$T style create read.we] $T style elements $S {sel.we text.read} $T style layout $S text.read -padx 6 -squeeze x -expand ns $T style layout $S sel.we -detach yes -iexpand xy # Text set S [$T style create unread.w] $T style elements $S {sel.w text.unread} $T style layout $S text.unread -padx 6 -squeeze x -expand ns $T style layout $S sel.w -detach yes -iexpand xy # Text set S [$T style create read.w] $T style elements $S {sel.w text.read} $T style layout $S text.read -padx 6 -squeeze x -expand ns $T style layout $S sel.w -detach yes -iexpand xy # # Create items and assign styles # set msgCnt 100 set thread 0 set Priv(count,0) 0 for {set i 1} {$i < $msgCnt} {incr i} { $T item create while 1 { set j [expr {int(rand() * $i)}] if {$j == 0} break if {[$T depth $j] == 5} continue if {$Priv(count,$Priv(thread,$j)) == 15} continue break } $T item lastchild $j $i set Priv(read,$i) [expr rand() * 2 > 1] if {$j == 0} { set Priv(thread,$i) [incr thread] set Priv(seconds,$i) [expr {[clock seconds] - int(rand() * 500000)}] set Priv(seconds2,$i) $Priv(seconds,$i) set Priv(count,$thread) 1 } else { set Priv(thread,$i) $Priv(thread,$j) set Priv(seconds,$i) [expr {$Priv(seconds2,$j) + int(rand() * 10000)}] set Priv(seconds2,$i) $Priv(seconds,$i) set Priv(seconds2,$j) $Priv(seconds,$i) incr Priv(count,$Priv(thread,$j)) } } for {set i 1} {$i < $msgCnt} {incr i} { set subject "This is thread number $Priv(thread,$i)" set from somebody@somewhere.net set sent [clock format $Priv(seconds,$i) -format "%d/%m/%y %I:%M %p"] set size [expr {1 + int(rand() * 10)}]KB if {$Priv(read,$i)} { set style read set style2 read } else { set style unread set style2 unread } $T item style set $i 3 $style 4 $style2.we 5 $style2.we 6 $style2.w $T item text $i 3 $subject 4 $from 5 $sent 6 $size if {[$T item numchildren $i]} { $T item configure $i -button yes } } $T notify bind $T { if {[%T selection count] == 1} { set I [%T selection get 0] if {!$Priv(read,$I)} { if {[%T item isopen $I] || ![AnyUnreadDescendants %T $I]} { # unread ->read %T item style map $I subject read {text.unread text.read} %T item style map $I from read.we {text.unread text.read} %T item style map $I sent read.we {text.unread text.read} %T item style map $I size read.w {text.unread text.read} } else { # unread -> read2 %T item style map $I subject read2 {text.unread text.unread} } set Priv(read,$I) 1 DisplayStylesInItem $I } } } $T notify bind $T { if {$Priv(read,%I) && [AnyUnreadDescendants %T %I]} { # read2 -> read %T item style map %I subject read {text.unread text.read} # unread -> read %T item style map %I from read.we {text.unread text.read} %T item style map %I sent read.we {text.unread text.read} %T item style map %I size read.w {text.unread text.read} } } $T notify bind $T { if {$Priv(read,%I) && [AnyUnreadDescendants %T %I]} { # read -> read2 %T item style map %I subject read2 {text.read text.unread} # read -> unread %T item style map %I from unread.we {text.read text.unread} %T item style map %I sent unread.we {text.read text.unread} %T item style map %I size unread.w {text.read text.unread} } } for {set i 1} {$i < $msgCnt} {incr i} { if {rand() * 2 > 1} { if {[$T item numchildren $i]} { $T item collapse $i } } } return } proc DemoOutlookNewsgroup::AnyUnreadDescendants {T I} { variable Priv foreach item [$T item descendants $I] { if {!$Priv(read,$item)} { return 1 } } return 0 } proc DemoOutlookNewsgroup::FixItemStyles {T} { set columns1 [$T column id "visible tag clip||arrow||watch !tail"] set columns2 [$T column id "visible tag !(clip||arrow||watch) !tail"] foreach C [$T column id "visible !tail"] { # The clip/arrow/watch columns only get a style when they are # between the first and last text-containing columns. if {[lsearch -exact $columns1 $C] != -1} { if {[$T column compare $C > [lindex $columns2 0]] && [$T column compare $C < [lindex $columns2 end]]} { $T item style set all $C s2 $T item state forcolumn all $C {!openW !openE openWE} } else { $T item style set all $C "" } continue } # The text-containing columns need their styles set such that the # active outline of the selected item extends from left to right. # Also, the left-most text-containing column is the tree column # and displays the icon. if {$C eq [lindex $columns2 0]} { $T configure -treecolumn $C set S s1 set state openE } elseif {$C eq [lindex $columns2 end]} { set S s2 set state openW } else { set S s2 set state openWE } $T item state forcolumn all $C [list !openWE !openE !openW $state] # Change the style, but keep the text so we don't have to reset it. $T item style map all $C $S {elemTxt elemTxt} } return } tktreectrl-2.4.1/demos/pics/0000755000076400010400000000000011646706167016276 5ustar TimAdministratorstktreectrl-2.4.1/demos/pics/big-dll.gif0000644000076400010400000000066507577521106020302 0ustar TimAdministratorsGIF89a ²3f™Ìÿ333!ù, ‚ÿÿÿ¿¿¿ÿÿÿÇ8*ÜþOÉ)…¹8k,ýÖ&fŒ÷UcjEw.êhµ&‹!}†7 ü@[/U¨¡†£¢×SRx@J%a¤âêW9'ÐêtªM^ÐNg X›—Òˆ™zÏÐö4Dæk¾Gu-\?v€Xs[z„‘ŠŒh‡?†lRŠ—a…žS” )…¤­«¨x*¬R‰©#³ˆ›†°p‡¿\ÀO=tºHʱÌÍÁÏ–ÎÒÆ`Õ¹xÛÜÝÞßÜg@ãäåæ5 !þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/big-exe.gif0000644000076400010400000000056007577521110020275 0ustar TimAdministratorsGIF89a ²3f™Ìÿ333!ù, ‚¿ÿ¿¿¿ÿÿÿ‚8ºÜþ,ÈI«½»ÿ`H!œhª®,¹±pÊóìšq\4ç1€p8¼‰ŽÈQ Ãl*7‚tJ­Z«ÏÑuË•f£Ý0õ+.Èæ0:Í]³¯î7ö–[ãv/=ßóÇ~zK‚Sxy‡v‰r‹oYI.M”LD—˜™šCžŸ ¡ !þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/big-file.gif0000644000076400010400000000072207577521110020433 0ustar TimAdministratorsGIF89a ²3f™Ìÿ333!ù, ƒÿèÿÿÿ¿¿¿ÿÿÿÌÐHB«½Wê­‰ú`(‚ÀÞ¨†”yvk¬IùNòêÕ.š«)Þ+õcŽH_1–èÁ–«¦:’rˆ2$ êÄeµÈuƒÝ†€@þŒŸŸ­^³ÍŠ·÷¬=øÕkG zX"Hwƒ]…!‡‘i`myŽX~Š–„Xˆž ¡x£!¥®ž±Ÿ ‚n˜#±²²HªS xq•µ—¿rÀZ|«·¦–ˆ¾WT*¬Ó"ÕÖÑdÙbÍÜÆÒßàd åæçèéæŽÄíîG!þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/big-folder.gif0000644000076400010400000000071307577521110020767 0ustar TimAdministratorsGIF89a ²3f™Ìÿ333!ù, ƒ//ÿÏÏ`ÿÏÿÿÿðïðððÅPÈI«½8ë-‡ÿÀebœè9ˆcU¦°±¶ÓpÄñÜDïÿ@PØAȤr‰½pPTá4¥€gÔ:­¼]B@»ÅU ^1¹üm[¥jS´ëŽÑ qvê^ŸæÍ{€_acrs\o`W…vetƒTw‰~ŒRz]›„k}mgTh’h¨—/¡n•£ªhx˜‚›°r­ˆ®ª£q^–¼²ƒ²³Z»¾¨ÅÅÇ| ™g”@Öר?ÝÞßàáâÝ4åæçè!þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/big-txt.gif0000644000076400010400000000061007577521110020327 0ustar TimAdministratorsGIF89a ²3f™Ìÿ333!ù, ‚ÿ¿¿¿ÿÿÿš(*ÔÏÁ)åº* ùîà'&hÎC¨lê®äP^èú¶v¾2¦­À pHõhÄ$Ñ8[ü”Ð"¯™±5®ÄJŠé‹F¹ÈÈ5å;½PsTŸØíiWŒE»Ÿðà=?ÜÓÇ€€+~|@~ˆ‚RGg…†ra‰’[Ž‹To“u„Žž…‡Še•k—¢cl |«yn'±²³´µ¥œ¹ !þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/checked.gif0000644000076400010400000000011607577521110020340 0ustar TimAdministratorsGIF89a , ßßßÿÿÿ'Œ6í/´ÖÈlxê6tƒ7‚"èPçsITÚf¯&j±€çzd÷;tktreectrl-2.4.1/demos/pics/feather.gif0000644000076400010400000002522211467611021020367 0ustar TimAdministratorsGIF89açÿ~‚€„…€}‚„‹„‚†…ƒ‡€…‡~…‡„‰‚‡‰†ˆ…‰ˆ€Œ‡†‹ˆŒ…ŠŒ‰‹ˆŒ~…”ŒŽ‹Š‘‡‘ˆŒ‘“Š’š‘“”’–’“‘–˜•šœ™”œ¤”œª››¥›™Ÿœžž¨™¡©¢Ÿ£œ¡¤¢¤¡š¥³›§ºŸ§¯£¨ª©§«¥©¸•¬Ê™¬Å£«³¡¬ºš­Æœ¬Ì–®Ì“¯Óž®Á—¯Íž­Í›¯Ç”°Ô˜°Îœ°È£®È¯­±™±Ï¤°¾ž±Ê«°²›²Ð¡±Ñœ³ÑŸ³Ëª²º£³Æ£²Ò´Ò¡´ÍžµÓ¢µÎ¯´¶Ÿ¶Õ£¶Ï ·Ö¶´¸¤·Ð¡¸×¥¸Ñ¢¹Ø¬¸Å¯¸À¦¹Ò¨¸Øª¹Ì£ºÙ§ºÓ´¸Ç¨»Ô¤¼Ú¥½Û©½Ö¦¾Ü®¾Ñ§¿Ý«¿Ø¶¾Æ¿¼Á¨Àß³¿Ì¬ÀÙ©Á຿½¾È­ÁÚ·¿ÔªÂá¤Äá®ÂÛ»ÀϬÃâ¯ÃܹÂʳÃÖ­Äã°ÄݸÃÑ®Åä²ÅÞ¯ÆåÂÃͳÆß¶ÆÙ°Çæ´Çà¾ÇÏ®ÊáµÈá±Éç¼ÈÖ¶Éã²Êé°Ìä·ÊäÃÉ˳Ëê»ÊÞÊÈ̱Íå´Ìë¸ÌåµÍì¹Íæ´ÏçÁÍÛºÎç¾Îâ¸ÐâÈÌÜ»ÏèÅÎÖ¼Ðé¶Òé»Òä½ÑêÁÑåÅÑ߸Ôì¿ÒìÈÐæÉÒÚÀÓíÃÓçÍÒÕºÖîÁÔîÄÔèÂÕïÅÕéÌÓéÏÓãÒÓÝÃÖðÀØêÇÖêÁÙëÈ×ëË×åÄØñÎ×ßÂÚìÉØìÏ×ìÊÙíÍØóÔÙÛËÛîÕÚÜÅÝïÏÛêÌÜðÓÜäÐÛ÷ÓÛñÍÝñÛÚòÎÞòÐßóÙÝíÙÜúÓßîÍáî×ÞôÓßúÑáõÕáïØáéÜßüÖâðßàêÐäðÓã÷×ãñØäóØãÿÞãóÙåôââúÜäúÝåîàåèÚçõáåõÜè÷ßèñßçýæçñäèøÞêøççþâéÿßëùâëóàìûãìôãëÿêêõçëûäíõéíýæï÷íîùèðùêòûíñÿñòüðõøÿÿÿ!ù ÿ,þÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹2G:Z 4 sÅŒg?ƒüXÖ*(3"F–9bÄH“&UÀ˜ñCè&U£¥z1òâ´"G„¤^⤉0`ÈС}è$Mr/¥C…‡ï#§³³>²¤‰”.WÂþ˜C‡ŽÚ–¢K7 Æ÷o"Ö³Ã?ͺ (Uº€9CÞÿCŸà²ÞPeàÀƒ¿å_|<ðC ÁÝKHa…û·\m¢ŒBÊ€>ùÑ„uïÉ·`8à€"„Ú9…ù‘qþùG‰%‰`¢NW˜xZƒBaŠ .ø#LàwEapüg‰(¹ìhK‘evÖ=ÈCŠ*~™¢u :È~Z„†g´¹Ü!ÂcåLWذ„ØÁ·b˜`ö a|(ª¨åPHQ¨Rx~bK"s¾äÇ \:Ø'‘—‚É"˜ñIh/JqÅ’‹F©É‡‘®Ôã%žè¥þ fÊ'5Ù`=¬Æ„}÷UqrQFª(ÑÑš¨e÷竘¦Xóµ¾ZƒËB(D=·šPPq!^ø! Ä–¤j©q$³®ø¬¦:ˆè‚@ÉC<¬Fœ^Ða‰0¨”+’ Mœ† |ƨ:¨˜bÃZà 5Dœð(2œë¶OÒ¡Š+1üÑD(q0 6¨C­&Ë+æðn:(ä½:à*á bèG'| òFƦf2²\:œqËO+³Š9è0Ø_ŠÉpÔËöo®HJF£¹xâÁÐ]±CwþÖZÒ+Vm)+OÛ0®ÍÖ¬2Ã9ãý0þµÖq…gøaK3k]Z6¡«­µÚ²¦ëŠ©©Í@2 ¤³´Êý,Ã*æÚDšOÒ‰&Y$P¸…Œ«­ì—9÷ð§Íöà,½÷B&ÄÐ΀7ÖGçE[b )˜îFtûÚ—¨ å8à›òºp[~ù» ­ÜœC¼qȱaÛ(X(¿&aZè󬢻š‘,Ùà¶~‰¢˜ÜsJ+ÅßÛ\ òÅ&üm?~€„*ø0õ!U¨‚¨®€(Í BF˜_žP³ëÓãßæ8µÿÁ 3H!ˤ¦ u' T@à!FÍ9DxÀ°¦.€§ þ÷y «²¤A$mÐH–ª•˜lÆ2‡=ë'l k½ñ€B»Š†àpWä 7Äá?à Ïx bC~ˆ(!f>>úQÂÆÄ¬ŠI ' àĦ•† .Úb£p‘(@Œž±ƒüà6˜!9bè¼`(èÅq>Dئì(³ZUlb0 (a0ö1^÷’£pœ3С‹ÅÈBMwˆ9üa‘}ðÃ"Íè2D2 4/™I=+“ÐZÔBIƒ'¾€bPÌc)kuš½†Šz¥&šQÈCšN‘ƒèƒ8u©K^šQ Lúa¡¸Ç‹ù‰V+{a ¢ï¥pxþ¼§ïp ãH Š œ£HÁ€YŠÌø!Nq*R‘æ$ƒgÐÙ…*@ï=€JYŸÞµ²gJóY¥Ä'>I)ÊiÝgPÀ¦ oƒ`h„èC úpˆA 6íƒ"ýÐ=<´œŽ4C$+šºùe”ŸDx™çéI†4¤¡ §€³«BµÑpQBœ¡±)"Æú‡pê¡§â|# [‚Âqm@ŒÓÆŠ¸¦ƒÄ!fšK3r¦ E-+–I%UsN•±Haµ>n._©YåþŽé@MŒ  od4¡ÞQ¢hN…)Qáæ,™·5Å-†Å:Üqšñ‡ãÁ–]¬§"9k¦Dav \J²ˆ; Ò"àˆLäb0€eFQS>ßÈøÄ…ùŒä$··­ÍXÕÛP Õ‡@LjTã#Ÿ@}Inô]I ÝSj-^;û } [à«•iŽ%,! ;[â™°Ÿ§}aW ÚÏ#nòMÙûXŸº•IÅAt1Éšd³“+ eT#­OQ6 jÚÒÕŽ¥ŠQÄL'Ñ n\°ó¶ûœä†+9Ãß6+[QÜjé7üüM¬¾×ÑiÒJ…Ð"%´þ"&>\Ï[` $Fa YzÓ1yƳ%2‘mmßù·pc[ b=gxÉ‚+ˆëPÏta )ÒF]V1Z¡HžœæÊâ­>Ýê>à™ŽAt+@„ã J ‚æ’@µÌgŽíibÏÒî3nŽáÞ2¶½î5·Õ8  n—šÖ³:™ÇªÛ“b¾»ÚŸ|užYQXC çÂçxþÄ%¸ <ƒâ§†»…MÝpœª÷ÀEÄb!û3P¨’¯QÛ”TLÙîéw`TI›Ï{Þw©ÜÖqh‰¼ò‚¡6Î/gïm€Kù™áS€5~&µ²‡+HÈ =C 4ñ…$€òˆ1p×–j's4×y§mÒ–s‡@so‡aE¶aˆY6¥XcIÒKdàKÔ:˜¤ RL"$5ì—W‰Gcc5Ô",xø8·Áp‡qxv  €sm× ×|ݦsˆ`sݦ€o'hÝfw}€w75àGæ†b˜…Akƒ0´§Iüä R@ó·2•†7xS1=°3LCp @¹ðð…! ×y˜7mÀ|Ú†j™d”m hp:‡aöaC÷M†tÀWP_‰4qþãA©Ã%]6+GÒ4WJpÃSDuª…/9À3cø5ÍV S`Hƒa ×– Ì' ˜—m2·m3§ŠÒ‡ÓFsr×XtWS€¨aeádY†(QbAñc"þ#]OOÇÆ=î'J¾³?@r1Ä‚0 ½ K ¢pm¨ö ¢€pÎçŠE¶p¨¶g¨æŠx¸‡f^8ˆ‡àGPg¥6åSõeYd@APÀ8GÔe13$o£" Ã2|´{]h/Y×3` š` -¥Èg”€yØø ‰sBXpG¦gÆm Žzˆ[u˜aæÅ^ìuMÐ(¡a•KuN@4DyR?(3’³þ;÷F‚O5“÷r/<ó7Q2 £b·sQ€™ ‘™ŠÐǃ¡'„v Y}N¦^¸ÅJpŽD÷ŽfQžLAô÷ˆ0ê¢4€Z å…Z“=9ÀŒ^@#>p ”p!Š× 9hŠ©†—Í÷ ÓGs2ga›g—˜gd|fŽßöv`Kàf÷X€¨X9µ•òH~Ô8¨¡êR)Kôkaò ‰W=^È0>à€C*× …†p¹1·—©ƒF™ 8‡€Æy8W}jwƒnWd¦‡d†8`àX¸5SˆV’yYDUŒƒ,éRMTh?QSøòqœ>£‰Lðx~þà!38«™† sÙ ¦Ð iŠ jØ&}Ðç†8žxfa¹^ßF ÐGàu™Vˆ H(iY·v@tQd™ïÑ*+ÆÊô _8BÖ†’~ U\—x! h—9Ø  ` ¦€yÍw „©Š² › gx€ÙsÍBœch8EtuVµ$å'…[’Š0í¢?×scªµŒ<#â3H[ßY ö  ¨fŠ9€ 8ssˆ¥<èy>h}?h‡~àù©y½ e8%N`’z TBµ>Äšáò±6у2d"îæ ˜˜2&ÇZV`> Ú¤þsa †pgêTÊvq‡2;p¤‰Q°lÈaµ[²da • ¶yI¯kgaמ–p ~™j ¯u›¯ˆ0 ‡À:@„P  Ð¢5;t݇·“ÕSääVBåwQÝê>Ê´GòAô‘c´iV‹p¼’+Ÿp•мÚÖ Ù³g»¬Ï7sÍþÇ€Ë ½™·¥Öøv•TðgЃ¯Ë^v;tªw’Þ7NEw\çt‡r´j£6òõ»YØ‚+·B&w® .IÐí É ”P¹ÚFa•뵦ÈyЗ›*+‘ˆ›XЇE/ŸÐK D6wçX‹7¥[ uVÞ§Kææ°bÀ‹˜AË?­H£ªŠ/|ÿر-N g38ÀìW Ô¶gnŸ›K¬}¶mꨉgµY›„ê·Ð;zØÇ}'™ÅzðX³´jzN¾¤­…±ôÁ’ó³§ô¢þCÞ pì¢pÀD˜”]º”¦¶¬FìvÔw½)ZSþ–@¼„À¯I}.ZV2%Yeb&ÙS{´EàªË5yÂáí–ÆG²3Û¢(„  «qÌ¢(ÄAØsA¨‘s¨pŪžh›ëépL†[êølà¡y¦€«Œ[K˜V“Yz V]¼·m%”dAÛÉÀˆ˧G€/³€t!ppàÃmÄ ×st\džÊpn׃kç—"*mogvc5UðTp¦ ¥6—a?ÈÅYLS5JÌh¥·¢j»fœqšL–èòFN Ê'µZ%Ž Ç§¼¯˜Çà|©ëì©Ém×kŠ5GÄùƒcEâ/¦hvuÇdfþ£’µ„ÀNeõXf€·znp=ŒC«‘AçšÓó“oçµEg ¨ Ñ?ŒþP ¢”§F³=‹ ¥i;¯ÚXsI¶zR@ñ ¢õ¼d~8kû,N ¥È¬·z\ÌðhlàKã'Æ6M!yòF; ç ÊÍÐ)ÇàÃG}Ýp€À®˜À¡g·—:V›‡¨ø”¶EÌ€KH*Ÿ õºsRÙΚÝPÀª¬'YjÅ·ŸÁ‘DÉ£‚ªR¸Ù§9íÓ?í"¬„!Q pµ}° ·y-«p)Zp°Ö¹h õz½Õ§Çñù˜aúRpÁºy˜Š¾ªþ·Xíì}\¼Å\ÜÒ“µ¦\éVd@~jÍH{®` ªÁÉÖ¼+¤Z G€püƽЄf¬>h·™ M‡´L¥7¸gý€Tô3Wa̺m· ™6…w‘õÙ’5ÖÕšH¼äKà­JPК¬+:½Ó¬µ.BP°N  °× ß·}w#ÆgG¾ˆ¬ŠPœ—¦°²zg©ˆÒfÐ9ÐRÓ¶Ê0žÙÜÇÒ‘áù|ÌÆèD TðL Ó‚ËÉ©Aššè°}ÈqðßFÝ×Xa•ÇuŽ vgmjÑ'¯óü멞û‰à9­ªÆjþ•€} µ`p7 ¨.ŤFÍ€(àL†›”°d}gp˜žù½¯9‘GXS®ä” ËûÄÊja‚Ö5Zø Ú.Ì:¥·>QC#•ôèfÌɵ¯P`@`Ç€éó½ª0tq—^ì tÖ—y¦( ©pêÈjaóšgLÖZÐ~vPÙ·™Ç‡-•†9nƒðÈe=»ùüP}káÈÀ®_»éÖüÓ€ä"^¾Ãµ àì-Ž¢P á4kE>Vì|z­L‡ê©íÛ¢™êLÆÁf@4Pòœs3—a >눕díþ^9¥Ò× ´*QXQ„ÚÄ®+Q»¸±Í\6ÔìcNæYØÓ è½ èµ¹yúz½•}êÚ¬=V~P8°v ½fGz×é`}SÔýÒÙm£×­V¡½òU´•¼­é-â\H\AÐÃÏóYqÀZû˜E¨zšÍНøí²ºÙžÁZ„„`؃€ê²¸ô´ÞðÁ\Öå^b­õ·^t‡Ž\Š{hH"¾¸Z8~ev¶]ðiÑ ¡g7ÅÎBwÜo©MÜ|¢0Ï©°í Ìdv WÔãIŽçh;×éæ˜6µXÁcû*ÛÇNY=jÍØ1CÆÌ\2bÀˆéR¥ (T¬üÕ¢eá™3\RHPÑ"IÆ?†Ì‘Ò¡N“^®¹rëÖA‡,ùþÄ™STN¨??%ŠÈ’ÍA`˜,CHTªÔ*Q^•zÕëWÎ]c’˲,Y⃑mkG;ÍçÒ¥‹·‹—+U´üý«Ì?†5LL¬8òxòåËwò¼ÚèdËV»º¤ôÙçÏÑ>o’Îô9S|KˆüH9B 3,¡å“ʤZϽ÷t‹i7•¼ÊJ¬´Êd¸´ÖÒÃæÞ2ƒçİ‹ 0¨»ÎŠ„¼ì :ÎH¢‰P óf¤±Fô‹o2ø¬ré½ø:Aí¾Ñ üL' ì«©1 ‚Œ?LIŧ©nëŠG¯vël¦”dâ*& 'L 8µÊRÎ?Þ²ŽèÀ`³‹+¼€S°íàðþ£ 'ŠQF÷ä³^2Šó£2I4ÚjSiåS½)Àº“Vz ’?_Þò½ßˆ«¥¬úèì´X „3…'<-Äñ@¸(!r„'¯<ú>q) È®u$ë2ë­úZ¾Ð<þ¸Ú~bÛ‹†)[”KrdOëAû–×Sá~ά­|ß™ ®·,?üÿŸÏ’‡¼àu ¼ €Ôþ¦&=Ú¨§3×e°r?šø¤=«}F“Ðç%;¾\;¤ Å\4ÃpÚÒ N}e,ÄË΂FÖKxÈZÐrHˆCÐð(‡`^E§‘F”€Ýjв7ÏŒ tç2ׯ€Fù$‡¥ú€¾Wä$lüy‰ -–. uêJ·ûƒ–µ¬à¢‡~@ FÒÐŽpd×óH”a!€8ÈòÈnìÔ ~4ŸDéOÒúD*Lщžø! tp£%l!.¹™kb¤IíX8“­@ˆ]ÈŸy¸J9px4ô™y8Ãî1}üc¯¨'Bö2,CIf&þSÊ™êQ¡ù˜Ç@!®ŸPk4”ˆ‹Œ" [x¬ ˆâÝô†®fñ®BœÑ_ƒV¢ÊUöp–uÔc9/£Ç?uByÂ^´K_Öó1¡øŒe.v%ø”k>¢OéH÷ŠÓ<*~Ã3ÑŠ× H'la ßs™C€eg1¡h/Š=šÓ‡- f2¡ MèyÀBD$2DèÙÓ¥$¹I&Ö3»‹}’2¢d*tÚ [Ôâ4áê¬*e)]¼Î‹5JEGU¥Ýdåb)¡¡Wþ§¿Zj´3ê¬jF)‘Š‘ýé®°…*„\àô|iZE‚‹k³+qI0‘äÓôd6¯ÀO')þÉCàkš­ 3µdÕäeˆÎŒ‚ѧ>õ2kì]F%KQ°!J¶èÄema H`!˜'ZÕ:Úh?ó RãÓA¡L‹Z ÀI*6)>q-–˜ -ºX= ÂGoï»_×(êØÉ÷Y‡ò‰f7Û W` ¨ÈX ,ÒV×#_."*щKjƒÔbE+zÁ‹Zèt4f3…%ÔDÉN¤¢¶¨¢}Rs®”¼-ÉŒW„Û9â3“ñî'Fá °ÚBÂè…&ø°‚HDg%¢u%ÌS¨DŸðqÔ£>fŠðڢeǠ$ BÀá¢p…(h! ê%Q=Ü»Jb»´OþM¶=3©CG¡ U€¸è…0š¡ Ld¡Á+í„•œ‘¸¦Ä„DÁÉ$é.ñ™ÂýøõL¡ Q0ǽ`臫éb}Zl±KíÜ£ÂÃÝø‡]MÁc Y˜XC „x€é.pÉõÔcT±E™ÒäG?JlÅPñ]¹¤£…%Ø@ˆWlÂøÅ+ÌæÐþdtoÂM¢R%H fƒÜŒ\$ xу#üg{–ƒ¶ %ð›( e6àÓix+íaF‚ à).šÑŒ^hº'óéÏì³aŒ(^ûÓµ÷ˆšDíľt3~á RðáyEZJk—þVƒÙ UÅ)>bˆ™˜HCŠ-CËd\l¯\6“&7kçW°[¨fçfÆ#Zû‡ŽÌ`]GâÍÚâËF.0•šµÏ cwZƒl‹J·B¤èÈært͆ZÓ*݇ fSÐê%„).-db¼×lí4f<#YÇÚ$?C'WÄçfW÷ظø…mÁLàAžÑ]À¬C>ÚK7›Ñ­ØÄF>1¡Ð‡’<Ý-`?õ¼’¼‡–xŪ›`ÓY3‚ÆuóqçÓ2Ü.*§sÅŸ~ñj`ÃSÔ¦€$o½º#ßäf ‰ŒÀuc¨éž¾Ù¸ËüÒ­èa*,dfkþºZۮͶ‘ý“’M¸/¾lV“ (Ðåt¯uÇ[7ꛬ¦?Œ¨”,MúÂåá™ËÂPÅQÜKzfWóåDºqÞ1ÓÎÏdûòTlÔP Ö^4£ÅàC!XÚ^åÉϽ_òÓoQMÙ ?1ƒ"?æwM§¯åǸ û…NðƒN ½hX¶Mz9hÓ>k˚ʊ X”!ò{¾eÆrxOP Y[7øû3Û,Fë\ (R 3PÙ i\¨¨;°¹ ²^°Bø„fàw£A³NÊ ÊÊŒ DÙ hé1Sµµ›Ahà†n`‡jð„7ð€`þ0(ÿã©_XCÚC0ôHóëB7ës¦‡Â ûøFš² ™Ë‚Åg\¶j€Âr8<˜tû8^Æ`¤9jQIÚCôˆ$ÒÑø¹»8[ [þh†r(‡jL@³… :Ì8”Ðúø6I*Æ>ü±‹:Ò3GÌŃq£®wA 3/JZTË©ÒA°A\¶Q´£°n8‡s‡8¤ÁÙz6`½EZ”ü˜À¼X¼ÀÂv`‡c@ƒŠ`¼EôÈÞû0zD¦{LHê£=Wˆ_x`8¤Á~£­Ò0’Ô7 87ÈUG`†}Ø­b‡Õy8`®Mzpqä–†5ÀˆU†a ‡qr°7˜Ë<©c;¾c‡½×†\zHï­Wwˆøð€4HƒH€d>;€H€ç¤äJ~Yh%á­‡MöÞ?æ ÷“_Wæåêåu‡kdo@†: ˜ W^fæŽá–`fqð†XPfÆæ9Tæaž†S lçñ8ãh^‡tèab&¾qfgÇpV¬<çN`Xçv¶g‘þ he‡up~v_p{hHò~ægqˆ…f莇uP׃®‡–…†¶èŒ¸†usôgqà„‹éu¸|‡‰niiN‡Æ‘žèeHi‹ÖX{(O—v‡dˆé†æY{8Nv¸‡{H‡ŠÎé~pbnðé0þè¡èpéZ¬‡Ÿ¦&ê{@h Í{¨g jßs E{à‡{àê®¶çf‡°î‡u0k{ß|8‡ZkshëvŽê{8‡'Ô‡~ø†ºfçzà‡|@n}¸kðëqŽj}€‡q‡~ȇÄç{àÆ.á~¨Éç~؇|8à|à–¶ÖllížµÈV‡ÑÎæð¥|è‡~PíÕß|€ìØ^ízi}°mlv~¨‡z°‡Ý–íÌîlŽìâFîäVîåfîævîç†îè–îé¦îê¶îëÆîìÖîíæîîöîïïðïñ&ïò6ïóFïôVïõfïövï÷†ïø–ïù¦ïú¶ïûÆïüÖïýæïþöïÿðð, ;tktreectrl-2.4.1/demos/pics/file.gif0000644000076400010400000000042707577521110017676 0ustar TimAdministratorsGIF89a Òttt¼¼¼ÿÿÿÀÀ!ÿ NETSCAPE2.0!þahttp://www.rtlsoft.com/animagic Created with Animagic GIF V 1.02a by Right to Left Software Inc.!ù d, (ºK#ÊÀ›Zˆø× B8F¥Ø¥'iž,üŽ1=¯¡ ï<èÿ€!ù d, &º;.>ðd„Ú:ÐÛ |¡3‚ÛYŠd©ºmøÊqú x®{|$;tktreectrl-2.4.1/demos/pics/folder-closed.gif0000644000076400010400000000015707577521110021501 0ustar TimAdministratorsGIF89a Ò„„„ÆÆÆÿÿÿÿÿÿ!ù , 3XÌú0ˆ1E€OÒm› D(Ža€\:™`¥R,ñº±kç|ÓùÎų ËCô €¤r¹L;tktreectrl-2.4.1/demos/pics/folder-open.gif0000644000076400010400000000017007577521110021164 0ustar TimAdministratorsGIF89a Ò„„„ÆÆÆÿÿÿÿÿÿ!ù , DWEHB+JD8NQ6UE+UH8VR=oBeE+cI:kW$gT:vI*xU%tW8yaJGCAOZNPGMRWSLEWNQXSGZXSKYdQYc]aQ\jl\wneLCdYJf\TvXJt[Qv^gibJidVveLthWzrZhifimxgqljuuviftnpyuguwwlyŠxx’v„Qz†i}‚wC‹N1†Z-‡X6‘Z;l5¡_+‰ZRŠpTok…xh†{sŸli–yg¢WR©rL²rlÈHÈ}{É}‰X™ˆJ—…Zš•]Œ„l‰…všb‰q”†l–‰vš–m›”{¡Y³_—¦dœ¥y³cŸ²pªŒC¦›Y§’k¨—|®­r¤¸pµ¡o¶¤wµ²vДṖvÒ©SÒ³oê³Xé®jÜÆ}îÈgæÍqôÄgóÈzôÑu‡ˆ„Œ’˜•Œ„™–ˆš•”““£Ÿ¢‹­‰…¥™ˆ¥•³‡§¦‰ª§”µ¦Š¶©”´²€¸³—ª¤ ¸®­º±¤¼·°ºÉ²Í“Ȭ‰Ãª–ʵ†Å·šÐª•Ò¿‡Ò¸šÌ£¡Äº¦Ç¾·Ñ»¥à‘å°­ÉÈ’ÛÂŒÚÉ“ÈĪËŵկ©ÖË·ÚÓ©ÙÓ¹äɈãÍšíÛëÔ—ôΈøÙˆøÚ—åŪåıéÔ¦åÚ·õˤüÚ¥óÝ·úâ‰ýä—ÿõŽèæ«èá»ùæ¦÷æ»ÿó¬ÿô¶ÇÄÈÌÕÜÔÍÁÛ×ÅÞÛÒÛâÄÜåàìÄÄåÙÅãßÓùÃÆóÝÂûØØäÝíêäÈéæÔïðÎõéÊöëÔøóÉúô×èçâëâóîðïìô÷ûøçüü÷þï,z“ÂÁ (@ ÁƒÑ”9ËöŒ Š)T´!ƒÅ N°@qÅ’)kÚ¨\“¥Íš—k´d™™EæÌ'Y¦DÉÂäf”)S¨ó@:©e‡Â3Õ﨓µ9É2#©ì£ÈP‹©n£òL&=ŠX@A‹ p2w`„ìcO/þApp@!Œ@Ä= Œðj€Â < ‹i)¤Bþ¨¥˜›ã5${¨êÚô\CÍ#ÑLž7ìœrxPü}A 5Øð‚)ûäó 9”Q‚2QDЇ`|=ÆÌÄ'ã<ªÙ¡ŽrÈð$cˆ·¼°PP¡†¨"þ-Ñ\#Í-lœÐ#‹Àþ7NÄ¡F  è} fÈo UD} 4Ðx-Rؘ&51£`ØÂª… íAvXÄ ¢ … üÄ Thœ)HÁ0( 'ÀnÁÁ|÷}”#ÐÔP4aZþðƒЬE8À(p‚b€ìlòC÷*HÅ*ô„Ć  Á K`‚”À'L0¸Àb³¸†0A R`RˆÍ  A èèY/ú@ò! U‰€C B0^*B]Qù ¡«.ˆ Byʃ€°0°§†àÅMJ«'x@3òfí b‘›M mø„>ö-ÒŒ=ËD0¨U ‚Æ ¨@/°Ý \€ìø0˜Á4É`ºbUÈ3ˆpÄšO\Ø}hÖ° &˜€&î²à‹}àÃ2èˆð‚t èÌ„þZPzà,`„ð‚:¡¿/0X_d%T@£3`lG±J 0€Â*t2?p€`P«`ÃTØ#<€ ‹q/²`ƒ&0¬âÇm7@€Ÿ,z˜0!áÕô‘A{°g¡D˜¬'œÀºbM4:å;LÁ;`€Ñà7A#¶Ç)ÊP†Pæ ¦K5ËèÈ>– ‚z„¼šÜÂff „-v”®Gò&OÀ @…`%£ e?èb1`:ŠP8®´ŒÆÐqÀÉ€qBÀÆklÌnsÓÖÂ|8ðÿƒ@¡±tr\€00ä³p#d  ]Üá«ðl4ðU­–ˆ„Ä©s€¯1Ó€8‚:'v tíÁnäê´ˆ{ê0B~°Ñxu Q˜ Ús€WàÉž½@ v@‹[Háã|%1Ûà‹yˆM‘˜CâÐ2´¯/ØÀJ÷û§ ™±tùÔéÓƒqA ´:ŽÀ a A„ÝéYVí;ÀÁ0!(x œJG+Œ! ±I#b hðVòÃpЀ{ vxòæöxã=~£@þQ`n|ä¼\€nùv!Ú-]‚øB 3˜ÁñþTáÆ –>’ñ†êçÀ À¶ù‘O \\ÏKàzt_àjXOÜåÂ?„<Ó *" po¶÷Ypp S/Àh= ¯° ·c“+àM` ß…N±óð=Ð̵qƒSnU÷j7ruJà@ }p/4¶*xoFãdŸEà3öæd 0Ÿ0 · ï°N°,°ÊfíÃÀ~ºçœâ_ÒtÕ)C°x]øjtE´Lg0Ap aáÒÇJð`[° °¬T Àl ¸à wx®ôJ Àÿ‚wæXG`xCW'nT7JÀ€;rg‡Ô:†vÑ×yÃÆ° pae4ó¢‡ °p`RàCøh®âwPN­oöB†UC`k‘˜x 7WC° NЀîÑŠú¦oóò‡Gð°ÀOФ 5° J ít.dˆ,pWgF–x­6u_ˆSGJ@iÖ4#eíÑ×}ŸÕ>°Ô¨È*p*ÀN@ è0 À°è *ð)` ]¶çÌv`'àtÌå‹^†Ò)WÅAC,e¸>µø¯d4`u Á*ÿ» ¿Ðí° ¤Ž 怊FsˆÐGƒÕ_4Æj‰gn_x#­Ö…K@#@ ÀRRvÐRýøYïtü`  ^eiànP¿p–í0 i°)€j` ”~‡ap`…ÅŽG]ögx|9uWõhC©šØ*-UaZÙyù¶B2 c§irPr@§à5ào óc1€síÓ];–þÅH©—|ŒâKpà(@ÈÓs“•¬$ŸùJ `JÀ`cYt+€ Ñ´p ~ðj Nðö†› N©Ø2`!HÙ)b‰©i|ÿ¶* DµÈY9¨•0×$16 –“)™p  Ò ¸€ ‹°Q6" ñN°_…\uvX%‰†7WÛ)]†€~³4êÔRŸ…N†NRv2 cäk¹rð §°à ¼@ K`C°2ðKî„›­s —&gÑ%? ⦰FŒK@p] `ˆ†8/1£Š~çw®Tq@ׄ*•ë9j  o0z°]5&p]Vv+Úp&Pš¾øŽ4Új6*—']°¤5håB†¹)Z 9^I`M½¦ `šç« ¦ðl°zð_ÿz@ESvÀÐt0PX2pUÑ °ÆE†§…KP'®âhkzoe‡mØV €&Ùt…/*R]pN p T°kÐQlð3pª¯BP=6`W¦Á(oøjW…ô‚›hõhëçY§»òDBQðQÜú6 `JêP 'Aa SÐ#3sJ=vc2`XuMÂèŽ3¬WUžzޱcŽØ†Nž¥i]ÜSzàC1¦„µ { 6¨a@ao#¬àÄ6@©a‰‘X¯ë–š4öht’Vê:'ŸåY‹†@ÀúTT@lð²ÿTP Æ@ TP(p °¥P PoÀ®÷(D )|–r30Ǻ Õhîó60£•†aðZð{Ð=~X ‹ Rpzá­°`P =ûœ(­C”…Jt5©zY¯\$ŒÙ ‘o bˆXûdðñ9ASð¥§Ð¡l€(`h`W ¸òš[¹ÃžËt§N¼¸·J`¦3€zËE0 Ä3.}:8ª¡#P¦É(kðSP«È¶D€ A°»~À=ÄFž[PÎKX½™x4ú´óa”åFcrÓN0ZÿeÇt»¢Ú•@ÄØª'Qzzà ª0lð”ð´0³k vHvਠP0p&%Ç‹AÀ®‰B@£Ö ;¦N¤uaëôNntvf$'1\¥» R€Qp•ùlð P2ÀW9Z {úk•íÑQ`?@5k*òj,,€mŒÆ¦j§Ç¦R¨héÔG?|0À=UÕ»J`;}Ô#A@f'М Ü'ZÈs«ƒÂP÷Ó$p:ÅgÀ«+7àRq¸Ò¸h%Šèdðñ'1#:bÅÔã[`´uæÿŽf1€gpj€g<[#0À´Fg +.3³+pˆP(ûdèD´òÉwMS°.€Ps3”ã&r!@€Ø,~@ÝÀ à€P·1°?Yg«b$ kCZ^9=âNÊÜe£¼hïD4h­)R©Ð 0ApÚÅÃðl@ÓÐ à€ yðÍ ¶Ð-p @ác'k"ZÐê*¤¥N±3»eÅ]þZÄUPæêQ.ðKà=€’RfMÇåB±3c±Q0à Ù@&Êð Ù0 —pÓÐ ÓÀC-p)°c( 7rÓdÑ·lÿ\ø:l(›N0W@`°u¸áºŽŠ’ UY ¥Ú]å40ð¶À •@¬0 ™À Ø ØÀ ØÀÌ g 7ÀÖ)…lZæ´]iåFj½]Þ5lÀG` •Ô  0Ÿ°.3°¿.0. BÀYÄ G Îp˜ —° –0 –` Ê@ ÐËß° ´` Ê0€¯$VKc4 ‘ƉùÒð· UÐ |  ¬  5· ´P oðM`rĪ_(iঠS@ Õ` ˜0 š  “ •  ߀”à Òý Í  Ø  ;tktreectrl-2.4.1/demos/pics/imovie-02.gif0000644000076400010400000001343007577521106020471 0ustar TimAdministratorsGIF89aP<w!ù ÿ,P<‡      .$9 $#'%64%$1!$ &'07 5)"2 #& %'%7 %74*5%0?46(&%'%3)6%)645(&6,376(865.(D:5DB ,G*C$+V#7H'9E68U(;V3@%EúÈ$h4XàဃM”+"0™4ÝÂ%H£H‹¼iÃfÄ œ?‚ @©a:@`¨PAE›ÛllŒ8éZ65{àù«èŸG‡ FŠôÕ<8XpÀ:‚p“"eY™L¸rþUZ¦)#D8@"åˆ*TjÐ@»$Loð4Q¤" Hd³Fpñ‰",Ås…9Ë 0 Ð5@"„ˆ"™€È.•äÂE%1¼ Ç(Ø€Áœt "ð¢HÌæRn¬Ñ F¨àF#ÚhcFD˜`€9² s޼òÈ/0à€àÁ‰è‚H™‰Þc€!"ˆ"‚ £\cKp:h€Á>È©pbpçzð¡ ( àF$(ª‘@ Ç ‚òÊ-bØ+¯ü2‚%HÉ‚€†Ëd‘ K1cc 4†ô@„ÿ³ óŠ,BtqÁ}tQÄ®»âK)] !D]œ¢ÇªµÑH$ÚáX }ý¥œ’HAâà#°œQš u0¡ !ˆ„‘Ée”q "ºìrË3¤<à )ª<£J+ÐÔR‹)©Ð¢Ê¾]¨ÒE¦ø¡ê]‚ *Âì† Sˆ'Ù°@$´ƒ&é#‹@âWµ°TÚF&0"N"šd±¥½Ü"M&*Ÿ£/Ò°âE4ÑqË.Ò<3†4í޲Ĥì#HHDÒRxøgƒtò  €G‹òÁÈލ±† fL Ë/x¼‘† ┣KÒ`d!M/Ñ”¡ËRär… \P‘….þÀ$‘I/dìÀ JxqDGÜ ƒ -<àãOÔà‚ _ÆÏH“È {¥0œ`@9ru( ËØhzÌ'!Ä Ë2N ‘ !„ÄáÁä/Ü!†1PQ !\Ð1Ã. !†._8AE tàÁ ÄÀA 1ˆðDõVh¢E%.tÈ/*´hƒ"Œàé"mÈÀ‚6¤q,²l#Ç8ãdL Z$Â"hÁD‹yA ƒÄ  †.´àæ-`!AfÀ¼là 0ÈcˆÀÆ ž€Nü¢ ^;ÃmÚ€6… m@$ÎðˆWÀbÛÀý´Áˆ'ìAþ0€ À . Ø@Dž`€0ؘGˆ¸`‹ñÒ¤@HRÀ)|0 ˆ²¬ %t0Â"J€\ÃI”ÚÆ"ÌA¿npÀQ䀦„ô¡PÄ`@Ð|àÄä€ 0‚ê,T€Ž€½$ `¦8PˆRçˆhh@ D,e f`TÌp[éj8„Lá Wœâ 8Ç9 ;x² €x`ˆVô ˆß„(ö" lÒ1Š@€ £è” ƒl z€@ ê3¨ .F0ƒdð†xœ!jЃ#hê YÔ´<…¬à@Rú@j!uø  Hf'# &¢HÀ^Fª¤€ S 4ɸ9¼€ O‘b q5 ŠÀƒÆ"ÁtØ¢j€Eþöð‡RÔô€€ ^=Pi©Áha y䀑=FƒÊ« µJ%h‚&@€¿ŠÀ)ßìè&µø€Bl@¡|7¢ 9¾A‹€E7âAwØâëp©9Ä&A :ê€ )èÂ3äÑŽƒ`/ëáä«TH BÁ LÀ€LB€Î”žPˆBÐÁL0€ Ñ ¯­A®< ºÁŽnãÅêØ†^qˆWDö@X°Tf.@õÐ<ê‘40àÈ‘…¤ôœ½p@XhÒàˆÔÁ €@p‡xÀOà@Ñ 7!†?8þa "Дzˆ?ý ØÀ褕?阃Ÿ€î˜ Ü(YÕ1°šX D`”%ø&(K@ƒ$¶ØG_Ñùð)Í5:0@!ŒÚúøÃ*Kha%z~ûk@Ûš œ<2 P€ç\s/&0ÃñpàÁ˜¹uf ðdÌ hÜ@ ¸ ø€Cð©ð‡aÌä€4Ü1|Ì#¸ƒfP+Ð OÁcak~æƒAdÀUìX)íƒgÀV ¤h(8ª‚ƒÌƒiL ~#\›]ˆE9î{pÜŸGÈ¡Aÿ; ƒ¢ÀD ð€)B ö4:î‘D `©ÕåóÌ€H°'ï`À}Ë[âøD!˜çafCzø4Ô¡ŽZœB²`‡Ç;.rß#(2D‘Œ”S‚4€Àš‚‹zÄcŸõhK¥s³HPÁ |4pµÊ{©B•x@%ÊŠ0Gǽ~v¨#îPÇÔ©Nõv¸£(D0âð‚Aº¿È( ìP- #Èå‡npó½ `m8ñ®iCEÓy}–À¨€Ï@Ë/b‹>³0‡,báŠX¼ÜîÀG,€0‚'Xaj—õíØþˆãŸ¸ q‡FÜàÇpÍ‹Ào@' @Ä@Z¾Ãц¿hp8@ÐÀì_¥FD}ÀøP@@@.€}Ù·{kgvPç åÐ Ž€ Ú Ðé`A‚j%å¥#RÆ`I—öhàLßÀ(€p'v¢0B¨?@„?àLv€ ¢ðãIGpž 2ãÐ Œhö@£á ã`ü”V(,À @$ÀO ðŽ5 "°{Ày@?0€qrЇP.Á(‘Qu¢  ÊÀ ÿ5мXÀ‰"x|ÄiÐi0 ô“%hôp^TSwn ð°A$E%ƒ°4•B@äpæ@‚Ȉ½XP¢` É ¡ ¢Ï! `>x€ž~æ0 x0 :é`ƒàB|~áo°2 jä]"°ˆáÁWF€‡ó-$°@/‘NÆ…À Æ i ÿx —Ð8-ðŒ0rÐ vŒ€Ý€xPim`m'wmŽØ0"àIlÀ¸–ú†PP­qPEˆ‚ÿi¶(7©`Î` Ô0 ¡ Æ0 ‰ àVð ð hð h )à  ,%˜ ¿0$ ×tn@ÎdVFÎ4 =a “´!'€è@(ˆ%¡7é‰à Í  ÉP ÊРƀ Ê @™rÁ0Áð ¿À×Оп€ã`æÐ P@ÐCphfp` õd¥jÐ}¢:ðz2´Ñ‹.º€/™–`— Ê”›”¢ÀÄ¿ Á ÝÜðfh>•A€Y)52DHDbÆ’> žè ñÁ?ˆÿmÉ©™wÀ ›`›· x) W0$"ÀÀåà å  Ýp Uh ~–#ÐL y€Y#D°Là’€:p,ñ71,(/ÒH@$t`žWÐ-à0qVà1àSð 3ž6ãœÙÀ |`()оÐ9fôSp4< @) ®àBx 02“"—ó¡{¡˜° ˜¢Ðjçr  ðAMoMà Ü@?5ºB=1R†À „h0M j0 ƒ@‡@°®Säð@ .I9(ˆÿ/R¥/¡\vàÍpí9 4D÷IYUPŸÄQh@b¾1mÀdDL ©L"€F jà Û ‡@H:p>°y¤>`qIWº/Q…Г— ’PVPZ4h TýuÍõXTÁï!SP‚Ð<ÃÐPâAz jyà /6 äP ï: Û ÞvQ@>à’€Èš.± œ°0pv3ÐyòIKx ¯QæL@VÁ“9p C 7õæP÷úŽu²Pää@²Ã0 ]G²®ÀÛÿ/¢$Р\l€1P3ŸP$}ÒAh°{‘Ű @}𤠱nä SÛð ~r:³ð ]쪎 5}^W =P %+—s)fð3°83PÏÃ[. cSÂcEIT°°Á€>¯r‡PD°èf`y+³0SD°ç~0 ëàìð }ð| ¶À*6A4€s ʆϦYF%Æ\|p({»°´p¯D±±@pMj!WŽ_j€M`­z{~À€zÐzp™A ®  ÿq` \0§û5P0P1 ´#%f)9¨b–Q°’iI# #A@)ð¡¯Á¼|ÐiWj[b)Vp ½K‹øPä`ØI÷ð ‰P½À ¸  ›! ç  ¾04`®†p Q&‘ M€¯.PpiÉmë+a)Aмû«¬Ôªf°^óŽ’›N°@ñä ¾p yp€ø0 ðÐó ëÐX¼Z, + P`]àl0Ö–(Ч§p à{À+™¯`' þ+a'g¡/²põŽÎK­Š®: ì0ÿ†|‡00ðpðòPÅWóð@,ì`C@ÆÙë† § +9ÀC°6üëËî+#˜éÃ@€ApÎ*À¼ W€Ä÷ëpë <ÚñPôPõpù`‹ÅÄ÷@™ : ®C÷jm]P «° Ò°ê`ÂCP¦@ЫœÊ @°¾>[å yÀàµ_% 60)À³2+àVìæ û”ѬOñ€çV-Æ2`-"'`{©\ ~ î nµ° µÐ ­° ê Å¦0‹»úM€'œÿ{ɹ !`AàÓ´_ðûõ0IƒÐúÍCMôPÛ m€, (€IMÙ S`¹êÐ&Ýа/ë «p¹ÐP>ÐÄëªäŠ{0ÈP ¹° »s¾BÛKmÀ êæw ¯‡l72àe‡º“ã2ðeaõ80-P—p y7.гO0Uâ^¸OX¨^èÌόۀfP£×0m ‘ÐÛ(ƒp îjP Gz”ºuë0à¢}.´3@ìÔÚI°œ •0 Æp [pP~”3 æÐKõh“Þ×údØÐ Ùˆ ‡}, º ]Û06Ì£Oðwð¼õ=”á7Íl:ö£ý Ç ŸÀ ÀÀ º°S ÄU4;tktreectrl-2.4.1/demos/pics/imovie-03.gif0000644000076400010400000001113007577521112020462 0ustar TimAdministratorsGIF89aP<w!ù ÿ,P<‡       $'2 #'&$79%%=-& & '4 4(*)&("&= %67#,&&),8*1*#387(&8.271+769(/B(9G6=G&E.K4N8U:I*:V$?i-AL8DE:GV:Ea:VkC G,E%P,V5H)#K4+F:7W4(W<4d9*g;2t=(I;ADTv%Xy6eD,fE6fU6vF9tQ>e>KEGCLZDP\UHGXWMXXVBKaKWfJVsT\gU]uEcDOqPXfETuFKjeNbzZdlXfwdLEbNYkRGjZVzMGyTFs^Vd]fq]hdnDbvIfwUrc\wxNffgblyhsyxgmWiƒ[r‡\r’cm…em’hw‡gx”sy‰s}“g}¢r}¤^…([†7cˆ.e‡0`”0qŽhŒGm‘Tt‡Sv—H{˜Xt A´Hnk‚™r†u†™}‘žj„¤o³vЦ}†²|’ª{”´}œÁ…L8„YF]Q“[J…bVšbR†ifŒwv“mbŸyn›}}¡i[£}r†[™€{…¥V‰¿O€¸Y“¶\ªf‹­z†¶eŽ´y•¿k¿y’ÄZ™Ìm®Ê¥ÙeŒœƒ¤‚„·…–ª†š·‘œ©”Ÿ±‹£¯Š¢º”¦¸˜±½§Œ£®»¤²¹‹ŸÀŠ¦ÅˆªÐµÊ²Ü•ªÇ–­Ò›³Ë›¶Õœºá ®È¥·Ê¥»Ø²¼É²¿Ò§½â±¿â—ψ£Á¿ÂØÂâªÁË©ÂÛµÃÌ´ÆÚ»ÑÞªÃå¬ÇñµÉçµÌñ¼ÒèºÒóÁÌÝÆÑÚÂÎçÆ×êÈÚñÑÝêÑÞòÌáêÍâöÕäì׿óÚðóðõ÷þ¿ìÂUé’/F·*U¢ŒV%-Qða%J¥) ±D $2ÐP…;|ôè¡£ %J ØâÌ–":¬P’gO :wj8àÁÐôÂõ S­H-ªt‹ÖLRà¿!k$)¤F6VCg$4¢Q k`F5¦ak`ãÚØß;…x?ÁùRÀE>E aìÓhFÄ žÉ‰@ÌŒž( ˆ  îB© iLÃiŒÆ'•1 ldã†ÜP‡:ÌÑ6nœt†¥,cA1Œ¡r‚š@„!‘ M°°~ØÄ[{J@xBl=È0H4ft•Ó¨ê5<êUn|CäÐêV·ÊqxÕa…4äÇRV‚ûåñ†WM •®5+D&ê ;»ÒTÃèþ  iƒ œj4LjYn\«•U;ÖAÜupUŽM.8¾Á’ÚP£E1ê¶Ê{v¢¸®&2×¹¢®ê›Ý@Å«OC|B¸Ý&)ªŠ¬’ãªUÇ7ÖÁŽv´ãï°o;·ú ph•VÍ¡j¤R¨p5†uAAÓb vp*ƒ³K?Žή£8F–±ÊhXòØ`n6²¡ú‚ƒ¾ÂÕ¯9,×Àì°Œ½zÑTÒ4}ñ…2VÙÊ—‰B¦2å±2.Z i\c†žÄ!üp fŒƒãl‰¿Aåƒ#Æìp‡<¶,yÔƒõ˜—åqetÄhÆj)£þÑÊ6BŸh³œU¹Æep´”Ô:±ñ ?°Ä‘•lq¿±âvȃô°‡>}èƒÖG=ÂÌŽû÷ÒÌe®o=Šj€4Ÿ…'B UjVÐx%:¯A“šòÝðƒ;b Yã:–ÐudG:Ü1{(úÑæ‡°‡­hz¼Ã9®ŒÜoŒ8Ö°•iÝD•Œ­„†gÑG6¹ªÛ8„7V Ù*C–«è@ö< ì| ØïžÇ<²ÌŽä"÷†Ù r6°h“ØÞ|YP?¡ÊÎÐ^½F6dhJi„ûì(±9ÆaŽÇ¢Àî ;ðaH;šî†÷°]ÿK?–¾Ù@ó´¥½Ž~?¤¦„F(®ÍàQh[Ž‹-åb§± ?”ƒ«ß‡e{\d£ãõèx»…-r¦ÏÃ1þ(7Ð,`i«\ýöí7ÚíϪr­·ƒj)EZJ=ocåðFÛ(ñ(³#×+†GÒ­h~L:Ãv>âytа¡€µ¡éÇ:›ÊúþÂ/[RÌ¢rv@Fu5BùŒCü\«n_G,uXGo€#ò˜tÉí.zw ;Ý0`1Ê01@CÀ6¼ár?íþ:–êà 77  ¡õÇ¡t†ÏÕþ rÖêœ:ÔåáëÐÛ#ô[ŽÇ¤áñŒc°b˜MD!†Œ±þ¦ôÖ³§}…‹å77¨üD"‘‚¯îòô¸¦9@w‚cËÏçrßéùRe@Ce0 ºÄ ßg{7Ô_—F~0`ÍUdøä 8 ~:´ã€äðX›·luÄ gi„eðþƒD¤ †D}ÐlÐCÐËT`‹w{†uÌ–eôõbÃUqœf ¤p^~p•ž•UgVG+–Uíl*è_FKì  ÇðG p/ËÓ]€ap(€€9È æ÷_ÈÆ–_æl h ûÆ ~à –e7q²$Kê€{¸‡·‚ìäyýÇ Åp ÇcS™ÿÎŒƒà º”ƒWV_úU_ù…_ô`_þ¥yýµoààsz¨BWYu˜‡è¶‡íÔN$ýDèàGÅ  <öRb0`x Ú` † ÷Åbùµ2–Œ@È™¶ué0‡x8Š!XG}˜0–lyäé GúS|„?ËÐSÍ3€\' ž¥ íµ6öU‰ôõò ŒÃubT§UòŠæY–…‡o'\˜eZ¦e[Æk„éà?wT¯È Å0Lj2'ÐGØ@~ç¨_í°+Ór9\Xw‘ët$tõ‚v$\ÈÆkòæeò¦ey”¹G¸$HGE0ÐÿƒP r„ ìðß°2 íàŽ'6\BY_9~ D\%t²t‡vqYv’òVøpñàñóðì@÷ƒÖIɰ'pKÜp_Áh_¹–-ç€j `%Öõp”B'Š•%K|ØNQ(fó@ópë¦(IÕÈ’Ø?þÓ?±ôvéÔd·O)6‘jéŽ?¹Tf‘Âxbï@G©‡¥¸yv”eï o‰ÖkŽvøT9ñîpqÉ–Šp‰Šu”v:ä“yŽlY\'Fe'Ör¶£y”¤h\'Õ¨˜n~IŽf“¦ù z}Y’ÔXG×’º–exé?ÿ¥–ÿ˜Y‘éŽóÕrý†f%öø Q¶ULJé–eËI÷0iùPŸùð—òæš»&Ô ˆì¤‡þƒ{• ž¿Ù›hF\q©–í`~°?QF:´Uy©eÇqŒ¦û°õy€ÉP Yöžô¦Gä'\ýE_É›¾I\œÄe”7$täYx¸ÈÆqŽVöIrö€’P •»¶úøšÐ—Ëueäi –IuÙ_1VbFY¤¨U¦ˆŠ,&oø ÷޶::Ÿ?:Xy’X‰È¦0&_X×rMŠ‘ã鎘ù¢G‰ 2 ¡Ûùž}Énõ™¡*iÒfa&oñ o]ÆeÔéÿç`<è“õX·¦”Ù›F‰? ’7”‡º†X*iÑ™º¡“æeù`÷PŸõÀ¡_Ö¡)¹†êX‰+6‰+ãŽVæ¨j™ñht:£vºb°ÉkÌ÷kžš¡–£ì¶h¾¶h>f~©n¬Ú”0†fš¸¤ÂÅ¢¿©FY§w(Šx©k,i’[ºЩ¡ ·Â®ÁÖ§:ZŸQ)oö€hîºbôcò Žž< crêd3Z©˜šn%ù—{š¡ü@®îF®çªw ‡¡6ª€Ù®ö°™¯i_øul•¶em(hæŽ:} ذ¯J‰ni˜ù­ r劲y7l›¡Åj¬)©ÿî:šó0šó:›/ÆŸïÀ» ã •*ŠèeÙ­¥Š²¦·²J»²F®à ®Í9ȶ™ˆÖ®}9wôà;{lY;µí€}0 ¬F ‰õsºFÔȡ󉡻´n»´äúh¶¤:o}鮾¦h:ú|Ç…4«µïplÀ G§Ó’·k»6Ÿžú¶Žë¶M;°ú0•'ŸÎÉnêœÓ9š‹šøÀœ}@¸#6 å@q§,É¡û¸¬ë¶ÂŠó€øtlê®øpl²»»;¸Ó Ôp ÓKB§¸îPªlۺʻ²àÚ®³ûk‘æ´¼›µø µ[*»ø°` U<‰U©åp†™[Ú¶Ë[¾åÚ©÷À§LDzŸ:•*°Ët7)Cß ¾|§£æ»¿ç륎˧êë´Â;tktreectrl-2.4.1/demos/pics/imovie-04.gif0000644000076400010400000001322707577521114020476 0ustar TimAdministratorsGIF89aP<w!ù ÿ,P<‡     " ! # #05$#* ) %?5 9(##+#%%9 '79% 6&:4&&#),1,4%/067*'3-767)665%@83LG(4G8G+?`4i-/_O2f-h:,L?IO?`o/EIKGG'DG9EX(HT:WF*XH8VX(XV7GgTo1@mJ5gs7GHDJJRITGOW_TMHUOZ[SL[TPXOfYhJVmmeKBcWKa]TzO@vWFwZZmYlfcGkbWiyDgwSwhKviVvvJ{wZjeh`opewek{sthip`p{skzxx_wt”Z„5f‡:M‹CWgZ¥OqKo€o`‡poŸp|ƒfƒwpŸoŸwmªXy¯gwÀgw‹‡jªo °ϰŸ0P€O†Q;`7‰\J’iS‘ti _P¢nZ¦ubÀ üÀ0Pï?PÀotÿ@_‹x¯°€Ÿ /¯/†ŽUŠ‚g†„y†“f‡—w–ˆo“x—lœ”v W‘«m­u°¯@ª¥tŽÏx ÏÀŸ@Ó“sï¿oßÀ_ßÐpðÏ`úïtŠ…ˆ……•—•Œ‚šŠš”˜••¦“§“’¥¯¬—ˆ¬›©¶§‹«£§§§°¯°§«°³·§§°¯¿µ°¬··³Ÿ¯Ó³¯Ï—Ò…Ï·˜åŽŸï°¨×‹´Êª­ê˜´ó¢ ÀÏ¿ÀÀ·ÇаßßÉ™‰È—°É®•Ò·ªç—ç¯å¶¬À¿ÀÀ¿àè°ÇÑÏ–ÑË®ÀàŸÌñ°ïÏ‹ì˯ôï”èí±ÉÇÄÀÀ×ÅÐÅË×ÐÐÏÇßÐÏÔØÕÚàßßïðõ×ÕåÚàìïÑëëëëðëë÷ùõïêõêõýûíûüûþ©¸adŠ5_¶àä‚ÇÏ×” ‚„ÉRæÆ A&ˆ¸0!Ž/¤¼XA"Ä„''R&Íž!%V¾|Á‚ÅGVhfÁò…Ì‹\@IôB¢ ¬Z1e„»wïæº¦ï pôÈ¢DG…:D¸0âV¼ÐQÂÃP*À¥,™>@X˜(ÁÒå‹— {¿tÙÙ÷ DãžЏˆ ¢4¬p`ˆ b¹Úù3â†Tº€ÙALŽ $`»à‚Ž ^|ŒàpCƒ ÕÝÈJß-Y²xÁ\¦_/e”d¸À%‚“ >”@ bD>K0l÷Þ»bÖòþYÓ1bƒ8>†PÀDŒ…²wà€`AI—.J<”ñÀå„?ÖÃ^2yœ_7œ_X”1Å#|Š…0!\ ‚IHä7Â(ÀìbÊÒì# d‘Ã`‘6±DP„±ÄÐDK$¡Jt4rð¢L>·`±Å`Á WM3…„&… ÔQÕÐ!€ ƒ9AD P¨±Ä|ÒQ, œ¹QÜqGj4A„#k„ñÇ LpàAÜàEÊàóÆ}Mö%‚P~QDÎe€€P …R$øPD5FñH›Q¨Ét6±ÄQDÁB'ÿv4ÁBw|Lè°ÅH8±„PAÄ'iü!Ì'S~(é \ðÁG1‡sCuðKܺÄ'w,"l·p«M8ÁÂ,°«D8‘D\¨C08á«f¨Ám{³Æ3!ØM<%ÈSb¼`s!t€ØPDqù¨ AD´;k h@Æq„Gd¼P±Â\pƒ ¬P*¨ Ê(Ïé„HX1q ×—£XŒqYH˜AJ `ÝS¬2ËðŠ‚„ -hÀL`°Â*8‚g0ÐÀ%ÀA'Ü`Á \Ph‚lqÆþ+ qÄ^Øäà2±1Kes(eðAsFd¬Á[¬°B9op¹ +là@/T®*¤s ``Á8^à AÄdVø`DK”AFÀYqVm^°ñ#˜0Á5ÔPA4°E /À¹ „pFßß;Ð€ß $°)40Âä C;Äl¡ H8 6޼èÃJHñ…? ²P…™L" AP&Ä ÀR ÁŒp„x EX@€¬@ X¶`¿-„  ˜ðÖÜÀJ,`„À% × Âð üàƒþñ‚Œ ‚¼4bÖ3 DìÐ/4…„`PšÖlà3+øа 8@“ ÁE€ƒŒ6ƒ ~`ƒ|Àrð€xÈF@öÁ‚M‚Pá Y8OD‚Å„1 PàID #€`_İ€@ è@L %„°~ @@ù øàø,&‘Œé°A†'ôñíÑÁZ6t…àM¡˜Á!´®Å€Là! Ê…@°€ˆ­ (Y  À:à€‘À`E8JBà4@!Œx…$82@ÿÂ/}ùC0à@ŠE Ž9…ã…àBy@0D” ÓX@J°O;˜€@€äÀ†ÍËC`„¾ùàEBˆ€-ЀÀtD$±ˆ<áY ƒG¡ÉJЙæTgC4ɶ`akë‹(r‚`àŠ[ v%#(,¢ > Bð°>¬4ø##1‰F<¡8 „ù‚+LAhÁQ ™@e‚€%AÌ0$àpY€an²/ØtB„`-D–PÊ£_€åˆ0ÇE€a­XD#Ñ1€FÔÁ!þù…)àB#)©èV+°Î¨EœÑ0`Û6j€H`”e€Š $@TpÀ¬…`!¸@‚4€;(x5 ?HmÀP†2`á!?YË p$D3•ØkøF*4 t€û€¬ l €0€À:Ø‘à7À '€â Ê`}ìCUP’…I¨¢“@ƒ#ȇ¤ò!Ax L^0Ø1 @Àð€W¸€®¸Ñs¾ÀºËrĘ $à*Ø„€€  @–·l© Žp#aƒ$tÁ_(çrþšºê¨ÑÌo*µz i¨ dÀôl‚$WT} 0À€ŠcNsE`€À¢Àᇤ™!¤ h #ÀàH@ ø‚2@‚À$xXÌZsQÚm rØ….B!†X€H¨‚ ›dN Àøñ ƒÎUNì †=z‘‹{øƒÐîG?4„î5 š&êQ~¬¡:èÀÒf¶´èàšYtP nlãà†*€ðH!(Æ•ûàgàhà û ¡ö°?ìq cpCÁØÄ-4q…RXÎ(LUQtÜããG0Á þÙÿ[ §S&¸ p°x—#àø†.Há<@0@Y‚·t”8À”Œm$#œ€Ä$æNP2›6sØÊ$+À!`„p”@ŒÀ&¼Áxn'\¼›A fЂ}™ãÔ¸<5žAs¤£ÀpDlà „Õ7Ã#Žsp¸>ˆÀ2€Úkñ!dd/@\to p€?¢‚ˆÒ~¶>ôñl6PA”oÁðà W\þ˜Æ9àApþ”Üø¾*Äàƒ:†A ÷¹H‘ `Üè°Í  l¢Š= HÀŸlApÁ€ ½  c0WPq Tà zÐ ƒPÑ Ó`ÔpÑÐ Í ¬À °À Ùés#Ú  PPmä> >0\l° v°c 4%ö³[J[à†0Uv$UPSpR`ð œ7 Ï0 VxV8 ƒÐ Ó°}tZŒ¢ŽÐC9€%àFoT/@\­¡Ey7´l %R%°`< –p ™Ð ÝPà0/ÿxÐ zpS8 Ô`…® \xa°i`Ài¼tZCP5p·¶oû¦QµWŠx˜µw)ØÄ0 ÀA06 `:0J` õðqó°îP p`®Ð …`UH щ ÏP…ð {À4@;p=°@P@p35†ÌT"l©ˆprxr˜w@fQ @Ô5FÀt@c '€aB çPx0…‰Æ¸Œz‰Û° èoŒðRÀÐPЏ1Ø´Žâ˜wrÀ™w@P‡0:ð‰v' BpA æð ÿÍЉȉϠx‰Ò° äÀ ä° Ù Ù 9@pØ"‡²G‘:vc¥ˆyWh°sÁ¶c[ š Ú0Úà d© šÐ¢0 ¬Ð{Ð ˆ“›g€H€°$wÀ  í— ª G7 E'ÐM4ƒ5ycpe¶Ç>ˆŽË“d­8`…šÀú  bN7,*°À…Ó TÈyÐN|`90z4## ­VÑ• Áœ€˜E’µw…c|  pPc"0†A‘…„e0 P'©ŒUh…ÏÐÿj  ? aà£á+‡#™ž hAÁ )à À¹QµçЛ$ÉV´sqál ñò–x€\ðA  é dð fà ÏÐ RÈyƒ€°†¥‡?@6PG#P0Iˆ1œ´s-ç«TcÍqi{8("`=ÐíÀþð£ô` \0 `<Ýð õ°k Z…Ï Ñ€˜ s' ’0SŒ@G40(Q½é%@px`- 1ø§d66£µB tÀ p<AZÀZ @À) ßÛÐwŒÿ­0 ® ä ’€— S‘ àGOàЦÐ¥½¹Q @ j€úRy, >@§Œ† Ÿ`œ   ÇÀ šbPC0À<€ `k Â@¬€ ¨Ð ÚIò–Ž`V†2åð-RG\ ¦aŠª P ž0jp-°-`(3:;XŠáxŸràÇmÐæú` q€APƒLp°„èÀ «à ÍH“° yt…2z;b Tú¬hE‘À>IV f°v`N0±ï¢.-p9kjwXhǰ—‚¢JÐ'J@]š³[€{ ä°Âà ÿëР«0 I@…âud;`×øC ©‘ ¢Ÿe•`{°w ´ƒ ;±N€iº£Ó;7`»À ¦ a@d IÀ]°T° x *Ÿ”ê°à ¬ jÐd PP~/µ=K5°?°{‹ž"”­MÛ´­¢´w`R{¦úâ[€â…=` §   ±³d KP^°n@xÀ²{ ²ð é ¥K ‚ @¥³ûaû¡ê¡~k4Л:V ubvB¼Më¸Mk¢š.‘ëQÐw ^» Âh |Á9ÀCÿrð 1-0« µ0¨CP-àj©ì Kî©5õ¡p V g°´v±{{€ ›¼›¼âú ¢` ÛÀ Û@ªðL,ª À.ÓP ´ ªÀ ¥Ð.r0©“j¥ëÛVê<ä¬P` œ´úÃKû¿vb'['M+±Nð ¦ ¬ Âð ¼>‚r÷u@‚ µà ŸÀ ÚP Ø€ Uà‘* &,»°4©ì[†y‰~f•°´ƒ€ ƒpNPÆKkŸ°´NЭ²´Ž»fð § m— j@½¦ÀEài pU ÿ÷P 0È›ð Ëp 1`ÅV: V:SX|Âh¥Oh b° (I;±ÿ‹ µ²´¢Œ LÛÆgÐ*Íë¢àÃò¦ kÀ Ü` I€zp Ÿ@} ë€ÈmpËÌÌ l ÁVɶëùdzÌì·;PËP Ÿ Q»´¶BÊ¦ÜÆn¼f‚¤ð À—¬  _«¹¬*àµ+¶@ˆ /€\pˆp¿@År@a0 €°‘ìV Ž`PÀð0 ̓@±h<Ã-±Ë*HàP4ðJª0Î=ÙÀ ¬ÐEmuð ¼`ZpÒËð ÄÒÿe@   a ˼ըa bà8@7c¼Ê{Æ9lÍLfpd@ý¦pF€º Àðd°w¬ D ¬WÊ r  Ã0 k1qq Á]`Ó³K¥‚ìÅ4=8r¤Çi`å»c,{@Lë¼¥Ò/j ;pF'19RBM ° rwºÀ »`dè]0»@ Í ’,ÈíQ»’f¼f‘š@À•Àû²/Ä«´P#°Ô•°Î ‚ÍfE@¾0ÒöÞìí®?êÞÒÆ|úÐòÀ rÞr0w³»šàÜ¥ñÛ€ ›öÍ= 3åÅ9ÝGu½”4.BÔé°ä`+Îû žk ñðÞ>zâTþ£#~â>Ê|×à î` ªÐV sÀ @ å0´‘ œ ý,f@Cð³¯I·ö­†O-ráëà ªp…í£à{ùU~èˆNåÌçùð¾€ €P Ê` À6 Ù qN¥’\àÑÝ¡CCà]ÔÀ­á¤^ ê ͰDò°âU>åXžèµþ£Ë7óì»ÐJ Ùàæl>w<  ð`µs›4`kº)3;tktreectrl-2.4.1/demos/pics/imovie-05.gif0000644000076400010400000000624607577521120020477 0ustar TimAdministratorsGIF89aP<f!ù ,P<† 0 ?0O/_/O0/_? P@O@0_O?`O o@0p@/pO0P0o/___oP@p`P€O/P0_@oO`p oO _¿PŸ€?¯ŸP¿o¿¯`ÏpÏ¿pß ÐÏŸ€ Ÿ¿ Ÿ¯¯¯°  ÏŸ€Ï ŸÀ°€Ð¯Ð¯Ÿß°ŸÏ¯ À°°à°ï¿Ÿà¿ Ï¿ÀßЀßÀ¿ïßïÀ ïÀ°ïпÿÏ ÿЯðаÿß°ààïïŸàà ïà¯ðð¯ÐÏÏßßïàÏÏïßßðÐÏðßßïßïïßðïàÀÿàÏÿïßÿðÏïàïïàððààðàïðïàðïïÿïàÿïïðàððïðÿïðÿðïðððÿððÿðÿÿÿðÿÿÿþ€‚ƒ„…†‡ˆ‰Š‹ŒƒS\\T“\`–——c_šcžœŸž`¡£¢ c¥¡ª¢bž‚TTSV”\X`¶`·–¨ž›©½À¼­Å½­£É b¿›¥£­Àb‚X\ÕX¶\cX½Íb`ΦКћ̜¿¼½`ÈéÀcbƂ׵]V]—•–˜KEðãB…¸Ð ¯dÁV¡6‰¿[ýY8j¼M_¡Š§ìá—/ݾtìØìݳzžZQ{4eß>.]¶åSé9a%ë‘4Þ¯JõTjZ),]0™¬ÑÂÙ/'–mXº„y'PèCSô ™Ääó]4eÅA2‹‹,þoùÙ’‹ ”»ŸÿH¾Ä¤‹ïÈ‚@cŽ‹6î•ÔkY­æÓ…”ð¼ëxkäRr`¼$ØÌÄŽ0aŠ„9ÓŠéGüºäT+àB¼ nmøoÝÏôTE4Øé•éjp÷aÑbL?㣾¡<øãÈ]·z’åË bh¡‘#¿4ìÖôi›ªo-îViÓcoýÂ<®üä%/Z$ËýÉi<Á¯´á„Tsξ}5fÛ€|iá×_–¥¥ +dc‘-5 §Ø(Ü\%geY’•†^`_fã¸gY)gÙ“Ih$NÕ,Û &áE—ÕU`8œ%^„§á{5"‡;ÄÜgƒ“‰¾™þÆÍ#ªQ•NÆ ØØ.5Ø…"—%&£VBâ#Ê+M˜V&MTuUj·¼Å™‰g ò¨E‡¨ˆäÔ1áÆ¥:3A˜-SÀu•M3ªœW,*ãUWi†8SN&J¡ZšÚƒÌ(ùÑt’” žjÂÁyå•;r9TžÚx]˜žŠÙ 5NlÑD×:ê5]ZiWB )œnxÕHÎ(5Vuy&¤^ÉLÓ`™¼Î2ŧa—[UDZ¶ÜRg_XŽórö¨T³%´ihk±eE[lëwsMÅ…nms܆ZÄX ‚Ê]ò‹)^4åð'3±ÕÄþ+yZÀnŠ‹•UËÙ£W\ñqÃÍQé×g`^zkƒSPQæ,z/bYik,=òUEQD±>GAç.J¹; ‘– £Ù0ÒÆÃÄÚŠqNû I£\ ÄÄ‘ÀDgDð€ |”yœaé¨ÃA(‚ä3)5'Ö¹5Ýì ZTPàÿ…†àª!€#€Î ˜0&0ÚÂQb >s‚j£îfŠoW;t`ÜàâT›‹Ô`V` p «½ì%)@€–h@áhp½(ˆ¬F.œ§Z˜…µbÁ0™ƒ J·àÏm]ÅŒ\T^E˳<ïn\-@Xxõ À;A‰=yViQj”HçÙ(2M¡ ™ƒÛÛªù÷팑UÈÂݪp…»EÁ´›Ô@9z†êô« hÀ>0‚cj”¹;«,s%Ïñfá²Q¹¶ªÀ„¸Q ¸£e$^›«A-„Œ Í»€|YÎ nè´û„”YPnrÌÜþ7÷¸Íµ[Ü7±&× ;», á*GoXhîd`ZÃuÒ¬kÀW¿ŠÉPÀ!ð @ùàñ‚ׯÇe”ð %üÖÂLxp'¦ããþVÁªÈfP…%˜`àäà*=ˆ à XÀ(p°`ïƒuÌö’Y LHBŽ`¹]nÀš0ç cø¸£Ã[îæ…ðPžîpI×€Ž<]€'}ðƒô€Ì;Ö1šÓœæ5¯ùl^‘[-¼é »Ëìp}Cv·'<Á.Ø ¢LV_˜Ѐpà“ðìÛŽ•„¬`'À@2° ÿ ؘ@7 A% ù·¿-ó]9ïì Y‚p@ˆ@/@-ëÊÙS(@8â4Àh&,×¼FÁÔ; È7½ñÝcZá¨eš³úæÜÛ+ÚÈͶtÀpà@.èx °à¸ ðHÀ¦;¯™pƒD@Ò“^VÎò•ç»ÇG¸¿!h\ _˜Ãö‚¤`„!ô\CØ6·I€jxàèGï,€¸Áa`òÎwËñ-yWµ€ wð¾õ­Ù/8³åœÜ(ì¼çCðù„ t‡“àÛ ˆ;ÒݸX';ëUϸë§›".lþ÷c ®c¾c®»™ÎhøœÑ\)<ç>ï9Ú×Þpàá"ˆ»Ñ;°÷Ö©îp#`6pÕu v­S6nÀúÖÏàõ3PÁëpÖ'Á뿲ý!?WûÚÙÞö¡ÃÝè|ß.éCÀ‚|àâ#¸jôGÀXF÷@(Èþ±O€x%0AJò›ÞÏÀã‹`i÷½æ?ÿ"!íB·¼åEàüàA€€(€AP€ø×( Å&{j¦´‡i¨-D/bàxóGï—v‘7iG÷§Càp&ˆyCð;`1>à;;°ÿ54X0ð1-0×7j¦f˜69Àz9p„Hˆ„L°siÇm¾çôçl7| ·mhE0ƒ7X6À‚5Pƒ-†<Ø‚2 h{7@„$Fb- -0 q˜ƒ1ðX tPHh§‡ABtF $]Hƒ]h\ˆƒ=øޏƒ>°ç†2P‰-p‰˜X‰98†;h`€æÛo¤Éy·Á]aB,4Ù[ÊlåÝVh‘gÅPDH^@æ¥7!îphõÕ'@~Ø7€þIÁVzWŒwÅcYèf’wÅDA`p (ˆP0‘#„žÅS¤!†P(¡;þÐá‡æçöå€ÄKT¹ƒ;ÀÃ\^Éă9U.a•L(Q¦ 1°ÀÀpÆ Á ̹À ;ŒÅ+(ç0i€ (hÅ9§ŸÅ-Ð(œsBP )˜bº¦v.*–ÚÙé(0gŠ> ©l¦€ó=Y¨„hß¼*Zq{ñÚhqÀúç’Jê(¯Ç ¢Ä:Ô Ã 7” ƒ "Ì„\`d@Â\ ‚%XМ¹ IÀAg |0¸ŒË­¶tð¶LPÁ4ðÀ®üÛïU¢w€²C Q„ÂEq„ÃG Ñ„þ(ÐDHd1=”ð4aÀnU˜0S 7x[ (ˆAË|@‚$x›X âÞ•³øJ ÂC¡G7\=¸~@4lÄÔGô‡ñX€ÁÖÞŽ A$”ÀC<ø ¶Ùd—PÍ.[à€t }äšë€q‚,„ ^´=äPø Dñ°Ò3íÀìFðA”€1`I`¬1ŠAx=ö< PºÛX•µXeª 9þ=„ìBa;=ÔŽt:ô@Äï‰÷@ƒébÌ6ÄŠGœ1™c.qÐvqæØ'Q:oG‹ƒ þL¾pÑCÜ.DB‘ƒí¡ADÔ4àè  ÈdBÍ.<Ü<çœkþ¼æÑ»õ¢—9aLsG Zí—¾:ðv@Ð öbj>œ±Š<РOlcÞþþ½Œa¯„ÿ;¡²p‡4F}·kÇ„Pâ@I(€¡ê3¨‹=0‚þ~§¸†%NÍK"÷¼ª•F@‚ `PƒÜàv½k! ÛÇ>ÐU@>9 #sxC?@aBø.pÈàç3b€p„Ä9ì}ELŸâþ'ˆôN:¸A º£E0t t_l˜Ð`>ZÎrЂ¢ÏŽéd=þ—8$Áa"LâÃŒÐGBön90\m·ÊÐõòiä}Ž3F-98áâÈÉÜFÔ_ÃÒX;ůŽE(åÑ ×¾?Âð…/Ô ©¤^ÙÇÆ):è;±˜r&½©¿:"SÀ<‚† L@.“…½K$û„ä()98ì$ç³bÑ vœLc@#èÍß Š¿C_BÓGJìwïÄ]ûùBŽÕð>xä  Qå àõS t »Ðy.ŽLŸçlGL’~Îs=`'”€;îpÎ+¶âCa¤ #“#? „ wïsŸJÝDZ“*T #fY ÿº>¦òL¥Vy§SÎÀ†…ʨ#¯Ù«ìåžË¡@jpSŠš/ª™TjJ3:™î`«©¬¢VuJNð†øPFÃHTù•ŠP,ª z§ÊAvUwŸƒë/ç*«öN©äë RéØ?~° ¨OF¯IÆIB >d\€ÖÊWÃqÕ¦ueú"˜H¸Á®9¨´6»Y+Þ ·¼ ¤y8R£a´° på*€îĪ){€ƒ¶Æ¶}³…lí¦XETNkZ3˜ r€Jé ó-e XZÊRîªÈXB î,dg›;_Æ´2 xeЄ ¼âÁ´6{³Îþ€P3X#í3ô€‡Øt˜™Êû2¸œÍïkçKÂq—ºox¿ë Xh20ƒ '–Ëid¯ Pƒê†(47HA ppTæ÷åtƒ‹_þÞÔvStÁ‚U,ƒ» -žÖdü*IeÓ ˜%°Ìz«92@ „̬ΠoäÝ‘å¬ä¬«Óªî‰¿+ÞˆÀÙ!hq2"ê09f5NŒ³bkW†³š#dÓe–7 ä÷ªi+ŠwÜ}±€û‚€ ÔP€ÃH€˜jNxÀ°`©DcywÓËPÀ;$ßVTò €ýÛÞþÿZ3ÐA”§çi Î%¸À}VÃŒ  V¯ÒæU¯ Š2 PPlÞöÙX öVÓ[A¼ €Îr #r‚½Ô®v«¯}m¡o°«3 𵄷ÃG¾³Â¯jîg%»‚`•ã ‚T@Æg¬¾-hA~ç¸ÈÅh pà@Á PP"ÙGæ-Ã}ˆ-ÀrD¢R <€(4«ËïŽüè׿¸¡In€ðå*HÚNPnbWýØ7p±t#žóy—ÚÔ7øÁ|ûT[‡÷8ÒÕnÁ¥‡qžùèÖ`‚° •.‡¹oUìi›¿ËþQé€ f€±Aì*(Ä(ò}«ýÚ OºÒ p€  ÀhË€Ìu¸íåƒç+‘Ëkìø=çîAVÿƒ ¨M&ÀÀ@mC‘19ø|ÿј@À÷ ‚ð¶ˆÜà„ÇA†Md «E6½»[ à¡õDp½ÚR`‚|ä«^£i©¤V‹<à‹·Lp‚¨óÒzãxw{ü7»P…~‘#îß1ûc{€^³Rt”·7 Ð ¸+$Xüy`Éc¿çG€ÒRnƒG^ÇÆ!P€2Ðb‚0‰ó;¬u&èÅ €€öf0ƒÿ {Ó/{(×F+D( °5#°f)G2Pv`w Ð €)‡„û&xxÂw¨q4ø8ð8šñ0ehƒ]ˆ,±tOW#À~*ÐzH€„ß^Ó².ñâeSUÖG<€…# …2–eÈpˆš¡/Ð*cXƒ¬R†4è/_‰¼ÂCmHí‡AÐ16`! 3@eCÓB‚@& ¨³P`ÀŒ(† ‹=Wg؈58†(‹_èŠ 4È‘~7o¨'xp4"#9 93ãb.  09·’‹_¸ˆ¯Øsd8ÿLj°±ŽPƒâhj¶(‹Àˆ{Ó\\È5H$0P;39ÞâlÓŒæ…úŒáØsàŠ/ŠØ*±8±¸Џ°øŠâ(‹±Ø*íhyA9 p5“4qsC7ðgW&†U‹·8†‹X†Ú¨šÑ*ÚÈÇú2 0× “€“I†Äs+2Ö\C/üâ0Rfe‚@,&¹ˆP†à”‡hq™’‰X‹;©“ð{ãYé;yŽã8ƒôQ€tÐFÀ3ðfƒ·s‚€)⎠Ùs‰ˆWɈâ8•±• àY`„ù)™ƒ8¦€ê2.õh o.à0™”Y™–i;tktreectrl-2.4.1/demos/pics/imovie-07.gif0000644000076400010400000000405307577521122020475 0ustar TimAdministratorsGIF89aP<D!ù ,P<„?/ _O0p_?___`@`O€`OoPpPp_Ÿ` €o¯p¯°ŸŸ¿ Ÿ¿¿¿À  À¯ À¯¯Ï°¯Ï°°Ð°°Ð¿°ß¿¿àÀÀïÐÏïßßþ Ždižhª®ì8a–…Í­m7ÎmœÖóNg8ä…Ecpéi:ŸÐ¨³ã¡:E¯X¬†Ñxw¾ÛnÇS—g"=”º«Q"\4»Àf²Y7<öõŒ€jc€kHkpSoOigtu1‘9•–•^–J`a@IŒVŠUgš•€XzZ0v”^5µ´³·c<žmÃVgd²¼¼°X1Αv·]]ÉÙ³¸^½´šdF@…TÄ–´Ù‘"õõîÏû’ÚÙÏb$kÕË–-\´4p»ä' L !U PÁ^½y""h¤'Ac ó@Î9‘Å‘þÛ•Üå $n·r2â…W;õ4Bð¨1ãÆyEÒ«ˆ³^ʼn" )2[-§üÚíjEiÇS~,vŒ°s'×" ˆõØQëÇ‹íBrLªõ"È1ú}‹ k[TzuŠÝ»Wă±^¿nÔX–Þœ9æõŠ6$¾‚»zí»Y¯+W±ùBð«y¯` Ë"–àYgÞ¼Fµã§¡Âºl.P´§·+`¯a;wþ ˜pG¯Œ·æ¼˜ržÊvÒ&NÄyx+Osëæ{øô±9Z4,¡¢öìÐÉŠ~7€Ì˜÷fF½óè¯!Ë¢>}™÷YÔÎy÷pàÿÿ{˜ýwÀþ À‚à ƒ &((È x&þØ€B`À J(„¦˜b‚%’há…Æ(ãŒ4Ž.H£ƒ"܈Ž@)d$ 9#ŽG"ƒ;*yd“<ö(£”7>褑IB¸$“A6¸dŽ:é¥ .8€™œÙàš_ú#“cÊÈå› `&–]–¹¦ž^†é&3òÉæ–€€Ÿ4ÆI掊Æx"|¦9€$P€gJjè¤  €¦i€©¤[ :f™`"ê(¢&ð)£fš¦¥$°À­¶&€@’ ¥išªã§  ê®iÀ«¦ËŠ`@ (m® þ0P- $À€µÛZ{-·h‹«¥•† í®Tz)¦Óêm´H‹À¼ k½ËžéWØv»m|m÷»íµb0¿+ì@ÀD,±ÄNlqÄûÛ€" @µÕòÛíµ·.@pÃ#+Àm·"³ü0ÊÇ|qà W¬q·*w¼²Á/ÌïÃÜÚz­¶›Üí´ í­Éíï¿c 5Ð è|ëÊ /­·âzk­Ê;?Ý/Í(lí¼I|õÒ ¬ÀÇòº«+V«\òÕ ÌòØ_<1À·ZÌï­µF 6Æ ;ÝmÙ ”M0Ÿ÷aÔ~Wn9åã]²»*‹ÀÝþ=·œô¼ôù.[~13Ḭ̈ÄýÚ}5´pï¶Ú~n-Ê_/ íÛûN~¹ê–7.8ãXW«k¦ÄÎ{+¿¶¦ü¬¶UKÞ÷ß4¿±à #Î0¶ O«6éµ–¯«²Éz~n­¼BkÀ¾RO±Ã}ËOñËoºòb͵®ó*À¼à©5=+^š@X*V1“ù s ûWÉ®’Œ[ øÔÁd7®õUj^”Råõ>É-Ž÷«ŸØÆÅ6ÝÉn[ƒÖ­Þö.jiÍVœ;—Û5­Zéì{ Þà‡«j/z¾S“¸f·ßI*^¹’á µFC„‹sáBßéD²m9zšÃÿ Öî¦+0h¸ª]ö.¸EkŒSL“´zø6RPçÛÈ’6­Š Wj£¡ãõA(Þ°]…C$éàå®ò)kõ@ÇÞ(´q•‚£ïØø9¡I«vîûÔ“X&CÙnY‰\²že¦_u¬ˆï£ £¸I[ÕJmÜá, 7EWm Så+Ÿ%ÀGZq‡$ú u>}ñçšTÄ&£˜ÉýÁÒ‚g"¯ÊW,uÑkZjÚÔCeEsÀ]u¤¦´`)EúN\B;ÛfEMYMêS¯ª”ûð *>ÑŠ˜$þÛÅLuRr ´ë!µ~G.öuŽ€Þ´¢({(Q‹†J€%<Àôx˜HÎñm€t£´&µ+Žú._;LÓ=e©«9Îð\m´]&i¾TŠo¨a»$ Èr©)]B-/c8AÃQŠv\*ìµQ­nT‘m¬!M]%{ñê‘ɺ¦H©éT]®cÓKä"‘j>rrôšzµè¥L9¯·Åë°â›Tí HH½ Z" @#³)·D Õ¯êŒ[á$åÍô™õžØ Wé¸+XÎùVLU:µ¬o]VlI;-pŠg…U7W›Z{‘µVÏ: h µ×É’Ž€Äu×E{zÛE¶µåU[{®5¯ÈŠÊ·À$Ýuëõ©ßNÖ°Ô¥«HÖF–.‡ÚÍW° …¾Òyð€Í=m7•E)QY7Ÿ ^—¹V{>è®öRßÜ&gµJ/Ë­UõÚ‚Ý:©ÈNêÀ˜šo}K«,cZ˜|·}¤=@H‚È1§±ZÀä&;ùÉ&;tktreectrl-2.4.1/demos/pics/internet-check-off.gif0000644000076400010400000000010607577521110022424 0ustar TimAdministratorsGIF89a,€ÿÿÿ%ŒiÀí}žd¨Šo Ëj¾y*¤hŠerja6ªÓSÍ‹çG;tktreectrl-2.4.1/demos/pics/internet-check-on.gif0000644000076400010400000000011407577521110022265 0ustar TimAdministratorsGIF89a,€ÿÿÿ+ŒiÀí}žd¨Š•¥Ë&Ê`µybyz!èdgg¾]ô™¡fO©ß×T;tktreectrl-2.4.1/demos/pics/internet-print.gif0000644000076400010400000000017407577521110021740 0ustar TimAdministratorsGIF89a",‚ÿÿ¿¿¿ÿÿÿIXºΰµ%¾«)eÙTäXñ‚@ÎS„B ÃëÌ#iÃ;Þ«ÜC`0¥BcÇÐ Ä@˜’5À¼È¸¡Šf$;tktreectrl-2.4.1/demos/pics/internet-radio-off.gif0000644000076400010400000000010407577521110022443 0ustar TimAdministratorsGIF89a,€ÿÿÿ#Œ©ËZ€4*ˆpz×¾€Ž·‘b™‘)ʦæùUp9K¶];tktreectrl-2.4.1/demos/pics/internet-radio-on.gif0000644000076400010400000000010707577521110022310 0ustar TimAdministratorsGIF89a,€ÿÿÿ&Œ©ËZ€4*ˆpz×îx`‚ãdQä'¶›Çv°öV°|Kú^;tktreectrl-2.4.1/demos/pics/internet-search.gif0000644000076400010400000000016207577521110022046 0ustar TimAdministratorsGIF89a",‚ÿÿÿÿÿ¿¿¿ÿÿÿ?x* úp1]|bN3lÌTÈyX¸ )‰hw -'«KŒÁUÏD‘ë€×ûéDß’4.›Kd€pq´«";tktreectrl-2.4.1/demos/pics/internet-security.gif0000644000076400010400000000015407577521110022451 0ustar TimAdministratorsGIF89a",‚ÿÿ¿¿¿ÿÿÿ9HºÑ±†@QRÕp&—äe!3F—Ó=¨êžìWr„`ßö ‚î¤?8Üç ƒ·_Ouª8Ÿ•’;tktreectrl-2.4.1/demos/pics/logMedTrans.gif0000644000076400010400000000747111467607432021211 0ustar TimAdministratorsGIF89axµç9?[SAWXBVRDZQG_LIc`HZeMagM]URnoQ`iSggTjfVnuUbb[upXk|Zez\jw]nu_r‚^gmc}€`l~bqˆbizfz…esyh~ekyj‚k}yn†’jr”jn‘mw™mp†r…žpqƒvŽ srŸtqœt|•w„ vp¢vxŸym yp¤xyŸ{m}“š|‡ }l’~¡{ƒ€–š~ŒŸ€k¦|ŸiŸ…iŸ‡iª‚ƒ¥ƒ‹žŠf«ƒ‡˜ˆœžŒfª†˜‹Ÿžf’c¥‹—°Š‹°Šž–bªŽ™¥“¤£”¦°’›µ‘—¤–ª¶”•«—¦µ•°–¢°š§»™Ÿ¶š¤½ž»¥­¡³·Ÿ«Á¡§¼¢¬Â¦¦¹¬ºÆª°¹­½¾®»É¯°Ã±¼Í³¹Ä¸ÄùÇθ¸ÎºÁÓ½ÃÔÀÀÕÃÊÑÇÐÐÈÒÙÇËÖÊÒÚÊÊÛÍÓáÑÖàÒÒÛÕÝçÛÜèÜßèãéêäèíååðèêóíîóñó÷óõù÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ÿ,xµþ H° ÁƒÜs§a4Ó|‘BQЉ‹}¤é£°£Ç CìÓ°!›ˆd*Jñ±¥Ë—0Md©#²¦M„%ï<Œ˜EeÌŸ@ƒþÔÈñ¦QÓ¤¬C¨Ó§PŸÎÀLq Ü<ÌŒU4pTÐ2ÃÆÇ-FÆþŠ@xø® ,*›€©g: c‘€•^õ<¢“2¨•Æ„0Êi€g2L!e‡u Vˆi,œè1E£`2Y« d áœrhOD1ÂH;%E‚ "¦µbÀ)“œê"”ápq`w)ª·%/HJ&°BS§e¹Ê° FÈ<@Iýì Ý*ÓÌ0 Æ ÅTHà‡´FJc™ikß*ñÕŠ!W­â倚3!UäË@Øi‚‚¤q4ÌP#<Ì“žˆª]<᱃ €Æ`´deÖ0áHMÀ… ¾«µ*=þŒC ’Øù€¶V?kÃOß5¨(&¥{ Œ@ +WÄa·â2 ÜÚêE Æ””傱Z ‚(=maRÔH™€y8/„87/æé. L ‚ðŠKeLsc HÔ zWÔXÞƒü¥0òæ¨:ëØýë /£ÌlKh¯@¬ VÕB 6+©ã.³QŒzf°ZõP8R©¹¬`ê_Á( ¸5&,®`×ZR ¥sR¬Õÿ)ä… ‰c+Ü0$Õ¬&0 €?æœ7Åé~)Ë ù˜F>N3|J×s¸­±2``¦­íËèà€QYî Zþëþ€¼,0/F=½2š‰ë]âxñ0nV €>*ç4Kª³'®Ì”!%˜ÙsžV”Ê Z1€BY›Œh?GêgÄa3_ òL*û¸Ïtî— „„àò‚p0¨¹K2ÆÔnă•‹›hcI6rÿæ«+°êÁÙÕòÕõbðÀaJמJ€]e6z꾘 ½Uð@ÓÅ0û1J0ƒ¤¢‡fÕJêƒëÒ4sR¯ÇàÉD®4…ÐÒT¦žçí Ðý34°˜‰Ñ<ß}xóå ö™ ö»Y(! ßÊ©Žû ™8!RÕj½›<—)Æñ7_©ÎÖX©©þìpTÈá±Adz:ñ?ÀLF³¸ÓLó%‹&ø€{§%s¶$S…é‚Çvú'¬`çÆB3fš¹â˜A?è6Á ^«7´NÊ<ÌÈþ`†xÀ¯È@‘U(.=øv1I8c)}e Q/ ®+bÔfý0zCwÊýO`h©ï~>P š98ª)°v+cˆ£^¬ûÛt¨åà ²£ÇðŸ+w|¨ÈÌ¢ a €¨éÝÖ¾L bfº—úÀÜì~œ:… €‡³g— µ ò°Â ! p}$ÔWÆ[”:@õ?©Á÷¿èóñþ},,€+ÀQmƤø™iÁ¢ßÙôJª Cå·Í2C‚)¬£v- QùÒ3$Àb`" $5ÕFͦ$Ð?îÒY X È€ Ñ‘P]u_@Õ!/¡ =áAChnw &X9Ђ;ðŠ2s/‘-ØAC6·/@KéQzV/°Kpƒ‘ƒ:؃/hYA„áGˆCèƒ.!ÀöN(\´…/°1`S y3Ø‚?‘…€…W‘K`¨„ÄÃc†1†¶´…k؆oH….¡4E‡0a‡ŠE6@`þK`@ð…3ÈC@à†0ˆšSr-C°G/øY¸¸ˆyÑr(@ ‡0áG`ƒ&€GÀ“‡…øC‰.‘…,`4°È“§(‰.áŠKÁƒEø¶ˆ|@†-‘Œá„/`Œ¨½ˆ¿1 ‰ñ¯‹|è?ÎxD˜,ÐÕx×ølø?1Žvæg¨‰K‹|‘ŽV±Ž.ÑŽN1ŽÑ±=ãhDèåÈx䋨è_í?CÅF€î?RðDÎG{©O¢ßHmçIfñN”Z¼ðI`ÆQŽîLPŸZ¶µ[©óXñUmïZ^¡gÃÑ^•ôb¬g¼Ù_Žâ_‡ê`ó`{õoñhkÛkœ®uÊãl•·vÃìlŽÁv½ôm‡özËw¶Ów°òvyÜy©åy£¹ƒÑø†õ{•ó„†ù“ö‰£Ä“×ΔÑ×”Êô‘“ß•Äú¡ ð—¶ø˜°Ï¢Þöž¡Ø¤×û¯ñ§Äù§½÷¬®ý½ÙµåâµÞê¶×ò¶Ñøº¼ú¸ËþÍãÆëúÈÉÿÜûÈ×ûÖ×íÙòõÙìýÚåüãäöëøþëòþñòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù ÿ,xµþ H° ÁƒÌc§¡œ0ÃTBˆ†‹_„飰£Ç CìӰᙈ[*y±¥Ë—05(‘#²¦M„%í<Œ¨DeÌŸ@ƒþÔÈñ¦Qä¬XB¨Ó§PŸÎ@’äfuÝÎV¤üþ™€Y!¬••H6«B)ê­ 0—ykàéA×é¥í’N5(jÂN ” Q˜È_tmP Xƒ\þÔ(ÿ©€S1À(³vJ蔡ǧSÄùpÆQÝ6çQ ª°˜zÕ]= 2T . “ÔVÿ„õ‚|©çéOÄéöÏQ•ݵK®‚ ”þ®±½×mÜê= pUtÆà–N]»by$ Ü=GpUÙ·àÛ@9î·^æÝøÒ€„£\mL!äŒQƒøºãNÛ·ÀI¥­Ó(PîêZÌ1çuHôKsøêÀ"0A·ï» ¬^‘ (Þ-©ÀLq Ü<ÌŒ4pTÐ2ÃÆÇ-FÆþj@xø. ,*›€©g: Óce•W^õ<¢“2¨•ƈ0Êi €g2L!e‡M V ¸€ˆi,œè1E£`2Y«D@áœÖrhOD1ÂH;%•"¦µ‚À)“œê"”átq `w)ª·%¯HÊ BS§e¹Ê° FˆH IýÌ Ý*ÓÌ0 Æ ÅT2à‡´FJc™ikß*ñÕ*W­â倚3!UäË@Ø©‚¤qÔÀºP#<Ì“žˆª]U ᱃-€À`´deÖ0áH5`… ¾«µ*=þŒC ’Øù€¶V?SÃOß5¨(&¥{ Œ@ +W Àa·â2 ÜÚêE Æ””傱Z ‚(=maRÔHi y—8/„87/æé. 4p‚ðŠ‹eLscžHT zÔXÞƒü¥0òæ¨:ëØý /£ÌlKh¯@À V}B 6+©ã.³QŒzf°ZõP8R©¹¬`ê_ÁH ¸ÕÀ&,.`×ZR ¥sR¬Õÿ©ä… ‰c+\-$Õ¬0 €?æœ7Åi~)Ë ù˜F>N3|JWq¸­±"``¦­íKæ°€QYÎ Zþëþ€¼,0/F=½2š‰ë]âxñ0nV €>*ç4Kª³'®Ì”¡˜YsžV”Ê Z1øAY›Œh?GêgÄa3_ òL*û¸Ïtî—„„àò‚k8¨¹K2ÆÔnă•‹›hcI6rÿæ«°êÁÙÕòÕõbðÀaJמ9€]e6zê¾tá½Uð@ÓÅ0û19肤¢‡fÕJêƒëÒ4sR¯ÇàÉD®4…ÐÒT¦žçíËÐý33°˜‰Q<ß}xó ö™ö»Yä@ ßÊ©Žû ™8!RՂ½›<—)Æñ7_„©ÎÖX©yþêpTÈláqAdz:ñ?`LF³¸ÓLó%‹`{§%s¶$S…‰‚Çvú' À`çÆB3fš¹âtA?èÖÀ ^+7´NÊ<ÌÈþÐ…À¯ˆ@‘U(®=øv1;8c)}E Q/ ®+bÔfý0rCwÊýO)`h©ï~>P Èš98ª)°v+cˆ£^¬ûÛs¨åà ²£ÇðŸ+w|¨ÈÌ¢ a €¨éÝÖ¾E bfº—úÀÜì~œ:…€‡³g— µ ô°ÂØ  Tp}$ÔWÆ[Ô&@õ?‘Á÷¿èóñþ},,€+@QmƤø™ A¢ßÙôJJ Cå·Í2“),£v- QùÒ3^  $5ÕFͦÐ?îÒY X È€ Ñ‘P]uU@Õ!/¡ =áAChnw &XIЂRðŠ2s/a-ÈAC6·20w0éQzVñ2pwpƒ‘ƒ:؃/hYA„ñGˆCèƒ.!ÀöN(\´…2 >`S y3Ø‚?‘…€…W‘w`¨„ÄÃc†1†¶´…k؆oH….¡4E‡0a‡ŠE6cÐþwÐcð…3˜i0cà†0ˆšSr-áipt0/øY(¸ˆyÑr(c ‡0qt`ƒðt“‡…øC‰.‘…+ÐC°È“§(‰.áŠw`ÁƒEø¶ˆ|@†-‘Œá„2ÐŒ¨½ˆ¿> ‰!¯‹|è?ÎxD˜+ÐÕx×ølø?1Žvæg¨‰w‹|‘ŽV±Ž.ÑŽN1ŽÑ±=ã¨DxåÈx䋨èà]i•eÑ’(òîÁ7.™ePw”*s‰îV‚Qy !`—*ò"å”Wÿ‡"û4'ˆ˜Q•4Œ‡ù˜Õ™’¹”Y™ž$¡™»$HÈ™ã\ ¹ln5š¤)š¦‰qŸ™šYš¬iZ¥øš†¡,²)µy—%vU¾©*Q…è—B;@Ñ6å±9á¿ œÁyÚ”›1ñÑ›a"  qzÌùßéœÏÙI‘'ç=g œàÙžîÙž;tktreectrl-2.4.1/demos/pics/mac-collapse.gif0000644000076400010400000000042307577521110021313 0ustar TimAdministratorsGIF89a²3f™Ìÿ333!ù,‚ff̈ˆˆ»»»™™ÿÌÌÿÿÿÿ%hºÜþ0ÊI¸8Šÿ aH>€™Žð®1\ÑU®ïR!þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/mac-expand.gif0000644000076400010400000000042507577521110020772 0ustar TimAdministratorsGIF89a²3f™Ìÿ333!ù,‚ff̈ˆˆ»»»™™ÿÌÌÿÿÿÿ'hºÜþPèÀ¤ ”‹5á‘÷uA`U¢Â¬~mÔŽòîû !þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/outlook-arrow.gif0000644000076400010400000000016110234533000021557 0ustar TimAdministratorsGIF89a ³¿¿¿ÿÿÿ!ù, 0ˆj {3ئ…Ø—ømª÷Iî{Êf†\;tktreectrl-2.4.1/demos/pics/outlook-clip.gif0000644000076400010400000000016110234532776021377 0ustar TimAdministratorsGIF89a ³¿¿¿ÿÿÿ!ù, 0HAåXX@^ÇycFRfZ®èYváy‚XfÁR;tktreectrl-2.4.1/demos/pics/outlook-deleted.gif0000644000076400010400000000021207577521110022047 0ustar TimAdministratorsGIF89a"!ù ,‚¿¿¿ÿÿÿOxºÜK"%d1“1$D„#Å aw#KrÀ)ŠmÃÛ©ÚµÙ|‡‡N>E0¹„ä‚ÊÇÆX²ŠÈÄ;aDß›cÝH;tktreectrl-2.4.1/demos/pics/outlook-draft.gif0000644000076400010400000000020607577521110021544 0ustar TimAdministratorsGIF89a"!ù ,‚ÿÿ¿¿¿ÿÿÿKxºÜW0‚Ig¼Œ¸ÁµEàmW–Ó`vç@@‚ffåë!oqy‚‚ÎÔËn‚Ž×IB8V*MuˆùTAÝÏ,ì(›ÏŠ;tktreectrl-2.4.1/demos/pics/outlook-folder.gif0000644000076400010400000000020507577521110021716 0ustar TimAdministratorsGIF89a"!ù ,‚ÿÿ¿¿¿ÿÿÿJxºÜG0J¤Ö¹3¦iÛ ˜C÷ Pà¾.°§à~@PNØCÙvA$¡ƒº)wLSR7ù€²¬g9H‰.˜ïÅA.› ;tktreectrl-2.4.1/demos/pics/outlook-group.gif0000644000076400010400000000022007577521110021574 0ustar TimAdministratorsGIF89a"!ù ,‚ÿÿÿ¿¿¿ÿÿÿUhº Àp9õZ†”Ji-š6 Æ£)!X k™šÁø© ë,P2Ábd“¨„ŠÚÀ% ! dz¤yn œR¡0%`!ÒŒX“]¼èoD°moˇ|’;tktreectrl-2.4.1/demos/pics/outlook-inbox.gif0000644000076400010400000000020507577521110021562 0ustar TimAdministratorsGIF89a"!ù ,‚ÿÿ¿¿¿ÿÿÿJxºÜW0$|’Â*ñä›õhÖÔTªR* \À …Î<9ÝgΛ¯'=zo”Õ³ûÖÎýºõîº/‚ÿúøó•Ñ«ßL~}h÷íK“†O¿ímºÓ™aÂÿ°ìu)¥g $À0  -”P‚ 4xPƒ ¶SC "¨Y…=Gb-€p /x€L TðB TPÁ:@€Â¸ðA .ºPÂr2a¨2Ü0æA:èà‚-% pÀ9 i@ÿLn Ã ä`À,Zp#O:UMá7_^| $ 2\P’Læ@ààf’G2y¤Ä ž3"(X‚=[êdá2’ÙYË *$yhà&m²Ùfà“l°Á 5xð áˆà‚Š(„ðÂ{ö)T€|ö…Ž ¬à§LFiE¾.ʨ›“ °À’9±¤‰? ¹ ˜z£ŽOý)«"ˆj©“¤É¤ŠFê+›¿þŠC¹è¶i„’⮵²TÄœ¥êK÷i™W /æé»9 @è&¬°ÂçòÚ+“ê*å.ˆ ÿ YR[ÓæÅÅŒ,)烯¿¢¬0¯ç.L²óæó¹8\ð¤@pã ­i|S<=ó%ƒ0y2¯¿"Œ°Ëì²äp :¨¸í™6'©C ùò·/Púu¼ϵ”ðÁ'®¨h› £ŒtÂH/p’Mz{‹õn œ| ˜¿[8Z-|`·BÛ¬›å¶œ®Â8ŒnN®(¥š1k­bÑ“£ £×~‰êB%ªÈ€”‘:^.›Œ§ÜæìæÂˆ€å¹¾‰w·‰fÑÔРùŠ®œ¾pYH¢©!l޵¤N—[@ —ük½öùdšÊd;Ü:jÿÔWЂ‚û¼±×ö¡SC(L´:øÐúÑ*“Lrìæûk§!Øö65J=éI,êBp« à@7X‰ñxD¾äëG·b’FÖ°^É­GKíæ­ oQûž Y$0Rª,¡¾ÑQ/‚¸G¥ƒ½iÄj”õ‚•ƒ$€›SaÕnw;À^/Ü€>€Œõ)8{¹ L°H IŒs]ÂvUêÉ­e:àÀ 8ð°áÛçÁ1|òÓ 2ÐŒ/]ÑŠcyP€,5íƒ £YÊÐu®p@ˆ¤ü$ pÐ]‚Iò°ÿb6ØÓ k¸1·0c†$°Xh€,‘…‘il{\ã°‚H`è€$ˆIäà{O _'›ç;”È¢$åϦ²ud.8Ý \€Ð@"˜’ )þ­ÌdŒRÊpËØ’`cóLèK"uo¬ï6„\ipëñ#T.ƒ"… \˜£\œìw¹Eåïu‘#ÃBÀà—!àA@XH1B"©6¾4ÏFçÐçxÄV­“”€SÝJ|°¤–¶IR†¤ÞÂt¥ÐD&‰À'PIŒÎ‘—ntcÑXd/¼à¨¨˜2Y³\`Xû–Œ)y©)¦SÿÍÕAI6)7ýr‹‚Q´8 "m >`Ò“Bæ­49 0•0%‚Üi‚QII L¿À$V»jf£Iɪád$²Z1t±Éd#+”,‡¿–ÑîdÄ¢›Ô„Ó¡íš¡Û×VÞAƒÍ¥4w4Mm» Û®·M¯{"ƒÔÛ)H륯ÔßÊtU¬,©j¦’ÀQ/‚¥mŸ‚GØÃn-‰X¬¢ÚÐy +³š©`'U°vAÖWŒ•©Ê ë®_ê jPÔi^ ƒŽ+µ@Û“ØÖoѱÜ-¬ÄX—¬•uÊ‚)ëx{?ÞÆN‘óâî2¤Þê8nÿ>›R ?¥m<½UØßs/Ê2¬ÈÒt7g±hA’Zë+%è –¦¿¢ž›Œ3µ2WE;æ H¼ºä|û±A v¼‚£¾@~¤ÌJ¥Ë9yª…4ày)õË$~ïn8 ½EÕdµ«›À‚ia¥G{ÍQ˜XªŒ‹ÏŸ]¢B$A5ŠKÈÏ^U“§ö¶'€Ó¦)j}Æ·îÖB"`rÃ*Ü3WŒÚíÖ¶¿TBÜlT5^ÎlFJ:"” £ÞRÂup1™Ií-j¨öëZ¨ƒ'&úИ¬è%1©¢ U`~]ñ¤¨:ædõWϧ“ßéLƒiù'ÇPnŒdÿP÷¨…ä‘EÍÀ9æù€'ì!¿§"$ÔñŽ“¦¶ƒG7"jTfÒ˜Yˆ-P;Œ+…ç‘bÉB-° J£:6@Ø&j¨´×„Iò’³MÜöüËíK¶‘Gœh$#é€]2Ô¯èž ½='U :¨#/p™m/XÁ¥÷ao?¥Dx€ïJ ¾hÑ™Î|¤:ÛX"ÔZ?p§½„é`Šv2’Lº&nK]Nœ’/¬ã·ó Eξðš‚0öT‚LèZ>F‰¨ž„Qli·¼R‚XÕy¿¤—>ŠN¼¡w—€ôÞZÖÒœæÌ%¨% ÿ 8}mö 0éiC˜@[GP*T¡áµyUì›ÍÇÆ‡èDuHÖ.úäÜàð¬µÈD;—€ÿ{ìßws¦ ·Ÿý§WP&´=ût9vA¨<¡P äÊÃâ]m‚ AõÓÅUG þÆŸ¹Êm<1ݽú ¨\ôÁèé|w$ ’çŸø-#€Í2Þ¡´èË$~ñ³ýþl§½C#\ l]5àQjôeRh³cR\ýâ#A0p1àT4 v%@% >°÷šveTEÆKHÄzá—-"à~$!$§r;+$—"@""~Ø”ÿ-¡”-ù²u£‡øwæÄ{øÖ!!G%JÑgW¶€1(¤Á#És€]‹RUL‚„~1î¸c2€6APp!kÄ{•Ç3&Ç€ÒyR £Ç«Ð3<óÙBzl'm—‚©b-µ€ yéC6Í –‘ 7P$Ñ1nrPe9Jå^Ì«R NX‡Ik”K—–>ȆÑ×%ÑN‡p|8‡ €}$  €_‚ ^R„$@<-°°4/…02ÅH€à °5ËÁG›‡¡hÖ×Lï° ¦‡K@\Ã|`w†oè@!ÙB!`$ÿ4—a |„1ë"°*ðEƒ2eÔX.óA={t vu^—f)¨hcO‰ûv6+Ø„ I‘NxWéSAþb‰×Â3¡·¡ŒlH ÍÐOàR5àÂ]`–H¿Ò‘‘B„@"vt+PI2"R±á'oXR$ŠO÷v'—x'uR–2Í#Ç@ÜÒ\)–+9V^&)ØS!ï£DwW1²r¦¸|UÑc™—?Æ>âH.wC£h à õr+ÎÕ$/@1P~µMZv7ý5ÑÃUj6):p~¤= ”=9Ö^RHÎØÛH˜0¡}$˜,¹ˆ ÿr¦ìbA$.Ä((%'vóg¶E=e´báòKÄs:€Bõqˆ,7:˜W“U™•‰˜„•É/-0*€—@Òb«µ! ”GÐa55KÒ-’R.”ó$ `•BÑTIáG¦‚iÆ%;2˜1Ù—·˜¬™#$PÓ„QV5°ÃU0u'$œÉ’_ï‰YÀÈžS&5ZÖgU³^+. ?fl²é’aa•5ù7[YU‰vb6HDuQƒYãòKZ¦BÔk_†0&c`B ×-ÜÕ_G°žˆs6}6ù¢ÈLÌt˜2)RÜ9l(ʶaÌu^NSÿ[ ·(F™–”T%)F IºHp^òò¡°§B\)ˆUd‹¥4 ¶›Šæ•©”MK¶MA²£¾42‘SX­æ¥÷‰nR¢__ÖjP¤™5ì‚98à›Ø„>òÈÆ€6y‹â “ÊѢ˴¦˜o^ܲp¶e/ök@ ¦BG0œgú¦Fà_^º£Ü„,Gà@™‹|² —asŠÜ8›¯ Zi•Èõf,pv6lÚã_q9œ SÝ#Zšn4ô9¡¶X¿„^ŠmS6©:ÙbaÈS˜úÒ÷`§Êj˜Ý9“à‰ .‘‡yòwV£ çK°zU° >¦¹ÿI(¬Q©­³­ø©DP#$€ y8ª=B­€R ñ:ŽÀaª±©ü±'6 WEvTÆ\”ª ç_)Õ¥…€p«Až°p²êkjLãº`(&G!:m¶š„©!n¸!úÊ¢Þ9­>qr§â ±bg:eg×BêDáŠI½4¦õbkŸ{@;êWÃY5&ôK˜Ò¯÷qŠŽ¡:ŠˆEðE¥ˆÙµÀcxtˆÿº^/°tltDA¥£Û°е˜d©,4œ –UëJ°ôW¿”e=T®(&%UÓ^ž*²á™§øÐ*£E²Òª¯6pd0d”·²F÷H¦ÇF±vÿ†!Pj< €qtÜÔe]5fôÉMùkÁ™B½v u;‘Oº ójê´)º˜rP+- B`zûåÔ@P/ËP…tðæQ;¹.5óg”©eTEPéj©G€×G:+ ²á%¶Ñ¢Sêv/˜-2`z}'¾áæABA0qNCI ¹aK™÷óž0°›&®Wv^þ…$y©%Ð6¦K‘ת£äŒ§zrKâ!%Kt¦v¡¢\À`{l”Kü¸! èëK1e¦š¤£= hÿ»aÛ°2+Lp¶€?¶Ø ÿ² LŽP»ºD§É¥)75 òGr * ¸ÀpKò×PºIáÓÂÎk^T;º£ìÉIäv«+@-ØH[ÀXJ¯Ö@:úŒG«‰Ù-hzÓ+ò'*7ð(G0»A`{gxešÀÊ£þe«&´‘¬(À™dDŠ;¶.Œ««·´HÀÏÚ€]‚ÃóÀ*›L:ì…­¢ 0ÀiØ'†t˜¡Ò¸gDG´Á¸·Zk~gÈÀ h­V¤nÄçµI@GÔz‰lD˜Ä°C@ "pÉÕ»>ÇsÀR˜ÀI›Æœ ±©[GÇ·wi£'ÿ"˜N—vfKUq‰<¹²ªI¦¹×‘Ô»ÜB@Î˵áÚ΀q@·ÇÃÉÚ¬ùàÉ×;¥ ¬½€átL‡¬øásD½üBä\~‘dÎl„b¤I¯|w =ÐÑ<À<  àÁ‘´t÷L³ ¥µBa£j¯‹ÍJ;ÍÐPºµÉ ú„耈éðy’-l4IjDQÛPQû-þ%L@ÏBÐ=„­}Çt³ÏUq†‡tt+Æ&‹#!%Ðô@ЙW*z‹E{?/œ˜"MÑÝÐv?¸¾ì<€b ×Α4Õµ7mçPBHðgÿÒ‘TKˆ»6G1ÖJkÆÔ\Ƙ¸OPˆ#šÝ#0‰«~Bp{ø—‚k·²´ŒÂnô×Ríwì‡ie"„€MkWØßw†}Ô*‡¥8À;\Ój}½7<ÖaMº}¢¡L 6€Û·Ø¢÷Üà~2{= ×¯|†­çzÈgƒÈ »æTÇÏ”‚"{riN~„‡‚CÃK;ÓÒ¬Ù§;²˜mÀ}ëNÕ‚NL‡?¸v£wum¾Cøw=ÕDˆ ¥8ˆ²íP¢'}ŠÁQ\’ Pyÿü¢y;ÐzŠúÊÃ[9ÃpHz†Ý£7â?Èv|˜)PØ2XÜØkÐÕÂᲉ´(ÁÓûј¹§ ‰¯y§^Hç”]Ówî ¼çANªÈÓ/ƒ® ~DçËŠ§d ¨’-ܲå Üå’Êó±ÞŸÌ*ðJ¥½±X ¯.ªñÝÆ“-êÛKߥͧ.©~‡_™Ù ªÃÎé¾þÉŒîç©úèjÿë;…g}íFËTi›¢Ì%Ÿnìñ½¢ó äW¹Æ,Ê·7 ß­Ní>ŽãšnÃ³Ž·\~Ü·þåçßéÊzñÛè~ŠvnÙòýã3ýî0­®ËŽ‹Oh¥˜—áy[Ö´îè»éÞðB.‚ækŽÉ |ð¢\ºdÓL{ì—íð >ŽFÁ•\BèÉ´ ŒéÖÇëžlÖûNÜnëZ>8ã­ŽòÀ-ìEqÓð½ð0ßðz®ìçx¥|nñ;Ϙ4ì†ší»¾íßí¯ÆG¯í8ìÚóönÀ@þô4Íî2¯îæÎÆM_ÖÌ>ëmñföÐÈñü^ëþ^ôµ(òj¬ÿöJøÆ}¯qïôP¿î8=õî~´5?çx•:Ÿêåz¢/­í¥Êí^nô†ÿ±uººû^î#ÿêŽïòpoºr/ùOùaùãžób­ù’ÞõëâúW:øŒÎõÖ{î’žöÏôyû­?óQûyEêU_ùwûš|ùË¿L<¼|ü`ÖÅ}óÂô<_W~úA“úáž÷*íͯî,õÑOõ´Ÿ‰Õoê§ý|¿òÜÿõâüh $-‚„ƒ†…ˆ†-‹‚ŒŒ…‡‘‘‰‰Ž”“Šƒ•ˆ$„˜”—¤Ÿš©š«‡§Ÿ®¢±—²´©  –¤¥£»¢§“’¿ž°¥µÀ‹ŽÊÿɜʰËǽ¸Ò´ÌÖ«ž˜Ñ™Ô؊͸ءÒÝ™¨­Á®Ù¯¨æ½Û»îôíºòÅÑíüœÙèñàAÛGœ3o¡äÕ8k1ƒ›¶Y’ø­ÝÄaâô)¼õðV?q_1ŒµÑ;ûécH°â¦ôªL'IØAnÉJÞé ç7’æ.KîbÇ‚óª# p«1yBÔù =_øXZ,öò µ’-N4øóœÔuTü9+(Ø”6Af,·Ñ£Ëu(ë哚VÔ\X»í]¸íCpƒ# ¤‰lÇkByž5{íY[Š‹áÅÈJcP»\ñ>µšìd‘VÊZ·°ÊÃľò›ÔÓ}§õ…ü(f¥š§rþåY"hUÓòž<-\§^Ú;W¶6ú𱩡ðN ³±µÓÌyß¾üõm¾¸Oç.þ7¤S‚Ës7×ú·ºîrZ©ß·ÞÔØbïÁteàÉ'[Ú¸•Ùy›õ,g±³TrÐq$ßVÎ]`ÒeçÚ~£õçÛLbÙ„˜O‘9g Cã%ø›‚ŠQçTІ ;tktreectrl-2.4.1/demos/pics/small-dll.gif0000644000076400010400000000046707577521110020644 0ustar TimAdministratorsGIF89a²3f™Ìÿ333!ù,‚ÿÿÿ¿¿¿ÿÿÿI8²ÜóP˜IgðÉJ‹ÁG$Š©MAp…ªLáVqÀòZ² öùåVIOð:ÎF¢Á¹ý¦ATꤥF¿à¨¬D.«!þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/small-exe.gif0000644000076400010400000000016307577521106020650 0ustar TimAdministratorsGIF89a"!ù ,‚¿¿¿¿ÿÿÿ8xºÜ0Ê ‡½ø†ø`øm(Š’år!Ï´ÌÖ8qçôÎÛ°ßÌ÷#òH®`Él:Žè";tktreectrl-2.4.1/demos/pics/small-file.gif0000644000076400010400000000052207577521106021005 0ustar TimAdministratorsGIF89a²3f™Ìÿ333!ù,ƒÿèÿÿÿ¿¿¿ÿÿÿLˆI+¹X Í÷Ø¥uÜ€É,ª¥+ÂqZ¬¬'K[Q¿qØiÄV®ø OÃ9›*­/–ÀTL¾hTÍ+:˜ÏèðuͺD!þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/small-folder.gif0000644000076400010400000000046307577521106021345 0ustar TimAdministratorsGIF89a²3f™Ìÿ333!ù,‚ÿÏÏ`ÿÏÿÿÿÿÏïïïEºÜ+÷Ž1¥ˆéÄøàEŠpèU “™½pA°Ë8mß„¬c°žpÕq³âk(LÖ L$Áé YA€vËåR¾`p!þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/small-txt.gif0000644000076400010400000000045607577521104020711 0ustar TimAdministratorsGIF89a²3f™Ìÿ333!ù,‚ÿ¿¿¿ÿÿÿ@( ÄÞ* H½0Ödz¨D(Š (Qž à0ª©€i¸Î¡«Ã÷W“2_kg Òj=ÐÎUdý’¿æl@­Z{“å2’!þ€This animated GIF file was constructed using Ulead GIF Animator Lite, visit us at http://www.ulead.com to find out more.USSPCMT!ÿ PIANYGIF2.0Image;tktreectrl-2.4.1/demos/pics/unchecked.gif0000644000076400010400000000011007577521110020675 0ustar TimAdministratorsGIF89a , ßßßÿÿÿ!Œ6í/´ÖȬÆS_é}Y8pd ’¦š†˜ÇrtZ;tktreectrl-2.4.1/demos/random.tcl0000644000076400010400000002521311573541311017312 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker set RandomN 500 set RandomDepth 5 # # Demo: random N items # namespace eval DemoRandom {} proc DemoRandom::Init {T} { InitPics folder-* small-* set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -itemheight $height -selectmode extended \ -showroot yes -showrootbutton yes -showbuttons yes \ -showlines [ShouldShowLines $T] \ -scrollmargin 16 -xscrolldelay "500 50" -yscrolldelay "500 50" # # Create columns # $T column create -expand yes -weight 4 -text Item -itembackground {#e0e8f0 {}} \ -tags colItem $T column create -text Parent -justify center -itembackground {gray90 {}} \ -uniform a -expand yes -tags colParent $T column create -text Depth -justify center -itembackground {linen {}} \ -uniform a -expand yes -tags colDepth $T configure -treecolumn colItem # # Create elements # $T element create elemImgFolder image -image {folder-open {open} folder-closed {}} $T element create elemImgFile image -image small-file $T element create elemTxtName text -wrap none \ -fill [list $::SystemHighlightText {selected focus}] $T element create elemTxtCount text -fill blue $T element create elemTxtAny text $T element create elemRectSel rect -showfocus yes \ -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] # # Create styles using the elements # set S [$T style create styFolder] $T style elements $S {elemRectSel elemImgFolder elemTxtName elemTxtCount} $T style layout $S elemImgFolder -padx {0 4} -expand ns $T style layout $S elemTxtName -minwidth 12 -padx {0 4} -expand ns -squeeze x $T style layout $S elemTxtCount -padx {0 6} -expand ns $T style layout $S elemRectSel -union [list elemTxtName] -iexpand ns -ipadx 2 set S [$T style create styFile] $T style elements $S {elemRectSel elemImgFile elemTxtName} $T style layout $S elemImgFile -padx {0 4} -expand ns $T style layout $S elemTxtName -minwidth 12 -padx {0 4} -expand ns -squeeze x $T style layout $S elemRectSel -union [list elemTxtName] -iexpand ns -ipadx 2 set S [$T style create styAny] $T style elements $S {elemTxtAny} $T style layout $S elemTxtAny -padx 6 -expand ns TreeCtrl::SetSensitive $T { {colItem styFolder elemRectSel elemImgFolder elemTxtName} {colItem styFile elemRectSel elemImgFile elemTxtName} } TreeCtrl::SetDragImage $T { {colItem styFolder elemImgFolder elemTxtName} {colItem styFile elemImgFile elemTxtName} } # # Create items and assign styles # TimerStart $T item configure root -button auto set items [$T item create -count [expr {$::RandomN - 1}] -button auto] set added root foreach itemi $items { set j [expr {int(rand() * [llength $added])}] set itemj [lindex $added $j] if {[$T depth $itemj] < $::RandomDepth - 1} { lappend added $itemi } if {rand() * 2 > 1} { $T item collapse $itemi } if {rand() * 2 > 1} { $T item lastchild $itemj $itemi } else { $T item firstchild $itemj $itemi } } puts "created $::RandomN-1 items in [TimerStop] seconds" TimerStart lappend items [$T item id root] foreach item $items { set numChildren [$T item numchildren $item] if {$numChildren} { $T item style set $item colItem styFolder colParent styAny colDepth styAny $T item element configure $item \ colItem elemTxtName -text "Item $item" + elemTxtCount -text "($numChildren)" , \ colParent elemTxtAny -text "[$T item parent $item]" , \ colDepth elemTxtAny -text "[$T depth $item]" } else { $T item style set $item colItem styFile colParent styAny colDepth styAny $T item element configure $item \ colItem elemTxtName -text "Item $item" , \ colParent elemTxtAny -text "[$T item parent $item]" , \ colDepth elemTxtAny -text "[$T depth $item]" } } puts "configured $::RandomN items in [TimerStop] seconds" bind DemoRandom { TreeCtrl::DoubleButton1 %W %x %y break } bind DemoRandom { set TreeCtrl::Priv(selectMode) toggle DemoRandom::Button1 %W %x %y break } bind DemoRandom { set TreeCtrl::Priv(selectMode) add DemoRandom::Button1 %W %x %y break } bind DemoRandom { set TreeCtrl::Priv(selectMode) set DemoRandom::Button1 %W %x %y break } bind DemoRandom { DemoRandom::Motion1 %W %x %y break } bind DemoRandom { DemoRandom::Release1 %W %x %y break } bindtags $T [list $T DemoRandom TreeCtrl [winfo toplevel $T] all] return } proc DemoRandom::Button1 {T x y} { variable ::TreeCtrl::Priv focus $T set id [$T identify $x $y] set Priv(buttonMode) "" # Click outside any item if {$id eq ""} { $T selection clear # Click in header } elseif {[lindex $id 0] eq "header"} { TreeCtrl::ButtonPress1 $T $x $y # Click in item } else { lassign $id where item arg1 arg2 arg3 arg4 switch $arg1 { button { TreeCtrl::ButtonPress1 $T $x $y } line { TreeCtrl::ButtonPress1 $T $x $y } column { if {![TreeCtrl::IsSensitive $T $x $y]} { $T selection clear return } set Priv(drag,motion) 0 set Priv(drag,click,x) $x set Priv(drag,click,y) $y set Priv(drag,x) [$T canvasx $x] set Priv(drag,y) [$T canvasy $y] set Priv(drop) "" if {$Priv(selectMode) eq "add"} { TreeCtrl::BeginExtend $T $item } elseif {$Priv(selectMode) eq "toggle"} { TreeCtrl::BeginToggle $T $item } elseif {![$T selection includes $item]} { TreeCtrl::BeginSelect $T $item } $T activate $item if {[$T selection includes $item]} { set Priv(buttonMode) drag } } } } return } proc DemoRandom::Motion1 {T x y} { variable ::TreeCtrl::Priv if {![info exists Priv(buttonMode)]} return switch $Priv(buttonMode) { "drag" { set Priv(autoscan,command,$T) {DemoRandom::Motion %T %x %y} TreeCtrl::AutoScanCheck $T $x $y Motion $T $x $y } default { TreeCtrl::Motion1 $T $x $y } } return } proc DemoRandom::Motion {T x y} { variable ::TreeCtrl::Priv switch $Priv(buttonMode) { "drag" { if {!$Priv(drag,motion)} { # Detect initial mouse movement if {(abs($x - $Priv(drag,click,x)) <= 4) && (abs($y - $Priv(drag,click,y)) <= 4)} return set Priv(selection) [$T selection get] set Priv(drop) "" $T dragimage clear # For each selected item, add 2nd and 3rd elements of # column "item" to the dragimage foreach I $Priv(selection) { foreach list $Priv(dragimage,$T) { set C [lindex $list 0] set S [lindex $list 1] if {[$T item style set $I $C] eq $S} { eval $T dragimage add $I $C [lrange $list 2 end] } } } set Priv(drag,motion) 1 } # Find the item under the cursor set cursor X_cursor set drop "" set id [$T identify $x $y] if {[TreeCtrl::IsSensitive $T $x $y]} { set item [lindex $id 1] # If the item is not in the pre-drag selection # (i.e. not being dragged) see if we can drop on it if {[lsearch -exact $Priv(selection) $item] == -1} { set drop $item # We can drop if dragged item isn't an ancestor foreach item2 $Priv(selection) { if {[$T item isancestor $item2 $item]} { set drop "" break } } if {$drop ne ""} { scan [$T item bbox $drop] "%d %d %d %d" x1 y1 x2 y2 if {$y < $y1 + 3} { set cursor top_side set Priv(drop,pos) prevsibling } elseif {$y >= $y2 - 3} { set cursor bottom_side set Priv(drop,pos) nextsibling } else { set cursor "" set Priv(drop,pos) lastchild } } } } if {[$T cget -cursor] ne $cursor} { $T configure -cursor $cursor } # Select the item under the cursor (if any) and deselect # the previous drop-item (if any) $T selection modify $drop $Priv(drop) set Priv(drop) $drop # Show the dragimage in its new position set x [expr {[$T canvasx $x] - $Priv(drag,x)}] set y [expr {[$T canvasy $y] - $Priv(drag,y)}] $T dragimage offset $x $y $T dragimage configure -visible yes } default { TreeCtrl::Motion1 $T $x $y } } return } proc DemoRandom::Release1 {T x y} { variable ::TreeCtrl::Priv if {![info exists Priv(buttonMode)]} return switch $Priv(buttonMode) { "drag" { TreeCtrl::AutoScanCancel $T $T dragimage configure -visible no $T selection modify {} $Priv(drop) $T configure -cursor "" if {$Priv(drop) ne ""} { Drop $T $Priv(drop) $Priv(selection) $Priv(drop,pos) } unset Priv(buttonMode) } default { TreeCtrl::Release1 $T $x $y } } return } proc DemoRandom::Drop {T target source pos} { set parentList {} switch -- $pos { lastchild { set parent $target } prevsibling { set parent [$T item parent $target] } nextsibling { set parent [$T item parent $target] } } foreach item $source { # Ignore any item whose ancestor is also selected set ignore 0 foreach ancestor [$T item ancestors $item] { if {[lsearch -exact $source $ancestor] != -1} { set ignore 1 break } } if {$ignore} continue # Update the old parent of this moved item later if {[lsearch -exact $parentList $item] == -1} { lappend parentList [$T item parent $item] } # Add to target $T item $pos $target $item # Update text: parent $T item element configure $item colParent elemTxtAny -text $parent # Update text: depth $T item element configure $item colDepth elemTxtAny -text [$T depth $item] # Recursively update text: depth foreach item [$T item descendants $item] { $T item element configure $item colDepth elemTxtAny -text [$T depth $item] } } # Update items that lost some children foreach item $parentList { set numChildren [$T item numchildren $item] if {$numChildren == 0} { $T item style map $item colItem styFile {elemTxtName elemTxtName} } else { $T item element configure $item colItem elemTxtCount -text "($numChildren)" } } # Update the target that gained some children if {[$T item style set $parent colItem] ne "styFolder"} { $T item style map $parent colItem styFolder {elemTxtName elemTxtName} } set numChildren [$T item numchildren $parent] $T item element configure $parent colItem elemTxtCount -text "($numChildren)" return } # # Demo: random N items, button images # namespace eval DemoRandom2 { proc Init {T} { DemoRandom::Init2 $T } } proc DemoRandom::Init2 {T} { Init $T InitPics mac-* $T configure -buttonimage {mac-collapse open mac-expand {}} \ -showlines no return } tktreectrl-2.4.1/demos/span.tcl0000644000076400010400000000577411573541470017013 0ustar TimAdministrators# Copyright (c) 2006-2011 Tim Baker # # Demo: Column span # namespace eval DemoSpan {} proc DemoSpan::Init {T} { variable Priv set width [font measure DemoFont "Span 1"] incr width 4 # # Configure the treectrl widget # $T configure \ -showbuttons no \ -showlines no \ -showroot no \ -xscrollincrement $width # # Create columns # for {set i 0} {$i < 100} {incr i} { $T column create -itemjustify left -justify center -text "$i" \ -tags C$i } # # Create elements # $T item state define mouseover for {set i 1} {$i <= 20} {incr i} { set color gray[expr {50 + $i * 2}] $T element create e$i rect -width [expr {$i * $width}] -height 20 \ -fill [list white mouseover $color {}] -outlinewidth 1 \ -outline gray70 if {[winfo depth .] >= 16} { lassign [winfo rgb . $color] r g b # Can't use min() on 8.4 set r [expr {int($r * 1.3)}] if {$r > 65535} { set r 65535 } set g [expr {int($g * 1.3)}] if {$g > 65535} { set g 65535 } set b [expr {int($b * 1.3)}] if {$b > 65535} { set b 65535 } #set r [expr {int(min(65535,$r * 1.3))}] #set g [expr {int(min(65535,$g * 1.3))}] #set b [expr {int(min(65535,$b * 1.3))}] set color2 [format "#%04x%04x%04x" $r $g $b] $T gradient create g$i -steps 16 \ -stops [list [list 0.0 $color] [list 0.5 $color] [list 1.0 $color2]] # -stops [list [list 0.0 $color] [list 1.0 $color2]] $T element configure e$i -fill {white mouseover} \ -fill [list white mouseover g$i {}] } $T element create t$i text -text "Span $i" -lines 1 } # # Create styles using the elements # for {set i 1} {$i <= 20} {incr i} { set S [$T style create s$i] $T style elements $S [list e$i t$i] $T style layout $S e$i -detach yes -iexpand x -squeeze x $T style layout $S t$i -expand ns -padx 2 -squeeze x } # # Create items and assign styles # foreach I [$T item create -count 100 -parent root] { for {set i 0} {$i < [$T column count]} {} { set span [expr {int(rand() * 20) + 1}] if {$span > [$T column count] - $i} { set span [expr {[$T column count] - $i}] } $T item style set $I C$i s$span $T item span $I C$i $span incr i $span } } bind DemoSpan { DemoSpan::Motion %W %x %y } set Priv(prev) "" bindtags $T [list $T DemoSpan TreeCtrl [winfo toplevel $T] all] return } proc DemoSpan::Motion {w x y} { variable Priv set id [$w identify $x $y] if {$id eq ""} { } elseif {[lindex $id 0] eq "header"} { } elseif {[lindex $id 0] eq "item"} { set item [lindex $id 1] set column [lindex $id 3] set curr [list $item $column] if {$curr ne $Priv(prev)} { if {$Priv(prev) ne ""} { eval $w item state forcolumn $Priv(prev) !mouseover } $w item state forcolumn $item $column mouseover set Priv(prev) $curr } return } if {$Priv(prev) ne ""} { eval $w item state forcolumn $Priv(prev) !mouseover set Priv(prev) "" } return } tktreectrl-2.4.1/demos/style-editor.tcl0000644000076400010400000006144411573514113020464 0ustar TimAdministrators# Copyright (c) 2005-2011 Tim Baker namespace eval StyleEditor { variable Info array unset Info } proc StyleEditor::Info {info args} { variable Info if {[llength $args]} { set Info($info) [lindex $args 0] } return $Info($info) } proc StyleEditor::Init {Tdemo} { set w .styleEditor toplevel $w wm title $w "TkTreeCtrl Style Editor" Info Tdemo $Tdemo panedwindow $w.pwH -orient horizontal -borderwidth 0 -sashwidth 6 panedwindow $w.pwH.pwV -orient vertical -borderwidth 0 -sashwidth 6 TreePlusScrollbarsInAFrame $w.pwH.pwV.styleList 1 1 set T $w.pwH.pwV.styleList.t $T configure -showbuttons no -showlines no -showroot no -width 150 -height 200 $T column create -text "Styles" -expand yes -button no -tags C0 $T configure -treecolumn C0 $T notify bind $T { StyleEditor::SelectStyle } Info styleList $T TreePlusScrollbarsInAFrame $w.pwH.pwV.elementList 1 1 set T $w.pwH.pwV.elementList.t $T configure -showbuttons no -showlines no -showroot no -width 150 -height 200 $T column create -text "Elements" -expand yes -button no -tags C0 $T configure -treecolumn C0 $T notify bind $T { StyleEditor::SelectElement } Info elementList $T $w.pwH.pwV add $w.pwH.pwV.styleList $w.pwH.pwV.elementList set fRight [panedwindow $w.pwH.pwV2 -orient vertical -sashwidth 6] if {[Platform macosx]} { $fRight configure -width 500 } # # Property editor # TreePlusScrollbarsInAFrame $fRight.propertyList 1 1 set T $fRight.propertyList.t $T configure -showbuttons no -showlines no -showroot no if {[Platform macosx]} { $T configure -height 300 } $T column create -text "Property" -expand yes -button no -tags {C0 property} $T column create -text "Value" -expand yes -button no -tags {C1 value} $T configure -treecolumn property $T notify bind $T { StyleEditor::SelectProperty %S %D } Info propertyList $T # # Style canvas # set fCanvas [frame $fRight.fCanvas -borderwidth 1 -relief sunken] set canvas [canvas $fCanvas.canvas -background white -height 300 \ -scrollregion {0 0 0 0} -borderwidth 0 -highlightthickness 0 \ -xscrollcommand [list sbset $fCanvas.xscroll] \ -yscrollcommand [list sbset $fCanvas.yscroll]] scrollbar $fCanvas.xscroll -orient horizontal \ -command [list $canvas xview] scrollbar $fCanvas.yscroll -orient vertical \ -command [list $canvas yview] # Copy element config info from the selected item in the demo list $Tdemo notify bind StyleEditor { if {[winfo ismapped .styleEditor]} { StyleEditor::StyleToCanvas } } Info canvas $canvas Info selectedStyle "" Info selectedElement "" # # Create some scale controls to test expansion and squeezing # $::scaleCmd $canvas.scaleX \ -orient horizontal -length 300 -from 5 -to 150 \ -command StyleEditor::ScaleX if {!$::tile} {$canvas.scaleX configure -showvalue no} place $canvas.scaleX -rely 1.0 -anchor sw $::scaleCmd $canvas.scaleY \ -orient vertical -length 300 -from 5 -to 150 \ -command StyleEditor::ScaleY if {!$::tile} {$canvas.scaleY configure -showvalue no} place $canvas.scaleY -relx 1.0 -anchor ne $canvas.scaleX set 150 $canvas.scaleY set 150 Info scaleX,widget $canvas.scaleX Info scaleY,widget $canvas.scaleY # Create a new treectrl to copy the states/style/elements into, so I don't # have to worry about column width or item visibility in the demo list set T [treectrl $canvas.t] $T configure -itemheight 0 -minitemheight 0 -showbuttons no -showlines no \ -font [$Tdemo cget -font] $T column create grid rowconfigure $fCanvas 0 -weight 1 grid columnconfigure $fCanvas 0 -weight 1 grid $canvas -row 0 -column 0 -sticky news grid $fCanvas.xscroll -row 1 -column 0 -sticky we grid $fCanvas.yscroll -row 0 -column 1 -sticky ns $w.pwH.pwV2 add $fRight.propertyList $fCanvas $w.pwH add $w.pwH.pwV $w.pwH.pwV2 grid rowconfigure $w 0 -weight 1 grid columnconfigure $w 0 -weight 1 grid $w.pwH -row 0 -column 0 -sticky news wm protocol $w WM_DELETE_WINDOW "ToggleStyleEditorWindow" if {[Platform macosx macintosh]} { wm geometry $w +6+30 } else { wm geometry $w -0+0 } return } proc StyleEditor::SetListOfStyles {} { set T [Info styleList] set Tdemo [Info Tdemo] # Create elements and styles the first time this is called if {[llength [$T style names]] == 0} { $T element create e1 text -fill [list $::SystemHighlightText {selected focus}] $T element create e2 rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ -showfocus yes $T style create s1 $T style elements s1 {e2 e1} $T style layout s1 e2 -union [list e1] -ipadx 2 -ipady 2 -iexpand e $T column configure C0 -itemstyle s1 } # Clear the list $T item delete all # One item for each style in the demo list foreach style [lsort -dictionary [$Tdemo style names]] { set I [$T item create] $T item text $I C0 $style $T item lastchild root $I Info item2style,$I $style } return } proc StyleEditor::SelectStyle {} { set T [Info styleList] set Tdemo [Info Tdemo] set selection [$T selection get] if {![llength $selection]} { [Info elementList] item delete all Info selectedStyle "" StyleToCanvas return } set I [lindex $selection 0] set style [Info item2style,$I] Info selectedStyle $style SetListOfElements $style Info -orient [$Tdemo style cget $style -orient] [Info scaleX,widget] set 150 [Info scaleY,widget] set 150 StyleToCanvas 1 return } proc StyleEditor::SetListOfElements {style} { set T [Info elementList] set Tdemo [Info Tdemo] # Create elements and styles the first time this is called if {[llength [$T style names]] == 0} { $T element create e1 text -fill [list $::SystemHighlightText {selected focus}] $T element create e2 rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \ -showfocus yes $T style create s1 $T style elements s1 {e2 e1} $T style layout s1 e2 -union [list e1] -ipadx 2 -ipady 2 -iexpand e $T column configure C0 -itemstyle s1 } # Clear the list $T item delete all # One item for each element in the style foreach E [$Tdemo style elements $style] { set I [$T item create] $T item text $I C0 "$E ([$Tdemo element type $E])" $T item lastchild root $I Info item2element,$I $E } return } proc StyleEditor::SelectElement {} { set T [Info elementList] set Tdemo [Info Tdemo] set style [Info selectedStyle] set selection [$T selection get] if {![llength $selection]} { Info selectedElement "" SetPropertyList CanvasSelectElement return } set I [lindex $selection 0] set element [Info item2element,$I] Info selectedElement $element SetPropertyList CanvasSelectElement return } proc StyleEditor::SetPropertyList {} { set T [Info propertyList] set Tdemo [Info Tdemo] set style [Info selectedStyle] set element [Info selectedElement] # Create elements and styles the first time this is called if {[llength [$T style names]] == 0} { $T item state define header $T element create e1 text \ -fill [list white header $::SystemHighlightText selected] \ -font [list DemoFontBold header] set headerBG #ACA899 if {[winfo depth $T] >= 16} { $T gradient create G_header -steps 16 \ -stops {{0.0 #ACA899} {0.5 #ACA899} {1.0 #d5d2ca}} set headerBG G_header } $T element create e2 rect \ -fill [list $headerBG header $::SystemHighlight selected] \ -outline black -outlinewidth 1 -open nw -showfocus no $T element create eWindow window set S [$T style create s1] $T style elements $S {e2 e1} $T style layout $S e2 -detach yes -indent no -iexpand xy $T style layout $S e1 -expand ns -padx 4 set S [$T style create sWindow] $T style elements $S {e2 eWindow} $T style layout $S e2 -detach yes -indent no -iexpand xy $T style layout $S eWindow -expand ns -padx {0 1} -pady {0 1} set S [$T style create sHeader] $T style elements $S {e2 e1} $T style layout $S e2 -detach yes -iexpand xy $T style layout $S e1 -expand ns -padx 4 Info editor,pad [MakePadEditor $T] Info editor,expand [MakeExpandEditor $T] Info editor,iexpand [MakeIExpandEditor $T] Info editor,squeeze [MakeSqueezeEditor $T] Info editor,boolean [MakeBooleanEditor $T] Info editor,pixels [MakePixelsEditor $T] Info editor,string [MakeStringEditor $T] update idletasks set height 0 foreach editor {pad expand iexpand squeeze boolean pixels string} { set heightWin [winfo reqheight [Info editor,$editor]] incr heightWin if {$heightWin > $height} { set height $heightWin } } $T configure -font [[Info editor,pad].v1 cget -font] \ -minitemheight $height $T column configure C0 -itemstyle s1 } $T item delete all if {$element eq ""} return foreach {header option} { "Draw and Visible" "" "" -draw "" -visible "Center" "" "" -center "Detach" "" "" -detach "" -indent "Union" "" "" -union "Expand and Squeeze" "" "" -expand "" -iexpand "" -squeeze "Sticky" "" "" -sticky "Padding" "" "" -ipadx "" -ipady "" -padx "" -pady "Height" "" "" -minheight "" -height "" -maxheight "Width" "" "" -minwidth "" -width "" -maxwidth } { set I [$T item create] if {$header ne ""} { $T item style set $I C0 sHeader $T item span $I C0 2 $T item element configure $I C0 e1 -text $header ; # -fill White $T item state set $I header $T item enabled $I false $T item tag add $I header } else { $T item style set $I value s1 $T item text $I property $option value [$Tdemo style layout $style $element $option] } $T item lastchild root $I } $T column configure C0 -width [expr {[$T column neededwidth C0] * 1.0}] return } proc StyleEditor::SelectProperty {select deselect} { set T [Info propertyList] set Tdemo [Info Tdemo] set style [Info selectedStyle] set element [Info selectedElement] if {[llength $deselect] && ($element ne "")} { set I [lindex $deselect 0] if {[$T item tag expr $I !header]} { set option [$T item text $I property] $T item style set $I value s1 $T item text $I value [$Tdemo style layout $style $element $option] } } set selection [$T selection get] if {![llength $selection]} { Info selectedOption "" return } set I [lindex $selection 0] if {[$T item tag expr $I header]} { Info selectedOption "" return } set option [$T item text $I property] Info selectedOption $option $T item style set $I value sWindow switch -- $option { -draw - -visible - -union { $T item element configure $I value eWindow -window [Info editor,string] Info -string [$Tdemo style layout $style $element $option] } -padx - -pady - -ipadx - -ipady { $T item element configure $I value eWindow -window [Info editor,pad] set pad [$Tdemo style layout $style $element $option] if {[llength $pad] == 2} { Info -pad,1 [lindex $pad 0] Info -pad,2 [lindex $pad 1] Info -pad,equal 0 } else { Info -pad,1 $pad Info -pad,2 $pad Info -pad,equal 1 } Info -pad,edit "" } -expand - -sticky { $T item element configure $I value eWindow -window [Info editor,expand] set value [$Tdemo style layout $style $element $option] foreach flag {n s w e} { Info -expand,$flag [expr {[string first $flag $value] != -1}] } } -iexpand { $T item element configure $I value eWindow -window [Info editor,iexpand] set value [$Tdemo style layout $style $element $option] foreach flag {x y n s w e} { Info -iexpand,$flag [expr {[string first $flag $value] != -1}] } } -detach - -indent { $T item element configure $I value eWindow -window [Info editor,boolean] Info -boolean [$Tdemo style layout $style $element $option] } -center - -squeeze { $T item element configure $I value eWindow -window [Info editor,squeeze] set value [$Tdemo style layout $style $element $option] foreach flag {x y} { Info -squeeze,$flag [expr {[string first $flag $value] != -1}] } } -minheight - -height - -maxheight - -minwidth - -width - -maxwidth { $T item element configure $I value eWindow -window [Info editor,pixels] Info -pixels [$Tdemo style layout $style $element $option] if {[Info -pixels] eq ""} { Info -pixels,empty 1 [Info editor,pixels].v1 conf -state disabled } else { Info -pixels,empty 0 [Info editor,pixels].v1 conf -state normal } } } return } proc StyleEditor::MakePadEditor {parent} { set f [frame $parent.editPad -borderwidth 0 -background $::SystemHighlight] spinbox $f.v1 -from 0 -to 100 -width 3 \ -command {StyleEditor::Sync_pad 1} \ -textvariable ::StyleEditor::Info(-pad,1) spinbox $f.v2 -from 0 -to 100 -width 3 \ -command {StyleEditor::Sync_pad 2} \ -textvariable ::StyleEditor::Info(-pad,2) $::checkbuttonCmd $f.cb -text "Equal" \ -command {StyleEditor::Sync_pad_equal} \ -variable ::StyleEditor::Info(-pad,equal) pack $f.v1 -side left -padx {0 10} -pady 0 pack $f.v2 -side left -padx {0 10} -pady 0 pack $f.cb -side left -padx 0 -pady 0 bind $f.v1 { StyleEditor::Sync_pad 1 } bind $f.v2 { StyleEditor::Sync_pad 2 } return $f } proc StyleEditor::MakeExpandEditor {parent} { set f [frame $parent.editExpand -borderwidth 0 -background $::SystemHighlight] foreach flag {w n e s} { $::checkbuttonCmd $f.$flag -text $flag -width 1 \ -variable ::StyleEditor::Info(-expand,$flag) \ -command {StyleEditor::Sync_expand} pack $f.$flag -side left -padx 10 } return $f } proc StyleEditor::MakeIExpandEditor {parent} { set f [frame $parent.editIExpand -borderwidth 0 -background $::SystemHighlight] foreach flag {x y w n e s} { $::checkbuttonCmd $f.$flag -text $flag -width 1 \ -variable ::StyleEditor::Info(-iexpand,$flag) \ -command {StyleEditor::Sync_iexpand} pack $f.$flag -side left -padx 10 } return $f } proc StyleEditor::MakePixelsEditor {parent} { set f [frame $parent.editPixels -borderwidth 0] spinbox $f.v1 -from 0 -to 10000 -width 10 \ -command {StyleEditor::Sync_pixels} \ -textvariable ::StyleEditor::Info(-pixels) \ -validate key -validatecommand {string is integer %P} $::checkbuttonCmd $f.cb -text "Unspecified" \ -command {StyleEditor::Sync_pixels} \ -variable ::StyleEditor::Info(-pixels,empty) pack $f.v1 -side left -padx 0 -pady 0 pack $f.cb -side left -padx 0 -pady 0 bind $f.v1 { StyleEditor::Sync_pixels } return $f } proc StyleEditor::MakeSqueezeEditor {parent} { set f [frame $parent.editSqueeze -borderwidth 0 -background $::SystemHighlight] foreach flag {x y} { $::checkbuttonCmd $f.$flag -text $flag -width 1 \ -variable ::StyleEditor::Info(-squeeze,$flag) \ -command {StyleEditor::Sync_squeeze} pack $f.$flag -side left -padx 10 } return $f } proc StyleEditor::MakeStringEditor {parent} { set f [frame $parent.editString -borderwidth 0] $::entryCmd $f.entry -textvariable ::StyleEditor::Info(-string) bind $f.entry { ::StyleEditor::Sync_string } pack $f.entry -expand yes -fill both return $f } proc StyleEditor::MakeBooleanEditor {parent} { set f [frame $parent.editBoolean -borderwidth 0 -background $::SystemHighlight] foreach value {yes no} { $::radiobuttonCmd $f.$value -text $value \ -variable ::StyleEditor::Info(-boolean) \ -value $value \ -command {StyleEditor::Sync_boolean} pack $f.$value -side left -padx 10 } return $f } proc StyleEditor::Sync_orient {} { set Tdemo [Info Tdemo] set style [Info selectedStyle] $Tdemo style configure $style -orient [Info -orient] return } proc StyleEditor::Sync_pad {index} { set Tdemo [Info Tdemo] set style [Info selectedStyle] set element [Info selectedElement] set option [Info selectedOption] if {[Info -pad,equal]} { if {$index == 1} { Info -pad,2 [Info -pad,1] } else { Info -pad,1 [Info -pad,2] } } $Tdemo style layout $style $element $option [list [Info -pad,1] [Info -pad,2]] Info -pad,edit $index StyleToCanvas return } proc StyleEditor::Sync_pad_equal {} { if {![Info -pad,equal]} return if {[Info -pad,edit] eq ""} { Info -pad,edit 1 } if {[Info -pad,edit] == 1} { Info -pad,2 [Info -pad,1] } else { Info -pad,1 [Info -pad,2] } Sync_pad [Info -pad,edit] return } proc StyleEditor::Sync_expand {} { set Tdemo [Info Tdemo] set style [Info selectedStyle] set element [Info selectedElement] set option [Info selectedOption] set value "" foreach flag {n s w e} { if {[Info -expand,$flag]} { append value $flag } } $Tdemo style layout $style $element $option $value StyleToCanvas return } proc StyleEditor::Sync_iexpand {} { set Tdemo [Info Tdemo] set style [Info selectedStyle] set element [Info selectedElement] set option [Info selectedOption] set value "" foreach flag {x y n s w e} { if {[Info -iexpand,$flag]} { append value $flag } } $Tdemo style layout $style $element $option $value StyleToCanvas return } proc StyleEditor::Sync_squeeze {} { set Tdemo [Info Tdemo] set style [Info selectedStyle] set element [Info selectedElement] set option [Info selectedOption] set value "" foreach flag {x y} { if {[Info -squeeze,$flag]} { append value $flag } } $Tdemo style layout $style $element $option $value StyleToCanvas return } proc StyleEditor::Sync_string {} { set Tdemo [Info Tdemo] set style [Info selectedStyle] set element [Info selectedElement] set option [Info selectedOption] if {[catch { $Tdemo style layout $style $element $option [Info -string] StyleToCanvas } msg]} { tk_messageBox -parent .styleEditor -icon error -title "Style Editor" \ -message $msg } return } proc StyleEditor::Sync_boolean {} { set Tdemo [Info Tdemo] set style [Info selectedStyle] set element [Info selectedElement] set option [Info selectedOption] $Tdemo style layout $style $element $option [Info -boolean] StyleToCanvas return } proc StyleEditor::Sync_pixels {} { set Tdemo [Info Tdemo] set style [Info selectedStyle] set element [Info selectedElement] set option [Info selectedOption] set value [Info -pixels] if {[Info -pixels,empty]} { set value {} [Info editor,pixels].v1 conf -state disabled } else { [Info editor,pixels].v1 conf -state normal } $Tdemo style layout $style $element $option $value StyleToCanvas return } proc StyleEditor::StyleToCanvas {{scroll 0}} { set Tdemo [Info Tdemo] set canvas [Info canvas] set style [Info selectedStyle] $canvas delete all if {$style eq ""} { $canvas configure -scrollregion {0 0 0 0} return } set T $canvas.t $T configure -itemheight 0 $T item configure root -height 0 $T header configure first -height 0 $T column configure 0 -width {} # Get the state domain, either "item" or "header". # It is used as the command name as well as the -statedomain value. set domain [$Tdemo style cget $style -statedomain] eval $T $domain state undefine [$T $domain state names] eval $T style delete [$T style names] eval $T element delete [$T element names] eval $T gradient delete [$T gradient names] # Copy states foreach state [$Tdemo $domain state names] { $T $domain state define $state } # Copy gradients (name only) foreach gradient [$Tdemo gradient names] { $T gradient create $gradient } # Copy elements foreach E [$Tdemo style elements $style] { $T element create $E [$Tdemo element type $E] \ -statedomain $domain foreach list [$Tdemo element configure $E] { lassign $list name x y default current $T element configure $E $name $current } } # Copy style $T style create $style -orient [$Tdemo style cget $style -orient] \ -statedomain $domain $T style elements $style [$Tdemo style elements $style] foreach E [$T style elements $style] { eval $T style layout $style $E [$Tdemo style layout $style $E] #$T style layout $style $E -visible {} } if {$domain eq "header"} { set match "" } if {$domain eq "item"} { # Find a selected item using the style to copy element config info from set match "" foreach I [$Tdemo selection get] { foreach S [$Tdemo item style set $I] C [$Tdemo column list] { if {$S eq $style} { set match $I break } } if {$match ne ""} break } # No selected item uses the current style, look for an unselected item if {$match eq ""} { foreach I [$Tdemo item range first last] { foreach S [$Tdemo item style set $I] C [$Tdemo column list] { if {$S eq $style} { set match $I break } } if {$match ne ""} break } } } if {$match ne ""} { set I $match if {[$Tdemo selection includes $I]} { $T selection add root } else { $T selection clear } foreach state [$Tdemo item state get $I] { if {[lsearch -exact [$Tdemo item state names] $state] != -1} { $T item state set root $state } } foreach state [$Tdemo item state forcolumn $I $C] { $T item state set root $state } foreach E [$Tdemo item style elements $I $C] { foreach list [$Tdemo item element configure $I $C $E] { lassign $list name x y default current set masterDefault [$Tdemo element cget $E $name] set sameAsMaster [string equal $masterDefault $current] if {!$sameAsMaster && ![string length $current]} { set sameAsMaster 1 set current $masterDefault } if {$sameAsMaster} { } elseif {$name eq "-window"} { $T style layout $style $E -width [winfo width $current] \ -height [winfo height $current] } else { $T element configure $E $name $current } } } } if 0 { # Do this after creating styles so -defaultstyle works foreach list [$Tdemo configure] { if {[llength $list] == 2} continue lassign $list name x y default current $T configure $name $current } } if {$domain eq "header"} { set I first $T header style set $I 0 $style } if {$domain eq "item"} { set I root $T item style set $I 0 $style } # Hack some minimum layout size > 0 foreach E [$T style elements $style] { if {[scan [$T $domain bbox $I 0 $E] "%d %d %d %d" x1 y1 x2 y2] == 4} { if {$y2 - $y1 == 0 && $x2 - $x1 == 0} { $T style layout $style $E -minwidth 10 -minheight 10 } } } set scale 2 set dx 10 set dy 10 scan [$T $domain bbox $I 0] "%d %d %d %d" x1 y1 x2 y2 $canvas create rectangle \ [expr {$dx + $x1 * $scale}] [expr {$dy + $y1 * $scale}] \ [expr {$dx + $x2 * $scale}] [expr {$dy + $y2 * $scale}] \ -outline gray90 foreach E [$T style elements $style] { if {[scan [$T $domain bbox $I 0 $E] "%d %d %d %d" x1 y1 x2 y2] == 4} { $canvas create rectangle \ [expr {$dx + $x1 * $scale}] [expr {$dy + $y1 * $scale}] \ [expr {$dx + $x2 * $scale}] [expr {$dy + $y2 * $scale}] \ -tags [list $E element] } } scan [$T $domain bbox $I 0] "%d %d %d %d" x1 y1 x2 y2 incr dy [expr {($y2 - $y1) * $scale + 20}] # Now give the style 1.5 times its needed space to test expansion scan [$T $domain bbox $I 0] "%d %d %d %d" x1 y1 x2 y2 $T column configure 0 -width [expr {($x2 - $x1) * [Info scaleX]}] if 1 { $T $domain configure $I -height [expr {($y2 - $y1) * [Info scaleY]}] } else { $T configure -itemheight [expr {($y2 - $y1) * [Info scaleY]}] } scan [$T $domain bbox $I 0] "%d %d %d %d" x1 y1 x2 y2 $canvas create rectangle \ [expr {$dx + $x1 * $scale}] [expr {$dy + $y1 * $scale}] \ [expr {$dx + $x2 * $scale}] [expr {$dy + $y2 * $scale}] \ -outline gray90 foreach E [$T style elements $style] { if {[scan [$T $domain bbox $I 0 $E] "%d %d %d %d" x1 y1 x2 y2] == 4} { $canvas create rectangle \ [expr {$dx + $x1 * $scale}] [expr {$dy + $y1 * $scale}] \ [expr {$dx + $x2 * $scale}] [expr {$dy + $y2 * $scale}] \ -tags [list $E element] } } scan [$canvas bbox all] "%d %d %d %d" x1 y1 x2 y2 incr x2 10 incr y2 10 $canvas configure -scrollregion [list 0 0 $x2 $y2] if {$scroll} { $canvas xview moveto 0.0 $canvas yview moveto 0.0 } CanvasSelectElement return } proc StyleEditor::CanvasSelectElement {} { set canvas [Info canvas] set style [Info selectedStyle] set element [Info selectedElement] $canvas itemconfigure element -fill "" -outline black if {$element ne ""} { $canvas itemconfigure $element -fill gray75 -outline green } return } proc StyleEditor::ScaleX {value} { Info scaleX [expr {$value / 100.0}] StyleToCanvas } proc StyleEditor::ScaleY {value} { Info scaleY [expr {$value / 100.0}] StyleToCanvas } tktreectrl-2.4.1/demos/table.tcl0000644000076400010400000003333411575000557017130 0ustar TimAdministrators# Copyright (c) 2011 Tim Baker namespace eval DemoTable {} proc DemoTable::Init {T} { variable Priv $T configure -showroot no -usetheme no -xscrollsmoothing yes $T column create -tags rowtitle -lock left -button no for {set i 1} {$i <= 10} {incr i} { $T column create -text $i -minwidth 20 } $T column configure all -background gray90 -borderwidth 1 $T column configure all -justify center -itemjustify left # # Create custom item states to change the appearance of items during # drag and drop. The 'drag' state is also used when resizing spans. # $T item state define drag $T item state define drop # Another state to highlight the cell under the mouse pointer. $T item state define mouseover # # Create a style for the row titles # $T element create rowtitle.border border \ -background gray90 -thickness 1 -relief raised -filled yes $T element create rowtitle.text text set S [$T style create rowtitle] $T style elements $S {rowtitle.border rowtitle.text} $T style layout $S rowtitle.border \ -union rowtitle.text -ipadx 3 -ipady 2 -iexpand news $T style layout $S rowtitle.text -center x # # Create a style for each cell # $T element create cell.text text $T element create cell.border border -background gray -thickness 2 -relief groove $T element create cell.bg rect \ -fill {{light green} drag {light blue} drop gray90 mouseover} set S [$T style create cell] $T style elements $S {cell.bg cell.border cell.text} $T style layout $S cell.bg -detach yes -iexpand xy \ -visible {yes drag yes drop yes mouseover no {}} $T style layout $S cell.border -union cell.text -iexpand wens -ipadx {2 3} -ipady 2 $T style layout $S cell.text -squeeze x # # Set default styles and create items # $T column configure 0 -itemstyle rowtitle $T column configure {range 1 10} -itemstyle cell foreach I [$T item create -count 5000 -parent root] { $T item text $I rowtitle [$T item order $I] } $T item text {root children} {range 1 10} "edit me" $T item text 10 5 "*** DRAG ME ***" $T item span 10 5 2 $T item text 15 2 "RESIZE THE SPAN -->" $T item span 15 2 3 $T notify bind $T { %T item text %I %C %t set DemoTable::EditAccepted 1 } $T notify bind $T { if {!$DemoTable::EditAccepted} { %T item element configure %I %C %E -text $DemoTable::OrigText } %T item element configure %I %C %E -textvariable "" } # Set the minimum item height to be as tall as the style and the # entry widget used to edit text need. Text elements may wrap lines # causing an item to become even taller. set height [font metrics [$T cget -font] -linespace] incr height [expr {[$T style layout cell cell.border -ipady] * 2}] incr height 2 ; # entry widget YPAD $T configure -minitemheight $height set Priv(buttonMode) "" set Priv(cursor,want) "" set Priv(cursor,set) 0 set Priv(highlight) "" bind DemoTable { DemoTable::ButtonPress1 %W %x %y } bind DemoTable { DemoTable::Button1Motion %W %x %y DemoTable::MaintainHighlight %W } bind DemoTable { DemoTable::ButtonRelease1 %W %x %y DemoTable::Motion %W %x %y DemoTable::MaintainCursor %W DemoTable::MaintainHighlight %W } # Control-drag to copy text bind DemoTable { DemoTable::ButtonRelease1 %W %x %y control DemoTable::Motion %W %x %y DemoTable::MaintainCursor %W DemoTable::MaintainHighlight %W } if {[tk windowingsystem] eq "aqua" } { bind DemoTable { DemoTable::ButtonRelease1 %W %x %y command DemoTable::Motion %W %x %y DemoTable::MaintainCursor %W DemoTable::MaintainHighlight %W } } bind DemoTable { DemoTable::Motion %W %x %y DemoTable::MaintainCursor %W DemoTable::MaintainHighlight %W } bindtags $T [list $T DemoTable TreeCtrl [winfo toplevel $T] all] return } proc DemoTable::ButtonPress1 {T x y} { variable Priv if {[winfo exists $T.entry] && [winfo ismapped $T.entry]} { TreeCtrl::EditClose $T entry 1 0 } set Priv(buttonMode) "" $T identify -array id $x $y if {$id(where) ne "item"} return if {$id(column) eq "tail"} return if {[$T column tag expr $id(column) rowtitle]} return switch -- [WhichSide $T $id(item) $id(column) $x $y] { left { if {[$T column compare $id(column) > "first visible lock none"]} { set Priv(buttonMode) resize set Priv(item) $id(item) set Priv(column) [StartOfPrevSpan $T $id(item) $id(column)] set Priv(y) $y $T item state forcolumn $Priv(item) $Priv(column) drag return } } right { if {[$T column compare $id(column) < "last visible lock none"]} { set Priv(buttonMode) resize set Priv(item) $id(item) set Priv(column) $id(column) set Priv(y) $y $T item state forcolumn $Priv(item) $Priv(column) drag return } } } set Priv(buttonMode) dragWait set Priv(item) $id(item) set Priv(column) $id(column) set Priv(x) $x set Priv(y) $y return } proc DemoTable::Button1Motion {T x y} { variable Priv set Priv(highlight,want) {} switch $Priv(buttonMode) { dragWait { set Priv(highlight,want) [list $Priv(item) $Priv(column) mouseover] if {(abs($Priv(x) - $x) > 4) || (abs($Priv(y) - $y) > 4)} { set Priv(buttonMode) drag $T item state forcolumn $Priv(item) $Priv(column) drag set Priv(cx) [$T canvasx $x] set Priv(cy) [$T canvasy $y] $T dragimage clear $T dragimage add $Priv(item) $Priv(column) cell.border $T dragimage configure -visible yes } } drag { $T identify -array id $x $y if {$id(where) eq "item" && [$T column cget $id(column) -lock] eq "none"} { set Priv(highlight,want) [list $id(item) $id(column) drop] } set dx [expr {[$T canvasx $x] - $Priv(cx)}] set dy [expr {[$T canvasy $y] - $Priv(cy)}] $T dragimage offset $dx $dy } resize { $T identify -array id $x $Priv(y) if {$id(where) eq "item"} { set C [ColumnUnderPoint $T $x $y] if {[WhichHalf $T $C $x $y] eq "right"} { if {[$T column compare $id(column) > $Priv(column)]} { IncrSpan $T $Priv(item) $Priv(column) $C } if {[$T column compare $C >= $Priv(column)] && ([$T item span $Priv(item) $Priv(column)] > 1)} { DecrSpan $T $Priv(item) $Priv(column) $C } } if {[WhichHalf $T $C $x $y] eq "left"} { if {[$T column compare $C == $Priv(column)]} { DecrSpan $T $Priv(item) $Priv(column) $C } } } } } return } proc DemoTable::ButtonRelease1 {T x y args} { variable Priv array set modifiers { shift 0 control 0 command 0 } foreach modifier $args { set modifiers($modifier) 1 } switch $Priv(buttonMode) { dragWait { # FIXME: EntryExpanderOpen doesn't work with master elements $T see $Priv(item) $Priv(column) set text [$T item text $Priv(item) $Priv(column)] $T item text $Priv(item) $Priv(column) $text set exists [winfo exists $T.entry] TreeCtrl::EntryExpanderOpen $T $Priv(item) $Priv(column) cell.text if {!$exists} { $T.entry configure -borderwidth 0 scan [$T item bbox $Priv(item) $Priv(column) cell.text] "%d %d %d %d" x1 y1 x2 y2 place $T.entry -y [expr {$y1 - 1}] } # Remove the binding on the text entry since typing # may resize columns, causing the entry to become hidden. $T notify unbind $T.entry # Set the -textvariable on the text element and the entry widget # to be the same, so typing in the entry automatically updates # the text element. set ::DemoTable::TextVar $text set ::DemoTable::OrigText $text set ::DemoTable::EditAccepted 0 $T.entry configure -textvariable ::DemoTable::TextVar $T item element configure $Priv(item) $Priv(column) cell.text \ -textvariable ::DemoTable::TextVar -text "" # Override EntryExpanderKeypress to make the entry widget as wide # as we want. bind $T.entry { after idle [list DemoTable::EntryExpanderKeypress [winfo parent %W]] } # Now that the text is set, reposition the entry widget. scan [$T item bbox $Priv(item) $Priv(column)] "%d %d %d %d" x1 y1 x2 y2 set left [expr {$x1 + 2 - 1}] set right [expr {$x2 - 2}] place $T.entry -x $left -width [expr {$right - $left}] update idletasks # Emulate a button press in the entry widget. set entryX [expr {$x - $left}] set pos [$T.entry index @$entryX] set bbox [$T.entry bbox $pos] if {($entryX - [lindex $bbox 0]) >= ([lindex $bbox 2]/2)} { incr pos } $T.entry icursor [$T.entry index $pos] } drag { $T dragimage configure -visible no $T item state forcolumn $Priv(item) $Priv(column) !drag $T identify -array id $x $y if {$id(where) ne "item"} return if {[$T column cget $id(column) -lock] ne "none"} return if {[$T item compare $id(item) == $Priv(item)] && [$T column compare $id(column) == $Priv(column)]} return set textSource [$T item text $Priv(item) $Priv(column)] set textDest [$T item text $id(item) $id(column)] $T item text $id(item) $id(column) $textSource if {!$modifiers(control) && !$modifiers(command)} { $T item text $Priv(item) $Priv(column) $textDest } } resize { $T item state forcolumn $Priv(item) $Priv(column) !drag } } set Priv(buttonMode) "" return } proc DemoTable::Motion {T x y} { variable Priv $T identify -array id $x $y set Priv(cursor,want) "" set Priv(highlight,want) {} if {$id(where) ne "item"} return if {$id(column) eq "tail"} return if {[$T column tag expr $id(column) rowtitle]} return set Priv(highlight,want) [list $id(item) $id(column) mouseover] switch -- [WhichSide $T $id(item) $id(column) $x $y] { left { if {[$T column compare $id(column) > "first visible lock none"]} { set Priv(cursor,want) sb_h_double_arrow set prev [StartOfPrevSpan $T $id(item) $id(column)] set Priv(highlight,want) [list $id(item) $prev mouseover] } } right { if {[$T column compare $id(column) < "last visible lock none"]} { set Priv(cursor,want) sb_h_double_arrow set Priv(highlight,want) [list $id(item) $id(column) mouseover] } } } return } proc DemoTable::MaintainCursor {T} { variable Priv if {!$Priv(cursor,set) && $Priv(cursor,want) ne ""} { $T configure -cursor $Priv(cursor,want) set Priv(cursor,set) 1 return } if {$Priv(cursor,set) && [$T cget -cursor] ne $Priv(cursor,want)} { $T configure -cursor $Priv(cursor,want) } if {$Priv(cursor,set) && $Priv(cursor,want) eq ""} { set Priv(cursor,set) 0 } return } proc DemoTable::MaintainHighlight {T} { variable Priv if {$Priv(highlight) ne $Priv(highlight,want)} { if {$Priv(highlight) ne ""} { lassign $Priv(highlight) item column state $T item state forcolumn $item $column {!drop !mouseover} } if {$Priv(highlight,want) ne ""} { lassign $Priv(highlight,want) item column state $T item state forcolumn $item $column [list !drop !mouseover $state] } set Priv(highlight) $Priv(highlight,want) } return } proc DemoTable::StartOfNextSpan {T I C} { set span [$T item span $I $C] set last [$T column id "$C span $span"] return [$T column id "$last next visible"] } proc DemoTable::StartOfPrevSpan {T I C} { set prev [$T column id "$C prev visible"] if {$prev ne ""} { set starts [GetSpanStarts $T $I] return [lindex $starts [$T column order $prev]] } return "" } proc DemoTable::IncrSpan {T I C newLast} { set span [expr {[$T column order $newLast] - [$T column order $C] + 1}] $T item span $I $C $span return } proc DemoTable::DecrSpan {T I C newLast} { set span [expr {[$T column order $newLast] - [$T column order $C] + 1}] $T item span $I $C $span return } proc DemoTable::ColumnUnderPoint {T x y} { #return [$T column id "nearest $x $y"] set totalWidth [lindex [$T cget -canvaspadx] 0] foreach C [$T column id "lock none"] { incr totalWidth [$T column width $C] if {[$T canvasx $x] < $totalWidth} { return $C } } return "" } proc DemoTable::WhichSide {T I C x y} { scan [$T item bbox $I $C] "%d %d %d %d" x1 y1 x2 y2 if {$x < $x1 + 5} { return left } if {$x >= $x2 - 5} { return right } return } proc DemoTable::WhichHalf {T C x y} { scan [$T column bbox $C] "%d %d %d %d" x1 y1 x2 y2 if {$x < $x1 + ($x2 - $x1) / 2} { return left } return right } proc DemoTable::GetSpanStarts {T I} { set columns [list] set spans [$T item span $I] if {[lindex [lsort -integer $spans] end] eq 1} { return [$T column list] } for {set index 0} {$index < [$T column count]} {} { set Cspan [$T column id "order $index"] set span [lindex $spans $index] if {![$T column cget $Cspan -visible]} { set span 1 } while {$span > 0 && $index < [$T column count]} { if {[$T column cget "order $index" -lock] ne [$T column cget $Cspan -lock]} break lappend columns $Cspan incr span -1 incr index } } return $columns } # This is bad, relying on all sorts of private stuff in the library code. proc DemoTable::EntryExpanderKeypress {T} { variable ::TreeCtrl::Priv if {![winfo exists $T]} return set font $Priv(entry,$T,font) set text [$T.entry get] set ebw [$T.entry cget -borderwidth] set ex [winfo x $T.entry] scan [$T item bbox $Priv(entry,$T,item) $Priv(entry,$T,column)] "%d %d %d %d" x1 y1 x2 y2 set left [expr {$x1 + 2 - 1}] set right [expr {$x2 - 2}] set width [expr {$right - $left}] scan [$T contentbox] "%d %d %d %d" left top right bottom if {$ex + $width > $right} { set width [expr {$right - $ex}] } place configure $T.entry -width $width return } tktreectrl-2.4.1/demos/textvariable.tcl0000644000076400010400000000440011573542201020516 0ustar TimAdministrators# Copyright (c) 2005-2011 Tim Baker namespace eval DemoTextvariable {} proc DemoTextvariable::Init {T} { variable Priv # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no \ -selectmode extended -xscrollincrement 20 \ -yscrollincrement 10 -showheader yes if {!$::clip} { # Hide the borders because child windows appear on top of them $T configure -borderwidth 0 -highlightthickness 0 } # # Create columns # $T column create -text "Resize Me!" -justify center -tags C0 $T configure -treecolumn C0 # # Create elements # $T element create eWindow window $T element create eRect rect -rx 7 $T element create eText1 text -width 300 $T element create eText2 text -wrap none # # Create styles using the elements # set S [$T style create s1 -orient horizontal] $T style elements $S eText1 $T style layout $S eText1 -padx 10 -pady 6 -squeeze x set S [$T style create s2 -orient vertical] $T style elements $S {eRect eText2 eWindow} $T style layout $S eRect -union {eText2 eWindow} -ipadx 8 -ipady 8 -padx 4 -pady {0 4} $T style layout $S eText2 -pady {0 6} -squeeze x $T style layout $S eWindow -iexpand x -squeeze x # # Create items and assign styles # set I [$T item create] $T item style set $I C0 s1 $T item element configure $I C0 eText1 -text "Each text element and entry widget share the same -textvariable. Editing the text in the entry automatically updates the text element." $T item lastchild root $I foreach i {0 1} color {gray75 "light blue"} { set I [$T item create] $T item style set $I C0 s2 set tvar ::DemoTextvariable::Priv(tvar,$I) if {$::clip} { set clip [frame $T.clip$I -borderwidth 0] set e [$::entryCmd $clip.e -width 48 -textvariable $tvar] $T item element configure $I C0 \ eRect -fill [list $color] + \ eText2 -textvariable $tvar + \ eWindow -window $clip -clip yes } else { set e [$::entryCmd $T.e$I -width 48 -textvariable $tvar] $T item element configure $I C0 \ eRect -fill [list $color] + \ eText2 -textvariable $tvar + \ eWindow -window $e } $T item lastchild root $I set Priv(tvar,$I) "This is item $I" } return } tktreectrl-2.4.1/demos/www-options.tcl0000644000076400010400000001761411573543030020355 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker namespace eval DemoInternetOptions {} proc DemoInternetOptions::Init {T} { variable Priv set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no -itemheight $height \ -selectmode browse $T configure -canvaspadx {4 0} -canvaspady {2 0} InitPics internet-* # # Create columns # $T column create -text "Internet Options" -tags C0 $T configure -treecolumn C0 # # Create elements # $T item state define check $T item state define radio $T item state define on $T element create elemImg image -image { internet-check-on {check on} internet-check-off {check} internet-radio-on {radio on} internet-radio-off {radio} } $T element create elemTxt text \ -fill [list $::SystemHighlightText {selected focus}] -lines 1 $T element create elemRectSel rect \ -fill [list $::SystemHighlight {selected focus}] -showfocus yes # # Create styles using the elements # set S [$T style create STYLE] $T style elements $S {elemRectSel elemImg elemTxt} $T style layout $S elemImg -padx {0 4} -expand ns $T style layout $S elemTxt -expand ns -squeeze x $T style layout $S elemRectSel -union [list elemTxt] -iexpand ns -ipadx 2 # # Create items and assign styles # set parentList [list root {} {} {} {} {} {}] set parent root foreach {depth setting text option group} { 0 print "Printing" "" "" 1 off "Print background colors and images" "o1" "" 0 search "Search from Address bar" "" "" 1 search "When searching" "" "" 2 off "Display results, and go to the most likely sites" "o2" "r1" 2 off "Do not search from the Address bar" "o3" "r1" 2 off "Just display the results in the main window" "o4" "r1" 2 on "Just go to the most likely site" "o5" "r1" 0 security "Security" "" "" 1 on "Check for publisher's certificate revocation" "o5" "" 1 off "Check for server certificate revocation (requires restart)" "o6" "" } { set item [$T item create] $T item style set $item C0 STYLE $T item element configure $item C0 elemTxt -text $text set Priv(option,$item) $option set Priv(group,$item) $group if {($setting eq "on") || ($setting eq "off")} { set Priv(setting,$item) $setting if {$group eq ""} { $T item state set $item check if {$setting eq "on"} { $T item state set $item on } } else { if {$setting eq "on"} { set Priv(current,$group) $item $T item state set $item on } $T item state set $item radio } } else { $T item element configure $item C0 elemImg -image internet-$setting } $T item lastchild [lindex $parentList $depth] $item incr depth set parentList [lreplace $parentList $depth $depth $item] } bind DemoInternetOptions { TreeCtrl::DoubleButton1 %W %x %y } bind DemoInternetOptions { DemoInternetOptions::Button1 %W %x %y break } bindtags $T [list $T DemoInternetOptions TreeCtrl [winfo toplevel $T] all] return } proc DemoInternetOptions::Button1 {T x y} { variable Priv focus $T set id [$T identify $x $y] if {[lindex $id 0] eq "header"} { TreeCtrl::ButtonPress1 $T $x $y } elseif {$id eq ""} { set ::TreeCtrl::Priv(buttonMode) "" } else { set ::TreeCtrl::Priv(buttonMode) "" set item [lindex $id 1] $T selection modify $item all $T activate $item if {$Priv(option,$item) eq ""} return set group $Priv(group,$item) # a checkbutton if {$group eq ""} { $T item state set $item ~on if {$Priv(setting,$item) eq "on"} { set setting off } else { set setting on } set Priv(setting,$item) $setting # a radiobutton } else { set current $Priv(current,$group) if {$current eq $item} return $T item state set $current !on $T item state set $item on set Priv(setting,$item) on set Priv(current,$group) $item } } return } # Alternate implementation that does not rely on run-time states proc DemoInternetOptions::Init_2 {T} { variable Priv set height [font metrics [$T cget -font] -linespace] if {$height < 18} { set height 18 } # # Configure the treectrl widget # $T configure -showroot no -showbuttons no -showlines no -itemheight $height \ -selectmode browse InitPics internet-* # # Create columns # $T column create -text "Internet Options" # # Create elements # $T element create elemImg image $T element create elemTxt text -fill [list $::SystemHighlightText {selected focus}] $T element create elemRectSel rect -fill [list $::SystemHighlight {selected focus}] -showfocus yes # # Create styles using the elements # set S [$T style create STYLE] $T style elements $S {elemRectSel elemImg elemTxt} $T style layout $S elemImg -padx {0 4} -expand ns $T style layout $S elemTxt -expand ns $T style layout $S elemRectSel -union [list elemTxt] -iexpand ns -ipadx 2 # # Create items and assign styles # set parentList [list root {} {} {} {} {} {}] set parent root foreach {depth setting text option group} { 0 print "Printing" "" "" 1 off "Print background colors and images" "o1" "" 0 search "Search from Address bar" "" "" 1 search "When searching" "" "" 2 off "Display results, and go to the most likely sites" "o2" "r1" 2 off "Do not search from the Address bar" "o3" "r1" 2 off "Just display the results in the main window" "o4" "r1" 2 on "Just go to the most likely site" "o5" "r1" 0 security "Security" "" "" 1 on "Check for publisher's certificate revocation" "o5" "" 1 off "Check for server certificate revocation (requires restart)" "o6" "" } { set item [$T item create] $T item style set $item 0 STYLE $T item element configure $item 0 elemTxt -text $text set Priv(option,$item) $option set Priv(group,$item) $group if {$setting eq "on" || $setting eq "off"} { set Priv(setting,$item) $setting if {$group eq ""} { set img internet-check-$setting $T item element configure $item 0 elemImg -image $img } else { if {$setting eq "on"} { set Priv(current,$group) $item } set img internet-radio-$setting $T item element configure $item 0 elemImg -image $img } } else { $T item element configure $item 0 elemImg -image internet-$setting } $T item lastchild [lindex $parentList $depth] $item incr depth set parentList [lreplace $parentList $depth $depth $item] } bind DemoInternetOptions { TreeCtrl::DoubleButton1 %W %x %y } bind DemoInternetOptions { DemoInternetOptions::Button1 %W %x %y break } bindtags $T [list $T DemoInternetOptions TreeCtrl [winfo toplevel $T] all] return } # Alternate implementation that does not rely on run-time states proc DemoInternetOptions::Button1_2 {T x y} { variable Priv focus $T set id [$T identify $x $y] if {[lindex $id 0] eq "header"} { TreeCtrl::ButtonPress1 $T $x $y } elseif {$id eq ""} { set ::TreeCtrl::Priv(buttonMode) "" } else { set ::TreeCtrl::Priv(buttonMode) "" set item [lindex $id 1] $T selection modify $item all $T activate $item if {$Priv(option,$item) eq ""} return set group $Priv(group,$item) # a checkbutton if {$group eq ""} { if {$Priv(setting,$item) eq "on"} { set setting off } else { set setting on } $T item element configure $item 0 elemImg -image internet-check-$setting set Priv(setting,$item) $setting # a radiobutton } else { set current $Priv(current,$group) if {$current eq $item} return $T item element configure $current 0 elemImg -image internet-radio-off $T item element configure $item 0 elemImg -image internet-radio-on set Priv(setting,$item) on set Priv(current,$group) $item } } return } tktreectrl-2.4.1/doc/0000755000076400010400000000000011646706170014770 5ustar TimAdministratorstktreectrl-2.4.1/doc/man.macros0000644000076400010400000001144511527030076016747 0ustar TimAdministrators'\" The definitions below are for supplemental macros used in Tcl/Tk '\" manual entries. '\" '\" .AP type name in/out ?indent? '\" Start paragraph describing an argument to a library procedure. '\" type is type of argument (int, etc.), in/out is either "in", "out", '\" or "in/out" to describe whether procedure reads or modifies arg, '\" and indent is equivalent to second arg of .IP (shouldn't ever be '\" needed; use .AS below instead) '\" '\" .AS ?type? ?name? '\" Give maximum sizes of arguments for setting tab stops. Type and '\" name are examples of largest possible arguments that will be passed '\" to .AP later. If args are omitted, default tab stops are used. '\" '\" .BS '\" Start box enclosure. From here until next .BE, everything will be '\" enclosed in one large box. '\" '\" .BE '\" End of box enclosure. '\" '\" .CS '\" Begin code excerpt. '\" '\" .CE '\" End code excerpt. '\" '\" .VS ?version? ?br? '\" Begin vertical sidebar, for use in marking newly-changed parts '\" of man pages. The first argument is ignored and used for recording '\" the version when the .VS was added, so that the sidebars can be '\" found and removed when they reach a certain age. If another argument '\" is present, then a line break is forced before starting the sidebar. '\" '\" .VE '\" End of vertical sidebar. '\" '\" .DS '\" Begin an indented unfilled display. '\" '\" .DE '\" End of indented unfilled display. '\" '\" .SO '\" Start of list of standard options for a Tk widget. The '\" options follow on successive lines, in four columns separated '\" by tabs. '\" '\" .SE '\" End of list of standard options for a Tk widget. '\" '\" .OP cmdName dbName dbClass '\" Start of description of a specific option. cmdName gives the '\" option's name as specified in the class command, dbName gives '\" the option's name in the option database, and dbClass gives '\" the option's class in the option database. '\" '\" .UL arg1 arg2 '\" Print arg1 underlined, then print arg2 normally. '\" '\" RCS: @(#) $Id$ '\" '\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. '\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out '\" # BS - start boxed text '\" # ^y = starting y location '\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. '\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. '\" # Special macro to handle page bottom: finish off current '\" # box/sidebar if in box/sidebar mode, then invoked standard '\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. '\" # DS - begin display .de DS .RS .nf .sp .. '\" # DE - end display .de DE .fi .RE .sp .. '\" # SO - start of list of standard options .de SO .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. '\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\fBoptions\\fR manual entry for details on the standard options. .. '\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. '\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. '\" # CE - end code excerpt .de CE .fi .RE .. .de UL \\$1\l'|0\(ul'\\$2 .. tktreectrl-2.4.1/doc/treectrl.html0000644000076400010400000117677711646360503017530 0ustar TimAdministrators treectrl - Tk Commands

treectrl(n) 2.4.1 treectrl "Tk Commands"

Name

treectrl - Create and manipulate hierarchical multicolumn widgets

Synopsis

  • package require treectrl 2.4.1

Description

treectrl pathName ?options?

The treectrl command creates a new window (given by the pathName argument) and makes it into a treectrl widget. Additional options, described above, may be specified on the command line or in the option database to configure aspects of the treectrl such as its background color and relief. The treectrl command returns the path name of the new window. At the time this command is invoked, there must not exist a window named pathName, but pathName's parent must exist.

A treectrl is a listbox widget which displays items in a one- or two-dimensional arrangement. Items have a parent-child relationship with other items. Items may be arranged from top-to-bottom or from left-to-right. Items may be spread about one or more columns. Each item-column may be configured to span one or more adjacent item-columns. The visibility of items can be set individually.

Items have a set of states, which are boolean properties. For each column of an item there is a style associated, which determines how to display the item's column taking into account the item's current state set. New states may be defined to further control the appearance of items; these custom states may be turned on or off in individual columns of items.

Multiple rows of column headers are supported. Column headers have platform-native appearance on Windows, Mac OS X, and Gtk+. The appearance of column headers may be customized using styles.

Columns may be rearranged by the user using drag-and-drop. One column can be specified to display the data in a hierarchical structure. The visibility of columns can be set individually.

A treectrl can display a user-resizable selection rectangle called the marquee. Another feature, the drag image, may be used to provide feedback during drag-and-drop operations. Both of these are features commonly found in file browsers.

A treectrl can generate events when various things happen, such as changes to the selection, or a parent item being toggled open or closed. Scripts may be bound to these events. New events can be defined.

A treectrl can display a background image. The background image can be configured to be scrolled and tiled on each axis individually.

STANDARD OPTIONS

-background
-borderwidth
-cursor
-font
-highlightbackground
-highlightcolor
-highlightthickness
-orient
-relief
-takefocus
-xscrollcommand
-yscrollcommand
-foreground

See the option manual entry for details on the standard options.

WIDGET SPECIFIC OPTIONS

Command-Line Switch: -backgroundimage
Database Name: backgroundImage
Database Class: BackgroundImage

Specifies the name of an image to draw as the list background. Other options control whether the image is tiled and whether the image scrolls. If the image is transparent it is drawn on top of any column -itembackground colors.

Command-Line Switch: -backgroundmode
Database Name: backgroundMode
Database Class: BackgroundMode

Specifies how the background color of items is chosen in each column. The value should be one of row, column, order, or ordervisible. The default is row. This option has only an effect for columns which have -itembackground defined as list of two or more colors (see section COLUMNS below for more on this). If row or column is specified, the background color is chosen based on the location of the item in the 1- or 2-dimensional grid of items as layed out on the screen; this layout of items is affected by the -orient and -wrap options as well as item visibility. When order or ordervisible is specified, the background color is chosen based on the result of the item order command, regardless of the layout of items.

Command-Line Switch: -bgimage
Database Name: bgImage
Database Class: BgImage

Synonym for -backgroundimage.

Command-Line Switch: -bgimageanchor
Database Name: bgImageAnchor
Database Class: BgImageAnchor

Specifies how the background image should be aligned in any of the forms acceptable to Tk_GetAnchor. Must be one of the values n, ne, e, se, s, sw, w, nw, or center. The default is nw. When the background image scrolls, the anchor position is relative to the canvas, otherwise it is relative to the contentbox.

Command-Line Switch: -bgimageopaque
Database Name: bgImageOpaque
Database Class: BgImageOpaque

Specifies a boolean indicating whether or not the background image is fully opaque. This is needed because there is no way in Tk to determine whether an image contains transparency or not. The default value is true, so if you use a transparent -backgroundimage you must set this to false.

Command-Line Switch: -bgimagescroll
Database Name: bgImageScroll
Database Class: BgImageScroll

Specifies whether the background image scrolls along with the items or whether it remains locked in place relative to the edges of the window. The value must be a string that contains zero or more of the characters x or y. The default is xy.

Command-Line Switch: -bgimagetile
Database Name: bgImageTile
Database Class: BgImageTile

Specifies whether the background image is tiled along the x and/or y axes. The value must be a string that contains zero or more of the characters x or y. The default is xy.

Command-Line Switch: -buttonbitmap
Database Name: buttonBitmap
Database Class: ButtonBitmap

Specifies the name of a bitmap be used to display the expand/collapse button of an item. This is a per-state option. If a bitmap is specified for a certain item state, it overrides the effects of -usetheme.

Command-Line Switch: -buttoncolor
Database Name: buttonColor
Database Class: ButtonColor

Specifies the foreground color which should be used for drawing the outline and the plus or minus sign of an item's expand/collapse button.

Command-Line Switch: -buttonimage
Database Name: buttonImage
Database Class: ButtonImage

Specifies the name of an image to be used to display the expand/collapse button of an item. This is a per-state option. If an image is specified for a certain item state, it overrides the effects of -buttonbitmap and -usetheme.

Command-Line Switch: -buttonsize
Database Name: buttonSize
Database Class: ButtonSize

Specifies the width and height of the expand/collapse button of an item in any of the forms acceptable to Tk_GetPixels.

Command-Line Switch: -buttonthickness
Database Name: buttonThickness
Database Class: ButtonThickness

Specifies the width of the outline and the plus or minus sign of the expand/collapse button of an item in any of the forms acceptable to Tk_GetPixels.

Command-Line Switch: -buttonttracking
Database Name: buttonTracking
Database Class: ButtonTracking

Specifies a boolean that determines if the expand/collapse buttons are tracked like pushbuttons when clicking them. When true, buttons are not toggled until the <ButtonRelease> event occurs over them. When false, buttons are toggled as soon as the <ButtonPress> event occurs over them. This option defaults to true on Mac OS X and Gtk+, false on Win32 and X11.

Command-Line Switch: -canvaspadx
Database Name: canvasPadX
Database Class: CanvasPadX

Specifies the width of extra whitespace on the left and right edges of the canvas in any of the forms acceptable to Tk_GetPixels. The option value may be a list of one or two screen distances to specify padding for the two edges separately. The default is 0.

Command-Line Switch: -canvaspady
Database Name: canvasPadY
Database Class: CanvasPadY

Specifies the height of extra whitespace on the top and bottom edges of the canvas in any of the forms acceptable to Tk_GetPixels. The option value may be a list of one or two screen distances to specify padding for the two edges separately. The default is 0.

Command-Line Switch: -columnprefix
Database Name: columnPrefix
Database Class: ColumnPrefix

Specifies an ascii string that changes the way column ids are reported and processed. If this option is a non-empty string, the usual integer value of a column id is prefixed with the given string. This can aid debugging but it is important your code doesn't assume column ids are integers if you use it.

Command-Line Switch: -columnproxy
Database Name: columnProxy
Database Class: ColumnProxy

If this option specifies a non empty value, it should be a screen distance in any of the forms acceptable to Tk_GetPixels. Then a 1 pixel thick vertical line will be drawn at the specified screen distance from the left edge of the treectrl widget, which reaches from top to bottom of the treectrl widget and uses an inverting color (i.e black on lighter background, white on darker background). This line can be used to give the user a visual feedback during column resizing.

Command-Line Switch: -columnresizemode
Database Name: columnResizeMode
Database Class: ColumnResizeMode

Specifies the visual feedback used when resizing columns. The value should be one of proxy or realtime. For proxy, a 1-pixel thick vertical line is drawn representing where the right edge of the column will be after resizing. For realtime, the column's size is changed while the user is dragging the right edge of the column. The default is realtime.

Command-Line Switch: -columntagexpr
Database Name: columnTagExpr
Database Class: ColumnTagExpr

Specifies a boolean that enables or disables tag expressions in column descriptions. See ITEM AND COLUMN TAGS.

Command-Line Switch: -defaultstyle
Database Name: defaultStyle
Database Class: DefaultStyle

This option is deprecated; use the column option -itemstyle instead. Specifies a list of styles, one per column, to apply to each item created by the item create command. The number of styles in the list can be different from the number of tree columns. Each list element should be a valid style name or an empty string to indicate no style should be applied to a specific column. The list of styles is updated if a style is deleted or if a column is moved.

Command-Line Switch: -doublebuffer
Database Name: doubleBuffer
Database Class: DoubleBuffer

This option no longer has any effect, but was left in for compatibility. It used to control the amount of double-buffering that was used when displaying a treectrl.

Command-Line Switch: -headerfont
Database Name: headerFont
Database Class: Font

Specifies the font to draw text in column headers with. The default value is TkHeadingFont where available (on Tk 8.5+). This option can be overridden by setting the -font option for individual column headers.

Command-Line Switch: -headerfg
Database Name: headerForeground
Database Class: Foreground

Synonym for -headerforeground.

Command-Line Switch: -headerforeground
Database Name: headerForeground
Database Class: Foreground

Specifies the color to draw text in column headers with. The default value is the Tk button foreground color (usually black). On Gtk+, the system theme may override this color. This option (and the Gtk+ system theme color) can be overridden by setting the -textcolor option for individual column headers.

Command-Line Switch: -height
Database Name: height
Database Class: Height

Specifies the desired height for the window in any of the forms acceptable to Tk_GetPixels. The default is 200 pixels. If this option is less than or equal to zero then the window will not request any size at all.

Command-Line Switch: -indent
Database Name: indent
Database Class: Indent

Specifies the screen distance an item is indented relative to its parent item in any of the forms acceptable to Tk_GetPixels. The default is 19 pixels.

Command-Line Switch: -itemgapx
Database Name: itemGapX
Database Class: ItemGapX

Specifies the horizontal spacing between adjacent items in any of the forms acceptable to Tk_GetPixels. The default is 0.

Command-Line Switch: -itemgapy
Database Name: itemGapY
Database Class: ItemGapY

Specifies the vertical spacing between adjacent items in any of the forms acceptable to Tk_GetPixels. The default is 0.

Command-Line Switch: -itemheight
Database Name: itemHeight
Database Class: ItemHeight

Specifies a fixed height for every item in any of the forms acceptable to Tk_GetPixels. If non-zero, this option overrides the requested height of an item and the -minitemheight option. If an item's own -height option is specified then that is the height used for the item. In any case, items are never shorter than the maximum height of a button if they display one. The default is 0.

Command-Line Switch: -itemprefix
Database Name: itemPrefix
Database Class: ItemPrefix

Specifies an ascii string that changes the way item ids are reported and processed. If this option is a non-empty string, the usual integer value of an item id is prefixed with the given string. This can aid debugging but it is important your code doesn't assume item ids are integers if you use it.

Command-Line Switch: -itemtagexpr
Database Name: itemTagExpr
Database Class: ItemTagExpr

Specifies a boolean that enables or disables tag expressions in item descriptions. See ITEM AND COLUMN TAGS.

Command-Line Switch: -itemwidth
Database Name: itemWidth
Database Class: ItemWidth

Specifies a fixed width for every item in any of the forms acceptable to Tk_GetPixels. If more than one column is visible, then this option has no effect. If the -orient option is vertical, and the -wrap option is unspecified, then this option has no effect (in that case all items are as wide as the column).

Command-Line Switch: -itemwidthequal
Database Name: itemWidthEqual
Database Class: ItemWidthEqual

Specifies a boolean that says whether all items should have the same width. If more than one column is visible, then this option has no effect. If the -orient option is vertical, and the -wrap option is unspecified, then this option has no effect (in that case all items are as wide as the column). If the -itemwidth option is specified, then this option has no effect.

Command-Line Switch: -itemwidthmultiple
Database Name: itemWidthMultiple
Database Class: ItemWidthMultiple

Specifies a screen distance that every item's width will be evenly divisible by in any of the forms acceptable to Tk_GetPixels. If more than one column is visible, then this option has no effect. If the -orient option is vertical, and the -wrap option is unspecified, then this option has no effect (in that case all items are as wide as the column). If the -itemwidth option is specified, then this option has no effect.

Command-Line Switch: -linecolor
Database Name: lineColor
Database Class: LineColor

Specifies the color which should be used for drawing the connecting lines between related items.

Command-Line Switch: -linestyle
Database Name: lineStyle
Database Class: LineStyle

Specifies the appearance of the connecting lines between related items. The value should be dot, which is the default, or solid.

Command-Line Switch: -linethickness
Database Name: lineThickness
Database Class: LineThickness

Specifies the thickness of the connecting lines between related items in any of the forms acceptable to Tk_GetPixels.

Command-Line Switch: -minitemheight
Database Name: minItemHeight
Database Class: MinItemHeight

Specifies a minimum height for every item in any of the forms acceptable to Tk_GetPixels. The default is 0, which means that every item has the height requested by the arrangement of elements in each column. This option has no effect if either the -itemheight widget option or -height item option is specified. In any case, items are never shorter than the maximum height of an expand/collapse button.

Command-Line Switch: -rowproxy
Database Name: rowProxy
Database Class: RowProxy

If this option specifies a non empty value, it should be a screen distance in any of the forms acceptable to Tk_GetPixels. Then a 1 pixel thick horizontal line will be drawn at the specified screen distance from the top edge of the treectrl widget, which reaches from left to right of the treectrl widget and uses an inverting color (i.e black on lighter background, white on darker background). This line can be used to give the user a visual feedback during row resizing.

Command-Line Switch: -scrollmargin
Database Name: scrollMargin
Database Class: ScrollMargin

Specifies a positive screen distance in any of the forms acceptable to Tk_GetPixels. This option is used by the default bindings to determine how close to the edges of the contentbox the mouse pointer must be before scrolling occurs. Specifying a positive value is useful when items may be drag-and-dropped. Defaults to 0.

Command-Line Switch: -selectmode
Database Name: selectMode
Database Class: SelectMode

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 single, browse, multiple, or extended; the default value is browse.

Command-Line Switch: -showbuttons
Database Name: showButtons
Database Class: ShowButtons

Specifies a boolean value that determines whether this widget leaves indentation space to display the expand/collapse buttons next to items. The default value is true. The item option -button determines whether an item has a button. See also the widget options -showrootbutton and -showrootchildbuttons.

Command-Line Switch: -showheader
Database Name: showHeader
Database Class: ShowHeader

Specifies a boolean value that determines whether this widget should display the header line with the column names at the top of the widget. The default value is true.

Command-Line Switch: -showlines
Database Name: showLines
Database Class: ShowLines

Specifies a boolean value that determines whether this widget should draw the connecting lines between related items. The default value is true on Win32 and X11, false on Mac OS X and Gtk+.

Command-Line Switch: -showroot
Database Name: showRoot
Database Class: ShowRoot

Specifies a boolean value that determines whether this widget should draw the root item. By suppressing the drawing of the root item the widget can have multiple items that appear as toplevel items. The default value is true.

Command-Line Switch: -showrootbutton
Database Name: showRootButton
Database Class: ShowRootButton

Specifies a boolean value that determines whether this widget leaves indentation space to display the expand/collapse button next to the root item. The default value is false. The item option -button determines whether the root item has a button.

Command-Line Switch: -showrootchildbuttons
Database Name: showRootChildButtons
Database Class: ShowRootChildButtons

Specifies a boolean value that determines whether this widget should draw the expand/collapse buttons next to children of the root item. The default value is true.

Command-Line Switch: -showrootlines
Database Name: showRootLines
Database Class: ShowRootLines

Specifies a boolean value that determines whether this widget should draw the connecting lines between children of the root item. The default value is true.

Command-Line Switch: -treecolumn
Database Name: treeColumn
Database Class: TreeColumn

Specifies a column description that determines which column displays the expand/collapse buttons and connecting lines between items. The default is unspecified.

Command-Line Switch: -usetheme
Database Name: useTheme
Database Class: UseTheme

Specifies a boolean value that determines whether this widget should draw parts of itself using a platform-specific theme manager. The default is true.

Command-Line Switch: -width
Database Name: width
Database Class: Width

Specifies the desired width for the window in any of the forms acceptable to Tk_GetPixels. The default is 200 pixel. If this option is less than or equal to zero then the window will not request any size at all.

Command-Line Switch: -wrap
Database Name: wrap
Database Class: Wrap

Specifies whether items are arranged in a 1- or 2-dimensional layout.

If the value is an empty string (the default), then items are arranged from top to bottom (-orient=vertical) or from left to right (-orient=horizontal) in a 1-dimensional layout.

If the value is "N items", then no more than N items will appear in a vertical group (-orient=vertical) or horizontal group (-orient=horizontal).

If the value is "N pixels", then no vertical group of items will be taller than N pixels (-orient=vertical) or no horizontal group of items will be wider than N pixels (-orient=horizontal).

If the value is window, then a no vertical group of items will be taller than the window (-orient=vertical) or no horizontal group of items will be wider than the window (-orient=horizontal).

It is also possible to cause wrapping to occur on a per-item basis by using the item option -wrap. See the item create command for that option.

Command-Line Switch: -xscrolldelay
Database Name: xScrollDelay
Database Class: ScrollDelay

This option controls how quickly horizontal scrolling occurs while dragging the mouse with button 1 pressed. The value should be a list of 1 or 2 integers interpreted as milliseconds. If 2 values are specified, then the first value determines the intial delay after the first scroll, and the second value determines the delay for all scrolling after the first. If only 1 value is specified, each scroll takes place after that delay.

Command-Line Switch: -xscrollincrement
Database Name: xScrollIncrement
Database Class: ScrollIncrement

Specifies an increment for horizontal scrolling, in any of the usual forms permitted for screen distances. If the value of this option is greater than zero, the horizontal view in the window will be constrained so that the canvas x coordinate at the left edge of the window is always an even multiple of -xscrollincrement; furthermore, the units for scrolling (e.g., the change in view when the left and right arrows of a scrollbar are selected) will also be -xscrollincrement. If the value of this option is less than or equal to zero, then horizontal scrolling snaps to the left of an item, or part of an item if items are wider than the contentbox.

Command-Line Switch: -xscrollsmoothing
Database Name: xScrollSmoothing
Database Class: ScrollSmoothing

Specifies whether scrolling should be done as if -xscrollincrement=1 whenever scrolling is performed by non-unit amounts. When the value of this option is true and the xview command is called to scroll by "units", scrolling occurs according to the -xscrollincrement option, and all other scrolling is done as if the -xscrollincrement option was set to 1. The effect is that when dragging the scrollbar thumb scrolling is very smooth, but when clicking the scrollbar buttons scrolling is done in coarser increments. The default value is false.

Command-Line Switch: -yscrolldelay
Database Name: yScrollDelay
Database Class: ScrollDelay

This option controls how quickly vertical scrolling occurs while dragging the mouse with button 1 pressed. The value should be a list of 1 or 2 integers interpreted as milliseconds. If 2 values are specified, then the first value determines the intial delay after the first scroll, and the second value determines the delay for all scrolling after the first. If only 1 value is specified, each scroll takes place after that delay.

Command-Line Switch: -yscrollincrement
Database Name: yScrollIncrement
Database Class: ScrollIncrement

Specifies an increment for vertical scrolling, in any of the usual forms permitted for screen distances. If the value of this option is greater than zero, the vertical view in the window will be constrained so that the canvas y coordinate at the top edge of the window is always an even multiple of -yscrollincrement; furthermore, the units for scrolling (e.g., the change in view when the top and bottom arrows of a scrollbar are selected) will also be -yscrollincrement. If the value of this option is less than or equal to zero, then vertical scrolling snaps to the top of an item, or part of an item if items are taller than the contentbox.

Command-Line Switch: -yscrollsmoothing
Database Name: yScrollSmoothing
Database Class: ScrollSmoothing

Specifies whether scrolling should be done as if -yscrollincrement=1 whenever scrolling is performed by non-unit amounts. When the value of this option is true and the yview command is called to scroll by "units", scrolling occurs according to the -yscrollincrement option, and all other scrolling is done as if the -yscrollincrement option was set to 1. The effect is that when dragging the scrollbar thumb scrolling is very smooth, but when clicking the scrollbar buttons scrolling is done in coarser increments. The default value is false.

THE CANVAS

Throughout this manual page the term canvas is sometimes used. The canvas can be thought of as the virtual sheet of paper upon which all visible items are drawn. The treectrl window displays different areas of the canvas within its borders as the list is scrolled.

ITEM AND COLUMN TAGS

Columns and items may have any number of tags associated with them. A tag is just a string of characters, and it may take any form, including that of an integer, although the characters '(', ')', '&', '|', '^' and '!' should be avoided.

The same tag may be associated with many columns or items. This is commonly done to group items in various interesting ways; for example, in a file browser all directories might be given the tag "directory".

Tag expressions are used in column descriptions and item descriptions to specify which columns and items to operate on. A tag expression can be a single tag name or a logical expression of tags using operators '&&', '||', '^' and '!', and parenthesized subexpressions. For example:

.t item id "tag {(a && !b) || (!a && b)}"

or equivalently:

.t item id "tag {a ^ b}"

will return the unique ids of any items with either "a" or "b" tags, but not both.

Within a tag expression a tag name may be enclosed in double quotes to avoid special processing of the operator characters. For example:

.t item id {tag {"a&&b"||c}}

will return the unique ids of any items with either "a&&b" or "c" tags; in this example the && is not treated as an operator. A double-quote may be escaped within a quoted tag name using a backslash '\'.

Tag operators may be bypassed completely by setting the -columntagexpr and -itemtagexpr options. This can be useful if your application has column or item tags containing arbitrary text.

.t configure -itemtagexpr false
.t item delete "tag a&&b"

WIDGET COMMAND

The treectrl command creates a new Tcl command whose name is the same as the path name of the treectrl's window. This command may be used to invoke various operations on the widget. It has the following general form:

pathName option ?arg arg ...?

PathName is the name of the command, which is the same as the treectrl widget's path name. Option and the args determine the exact behavior of the command. The following commands are possible for treectrl widgets:

pathName activate itemDesc

Sets the active item to the one described by itemDesc, and switches on the state active for that item. The active item can be referred to by the item description active. If this command changes which item is active an <ActiveItem> event is generated. If the active item is deleted the root item becomes the new active item.

pathName bbox ?area?

Returns a list with four elements giving the bounding box (left, top, right and bottom) of an area of the window. If area is not specified, then the result is the bounding box of the entire window. If area is content, then the result is the part of the window not including borders, headers, or locked columns. If area is header, then the result is the part of the window not including borders where column titles are displayed. If area is left, then the result is the part of the window not including borders or headers where left-locked columns are displayed. If area is right, then the result is the part of the window not including borders or headers where right-locked columns are displayed.

If area is one of header.left, header.none or header.right then the area of the column headers occupied by columns with -lock=left, -lock=none or -lock=right is returned.

An empty string is returned if the display area has no height or width, which can be true for various reasons such as the window is too small, or the header is not displayed, or there aren't any locked columns.

pathName canvasx windowx

Translates the given window x-coordinate windowx in the treectrl to canvas coordinate space. The marquee command expects canvas coordinates.

pathName canvasy windowy

Translates the given window y-coordinate windowy in the treectrl to canvas coordinate space. The marquee command expects canvas coordinates.

pathName cget option

Returns the current value of the configuration option given by option. Option may have any of the values accepted by the tree command.

pathName collapse ?-recurse? ?itemDesc ...?

Deprecated. Use item collapse instead.

pathName column option column ?arg ...?

This command is used to manipulate the columns of the treectrl widget (see section COLUMNS below). The exact behavior of the command depends on the option argument that follows the column argument. The following forms of the command are supported:

pathName column bbox columnDesc

Returns a list with four elements giving the bounding box of the header of the column specified by the column description columnDesc. The returned coordinates are relative to the top-left corner of the widget. If the column option -visible=false or if the widget option -showheader=false, then an empty list is returned.

pathName column cget columnDesc option

This command returns the current value of the option named option for the column specified by the column description columnDesc, ColumnDesc may also be the string tail to specify the tail column. Option may have any of the values accepted by the column configure widget command.

pathName column configure columnDesc ?option? ?value? ?option value ...?

This command is similar to the configure widget command except that it modifies options associated with the columns specified by the column description columnDesc instead of modifying options for the overall treectrl widget. ColumnDesc may be the string tail to specify the tail column. If columnDesc refers to more than one column, then at least one option-value pair must be given. If no option is specified, the command returns a list describing all of the available options for columnDesc (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, 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 option is specified). If one or more option-value pairs are specified, then the command modifies the given option(s) to have the given value(s) for columnDesc; in this case the command returns an empty string.

See COLUMNS below for details on the options available for columns.

For compatibility with older versions of treectrl (which did not support more than one row of column headers) any of the configuration options mentioned in the HEADERS section, such as -arrow, -text, etc, may be passed to the top header-row through this command.

pathName column compare column1 op column2

For both column descriptions column1 and column2 the index is retrieved (as returned from the column order widget command). Then these indexes are compared using the operator op, which must be either <, <=, ==, >=, >, or !=. The return value of this command is 1 if the comparison evaluated to true, 0 otherwise.

pathName column count ?columnDesc?

If no additional arguments are given, the result is a decimal string giving the number of columns created by the column create widget command which haven't been deleted by the column delete widget command; in this case the tail column is not counted. If columnDesc is given, then the result is the number of columns that match that column description.

pathName column create ?option value ...?

This command creates a new column in the treectrl widget. The new column is placed to the right of all other columns (except the tail column). Any option-value arguments configure the new column according to the column configure command. The return value is the unique identifier of the new column.

pathName column delete first ?last?

Deletes the specified column(s). First and last must be valid column descriptions. If both first and last are specified, then they may refer to a single column only. The tail column cannot be deleted and it is an error to specify it. The order of first and last doesn't matter, and first may be equal to last.

pathName column dragcget option

Deprecated. Use header dragcget instead.

pathName column dragconfigure ?option? ?value? ?option value ...?

Deprecated. Use header dragconfigure instead.

pathName column index columnDesc

Deprecated. Use column id instead.

pathName column id columnDesc

This command resolves the column description columnDesc into a list of unique column identifiers. If the column(s) described by columnDesc don't exist, this command returns an empty list.

pathName column list ?-visible?

This command returns a list of identifiers for every column (except the tail) from left to right. If -visible is given, only columns whose -visible option is true are returned.

pathName column move columnDesc beforeDesc

Moves the column specified by columnDesc to the left of the column specified by beforeDesc. Both columnDesc and beforeDesc must be valid column descriptions. If beforeDesc is the string tail, the column columnDesc will become the last column.

pathName column neededwidth columnDesc

This command returns a decimal string giving the needed width of the column specified by the column description columnDesc. The needed width is the maximum of the width of the column header and the width of the widest style in any visible item.

When an item style or column header spans multiple columns, the needed width of a column is affected by the widths of other columns in the span, in which case the result of this command isn't particularly useful.

pathName column order columnDesc ?-visible?

This command returns a decimal string giving the position of the column specified by the column description columnDesc in the list of columns starting from zero for the leftmost column. If -visible is given, only columns whose -visible option is true are considered, and -1 is returned if columnDesc's -visible option is false.

pathName column tag option ?arg arg ...?

This command is used to manipulate tags on columns. The exact behavior of the command depends on the option argument that follows the column tag argument. The following forms of the command are supported:

pathName column tag add columnDesc tagList

Adds each tag in tagList to the columns specified by the column description columnDesc. Duplicate tags are ignored. The list of tags for a column can also be changed via a column's -tags option.

pathName column tag expr columnDesc tagExpr

Evaluates the tag expression tagExpr against every column specified by the column description columnDesc. The result is 1 if the tag expression evaluates to true for every column, 0 otherwise.

pathName column tag names columnDesc

Returns a list of tag names assigned to the columns specified by the column description columnDesc. The result is the union of any tags assigned to the columns.

pathName column tag remove columnDesc tagList

Removes each tag in tagList from the columns specified by the column description columnDesc. It is not an error if any of the columns do not use any of the tags. The list of tags for a column can also be changed via a column's -tags option.

pathName column width columnDesc

This command returns a decimal string giving the width in pixels of the column specified by the column description columnDesc, even if the treectrl is configured to not display the column headers by means of the -showheader option.

pathName compare itemDesc1 op itemDesc2

Deprecated. Use the item compare command instead.

pathName configure ?option? ?value option value ...?

Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, 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 option is specified). If one or more option-value 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. Option may have any of the values accepted by the treectrl command.

pathName contentbox

Returns a list with four elements giving the bounding box of the screen area used to display items. This is the area of the window not including borders, column headers, or locked columns. An empty string is returned if the display area has no height or width, which can happen if the window is too small. The result of this command is the same as that of bbox content.

pathName debug option ?arg arg ...?

This command is used to facilitate debugging of the treectrl widget. The exact behavior of the command depends on the option argument that follows the debug argument. The following forms of the command are supported:

pathName debug alloc

Returns a string giving partial statistics on memory allocations, if the package was built with TREECTRL_DEBUG defined.

pathName debug cget option

This command returns the current value of the debugging option named option. Option may have any of the values accepted by the debug configure widget command.

pathName debug configure ?option? ?value? ?option value ...?

This command is similar to the configure widget command except that it modifies debugging options instead of modifying options for the overall treectrl widget. If no option is specified, the command returns a list describing all of the available debugging options (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, 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 option is specified). If one or more option-value pairs are specified, then the command modifies the given debugging option(s) to have the given value(s); in this case the command returns an empty string.

The following debugging options are supported:

-displaydelay millis

Specifies a time duration in milliseconds, which should be waited after something has been drawn to the screen. Setting this option has only an effect, if the debugging options -enable and -display are switched on.

-data boolean

If this option is switched on (together with the debugging option -enable), at various places a consistence check on the internal data structure is made (e.g. for every item is checked, if the registered number of children is equal to the number of child items). If an inconsistency was found, a Tcl background error is raised.

-display boolean

If this option is switched on (together with the debugging option -enable), at varios places additional debugging output is printed to stdout.

-drawcolor color

When specified, areas of the window are painted with this color when drawing in those areas is about to occur. Setting this option has only an effect if the debugging options -enable and -display are switched on.

-enable boolean

All other debugging options only take effect if this option is also switched on.

-erasecolor color

When specified, areas of the window which have been marked as "invalid" (for example, when part of the window is exposed) are painted with this color. If you use an unusual color for this option (like pink), superflous screen redraws can be spotted more easily. Setting this option has only an effect if the debugging options -enable and -display are switched on.

-span boolean

Debugging related to column spanning.

-textlayout boolean

Debugging related to text-element layout.

pathName debug dinfo option

Returns a string describing display-related stuff. Option must be one of alloc, ditem, onscreen or range.

pathName debug expose x1 y1 x2 y2

Causes the area of the window bounded by the given window-coords to be marked as invalid. This simulates uncovering part of the window.

pathName depth ?itemDesc?

If the additional argument itemDesc is given, then the result is a decimal string giving the depth of the item described by itemDesc. If no itemDesc is specified, then the maximum depth of all items in the treectrl widget is returned instead. Depth is defined as the number of ancestors an item has.

pathName dragimage option ?arg ...?

This command is used to manipulate the drag image, which is used to provide feedback when items are drag-and-dropped within the window. The drag image is displayed as the dotted outlines of one or more items, columns and/or elements. The exact behavior of the command depends on the option argument that follows the dragimage argument. The following forms of the command are supported:

pathName dragimage add itemDesc ?column? ?element?

Adds the shapes of the item described by itemDesc to the shapes of the dragimage. Specifying additional arguments reduces the number of rectangles that are added to the dragimage. If no additional arguments is specified, for every element of the item in every column a dotted rectangles is added. If column is specified, all elements in other columns are ignored. If also element is specified, only a rectangle for this one element of the specified item in the given column is added.

pathName dragimage cget option

This command returns the current value of the dragimage option named option. Option may have any of the values accepted by the dragimage configure widget command.

pathName dragimage clear

Removes all shapes (if there are any) from the dragimage. This command does not modify the dragimage offset.

pathName dragimage configure ?option? ?value? ?option value ...?

This command is similar to the configure widget command except that it modifies the dragimage options instead of modifying options for the overall treectrl widget. If no option is specified, the command returns a list describing all of the available dragimage options (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named dragimage option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given dragimage option(s) to have the given value(s); in this case the command returns an empty string.

The following dragimage options are supported:

-visible boolean

Specifies a boolean value which determines whether the dragimage should currently be visible.

pathName dragimage offset ?x y?

Returns a list containing the x and y offsets of the dragimage, if no additional arguments are specified. The dragimage offset is the screen distance the image is displayed at relative to the item(s) its shape is derived from. If two coordinates are specified, sets the dragimage offset to the given coordinates x and y.

pathName element option ?element? ?arg arg ...?

This command is used to manipulate elements (see ELEMENTS AND STYLES below). The exact behavior of the command depends on the option argument that follows the element argument. The following forms of the command are supported:

pathName element cget element option

This command returns the current value of the option named option associated with the element given by element. Option may have any of the values accepted by the element configure widget command.

This command also accepts the -statedomain option.

pathName element configure element ?option? ?value? ?option value ...?

This command is similar to the configure widget command except that it modifies options associated with the element given by element instead of modifying options for the overall treectrl widget. If no option is specified, the command returns a list describing all of the available options for element (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, 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 option is specified). If one or more option-value pairs are specified, then the command modifies the given option(s) to have the given value(s) in element; in this case the command returns an empty string. See ELEMENTS AND STYLES below for details on the options available for elements.

pathName element create name type ?option value ...?

Creates a new master element of type type with the unique user-defined name name and configures it with zero or more option/value pairs. See the subsections on individual element types in ELEMENTS AND STYLES for the options that are valid for each type of element. This command returns the name of the new element (the same as the name argument).

This command also accepts the -statedomain option with a value of either header or item to specify where this element will be displayed.

pathName element delete ?element ...?

Deletes each of the named elements and returns an empty string. If an element is deleted while it is still configured as an element of one or more styles by means of the style elements widget command, it is also removed from the element lists of these styles.

pathName element names

Returns a list containing the names of all existing elements.

pathName element perstate element option stateList

This command returns the value of the per-state option named option for element for a certain state. StateList is a list of state names (static and dynamic, see STATES) which specifies the state to use.

pathName element type element

Returns the type of the element given by element, such as rect or text.

pathName expand ?-recurse? ?itemDesc ...?

Deprecated. Use item expand instead.

pathName gradient option ?arg ...?

This command is used to manipulate color gradients. See GRADIENTS for more information about using gradients. The exact behavior of the command depends on the option argument that follows the gradient argument. The following forms of the command are supported:

pathName gradient cget gradient option

Returns the current value of the configuration option for the gradient specified by gradient whose name is option. Option may have any of the values accepted by the gradient configure command.

pathName gradient configure gradient ?option value ...?

If no option is specified, the command returns a list describing all of the available gradient options (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named gradient option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given gradient option(s) to have the given value(s); in this case the command returns an empty string.

The following options are supported (see gradient create for the meaning of each option):

-bottom coordSpec
-left coordSpec
-orient direction
-right coordSpec
-steps stepCount
-stops stopsList
-top coordSpec
pathName gradient create name ?option value ...?

Creates a new gradient with the name name, which must be a unique name not used by another gradient created by this treectrl widget.

The following options are supported:

-bottom coordSpec
-left coordSpec
-right coordSpec
-top coordSpec

Each of these options specifies one edge of the gradient brush. If the option is specified as an empty string (the default), the gradient brush's edge is the same as that of whatever rectangle is being painted using the gradient. See GRADIENT COORDINATES for details on gradient brush coordinates.

The format of each of these options is a list of 2 or more values {value coordType ?arg ...?}, where value is a floating point number (usually from 0.0 to 1.0) and coordType is one of area, canvas, column or item. The area keyword must be followed by one of the same area names that the bbox command accepts. The column keyword may be followed by a column description specifying exactly one column. The item keyword may be followed by an item description specifying exactly one item.

-orient direction

This option specifies the direction a linear gradient changes color in. Must be either horizontal (the default) or vertical or an abbreviation of one of these.

-steps stepCount

Specifies the number of bands of color drawn for each color stop described by the -stops option. The default value is 1, the maximum is 25. This option has no effect if gradients are drawn using something better than Tk API calls. See GRADIENTS for more on this.

-stops stopsList

Specifies the color stops along this gradient. The argument stopsList has the following form:

{{offset color ?opacity?} {offset color ?opacity?} ...}

Each offset is a floating point number from 0.0 to 1.0 specifying the distance from the start of the gradient where the color begins. Each color is a Tk color name or description. Each optional opacity is a floating point number from 0.0 to 1.0 specifying how transparent the gradient is.

If stopsList is non-empty there must be at least two stops specified, and the first offset must be 0.0 and the last offset must be 1.0. Any other stop offsets must be listed in increasing order. Specifying opacity has no effect if gradients are drawn using Tk API calls. See GRADIENTS for more on this.

pathName gradient delete ?name ...?

Deletes each gradient specified by name. If the gradient is still being used then it is not actually deleted until all elements etc using the gradient have stopped using it. A deleted-but-in-use gradient is not recognized by the various gradient commands. Creating a new gradient with the same name as a deleted-but-in-use gradient resurrects the deleted gradient.

pathName gradient names

Returns a list of names of all the gradients that have been created by this treectrl widget.

pathName gradient native ?preference?

Without any arguments, this command returns a boolean indicating whether or not the platform supports native transparent gradients. The preference argument is a boolean that indicates whether native gradients should be used; this can be used to test the appearance of the application.

pathName header option ?arg ...?

This command is used to manipulate column headers. The exact behavior of the command depends on the option argument that follows the header argument. The following forms of the command are supported:

pathName header bbox headerDesc ?column? ?element?

See the item bbox command.

pathName header compare headerDesc1 op headerDesc2

See the item compare command.

pathName header configure headerDesc ?arg ...?

There are two forms of this command distinguished by whether or not a column description appears after the headerDesc argument. If the first argument after headerDesc begins with a '-' character it is assumed to be an option name, not a column description, in which case the command applies to the header-row. If the first argument after headerDesc does not being with a '-' it is assumed to be a column description, in which case the command applies to a header-column.

pathName header configure headerDesc ?option? ?value? ?option value ...?

If no option is specified, returns a list describing all of the available options for the header given by headerDesc (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, 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 option is specified).

If one or more option-value pairs are specified, then the command modifies the given option(s) to have the given value(s); in this case the command returns an empty string. This is the only case where headerDesc may refer to multiple header-rows.

The following options are supported by this command (see header create for the meaning of each option):

-height height
-tags tagList
-visible boolean
pathName header configure headerDesc column ?option? ?value? ?option value ...?

If no option is specified, returns a list describing all of the available options for the single column column of the header-row given by headerDesc (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, 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 option is specified).

If one or more option-value pairs are specified, then the command modifies the given option(s) to have the given value(s); in this case the command returns an empty string. This is the only case where both headerDesc may refer to multiple header-rows and column may refer to multiple header-columns.

The following options are supported by this command (see HEADERS) for the meaning of each option):

-arrow direction
-arrowbitmap bitmap
-arrowgravity direction
-arrowimage image
-arrowpadx amount
-arrowpady amount
-arrowside side
-background color
-bitmap bitmap
-borderwidth size
-button boolean
-font fontName
-image image
-imagepadx amount
-imagepady amount
-justify justification
-state state
-text text
-textcolor color
-textlines count
-textpadx amount
-textpady amount
pathName header count ?headerDesc?

If no additional arguments are given, the result is a decimal string giving the number of header-rows created by the header create widget command which haven't been deleted by the header delete widget command, plus 1 for the ever-present top header-row created along with the widget. If the optional argument headerDesc is given, then the result is the number of header-rows that match that header description.

pathName header create ?option value?

Creates a new header-row and returns its unique identifier. The following configuration options are supported:

-height height

Specifies a fixed height for the header-row in any of the forms acceptable to Tk_GetPixels. Must be >= 0. If height is zero then the header-row's height is the maximum height of all of its column headers. Defaults to 0.

-tags tagList

TagList is a list of tag names to be added to the new header-row. The header tag command can also be used to manipulate this list of tags.

-visible boolean

Boolean must have one of the forms accepted by Tcl_GetBoolean. It indicates whether or not the header-row should be displayed. If the widget option -showheader is false then the header-row will not be displayed regardless of the value of this option.

pathName header delete headerDesc

Deletes the header-rows given by the header description headerDesc. Attempts to delete the ever-present top header-row are ignored without raising an error.

pathName header dragcget ?arg ...?

There are two forms of this command distinguished by whether or not a header description appears as the first argument. If the first argument begins with a '-' character it is assumed to be an option name, not a header description, in which case the command applies to the header-drag-and-drop options for the widget. If the first argument does not being with a '-' it is assumed to be a header description, in which case the command applies to a header-row.

pathName header dragcget option

This command returns the current value of the header-drag-and-drop option named option for the widget. The following configuration options are supported (see header dragconfigure for the meaning of each option):

-enable boolean
-imagealpha alpha
-imagecolor background
-imagecolumn column
-imageoffset offset
-imagespan count
-indicatorcolor color
-indicatorcolumn column
-indicatorside side
-indicatorspan count
pathName header dragcget headerDesc option

This command returns the current value of the header-drag-and-drop option named option for a header-row. The following configuration options are supported (see header dragconfigure for the meaning of each option):

-draw boolean
-enable boolean
pathName header dragconfigure ?arg ...?

There are two forms of this command distinguished by whether or not a header description appears as the first argument. If the first argument begins with a '-' character it is assumed to be an option name, not a header description, in which case the command applies to the header-drag-and-drop options for the widget. If the first argument does not being with a '-' it is assumed to be a header description, in which case the command applies to a header-row.

pathName header dragconfigure ?option? ?value? ?option value ...?

This command queries and sets header-drag-and-drop options for the widget, not for individual header-rows. The following configuration options are supported:

-enable boolean

Controls whether the user is allowed to rearrange columns by drag-and-drop. The default is false. Each header-row also has an -enable dragconfigure option.

-imagealpha alpha

Alpha is an integer from 0 (invisible) to 255 (opaque) controlling the transparency of the drag image. Any value outside this range is clipped. The default is 200.

-imagecolor background

Unused.

-imagecolumn column

Column specifies the column to create the drag image from.

-imageoffset offset

Offset is the horizontal screen distance the drag image is offset from its starting position.

-imagespan count

Count is the number of columns, starting with -imagecolumn, that will be dragged as a group.

-indicatorcolor color

Unused.

-indicatorcolumn column

The 2-pixel-thick line will be drawn over the left or right edge of column.

-indicatorside side

Unused.

-indicatorspan count

Count is the number of columns, starting with -indicatorcolumn, that will be displaced as a group by the dragged column(s)

pathName header dragconfigure header ?option? ?value? ?option value ...?

This command queries and sets header-drag-and-drop options for header-rows, not for the widget as a whole. The following configuration options are supported:

-draw boolean

Controls whether a header-row displays any feedback during header drag-and-drop. The default is true.

-enable boolean

Controls whether clicking and dragging in this header-row initiates drag-and-drop. The default is true. If the -enable option for the widget is false (see above) then this option has no effect.

pathName header element ?arg ...?

See the item element command.

pathName header id headerDesc

This command resolves the header description headerDesc into a list of unique header-row identifiers. If headerDesc doesn't refer to any existing header-rows, then this command returns an empty list.

pathName header image headerDesc ?column? ?image? ?column image ...?

The behavior of this command depends on whether or not a column header was assigned a style containing an image element. If a column header has no style or no style with an image element then this command operates on the same -image option as header configure. Otherwise this command operates on the -image option of the first image element in a column header's style. See the item image command.

pathName header span headerDesc ?column? ?numColumns? ?column numColumns ...?

See the item span command.

pathName header state command headerDesc ?arg ...?

See the item state command.

pathName header style command headerDesc ?arg ...?

See the item style command.

pathName header text headerDesc ?column? ?text? ?column text ...?

The behavior of this command depends on whether or not a column header was assigned a style containing a text element. If a column header has no style or no style with a text element then this command operates on the same -text option as header configure. Otherwise this command operates on the -text option of the first text element in a column header's style. See item text.

pathName header tag command headerDesc ?arg ...?

See the item tag command.

pathName identify ?-array varName? x y

This command returns information about the what is displayed at the given window coordinates x and y. When the -array option is used to specify the name of an array variable, elements of the array variable are set as follows:

  1. If the coordinates are outside the window, over the borders, or over any whitespace in the window, then:

    $varName(where) is ""

  2. If the coordinates are over a column header, then:

    $varName(where) is header

    $varName(header) is the unique id of the header-row

    $varName(column) is the unique id of the column

    $varName(element) is the name of an element, or ""

    $varName(side) is left or right if the coordinates are close to the edge of the column header, otherwise ""

  3. If the coordinates are over an item, then:

    $varName(where) is item

    $varName(item) is the unique id of the item

    $varName(column) is the unique id of the column

    $varName(element) is the name of an element, or ""

    $varName(button) is a boolean indicating whether or not the coordinates are over the item's expand/collapse button

    $varName(line) is the unique id of an ancestor of the item (but not the parent of the item) if the coordinates are over a line descending from that ancestor. If the coordinates are not over such a line then $varName(line) is "". This is used to collapse the ancestor when the line is clicked on.

When the -array option is not used, this command returns a list describing what is displayed at the given window coordinates. The format of this list can be like one of the following:

  1. {}

    An empty list is returned if the coordinates are outside the window, over the borders, or over any whitespace in the window.

  2. header C ?left|right?

    header C elem E ?left|right?

    header H column C ?left|right?

    header H column C elem E ?left|right?

    Only when there is more than one header-row is there a unique id of a header-row H followed by the keyword column. This is for compatibility with older versions when there was only one row of column headers allowed.

  3. item I column C

  4. item I column C elem E

  5. item I button

    This is the result when the coordinates are over the expand/collapse button next to an item.

  6. item I line I2

    This is the result when the coordinates are over a line descending from an ancestor I2 of the item I (but not the parent of that item). This is used to collapse the ancestor when the line is clicked on.

pathName index itemDesc

Deprecated. Use item id instead.

pathName item option ?arg ...?

This command is used to manipulate items. The exact behavior of the command depends on the option argument that follows the item argument. The following forms of the command are supported:

pathName item ancestors itemDesc

Returns a list containing the item ids of the ancestors of the item specified by itemDesc. The first list value is the parent, the second is the parent's parent, an so on. The last list value will be the root item if itemDesc is a descendant of the root item.

pathName item bbox itemDesc ?column? ?element?

Returns a list with four elements giving the bounding box of the item described by itemDesc. If no further argument is specified, the bbox spans the area of the item over all non-locked columns. If a column is specified, only the area of the item in this column is considered. If an additional element is specified, the area of this element in column of the specified item is returned. The returned coordinates are relative to the top-left corner of the widget. If the item is not visible for any reason, the result in an empty string.

pathName item buttonstate itemDesc ?state?

If state is specified, this command sets the state of the expand/collapse button for the single item specified by itemDesc. The state argument may be one of active, normal or pressed. The current (or newly-set) state of the button is returned. The button state is used by the system theme, if any, to change the appearance of the button.

pathName item cget itemDesc option

Returns the current value of the configuration option for the item specified by itemDesc whose name is option. Option may have any of the values accepted by the item configure command.

pathName item children itemDesc

Returns a list containing the item ids of all children of the item specified by itemDesc in the correct order from the first child to the last child.

pathName item collapse itemDesc ?-animate? ?-recurse?

Switches off the open state of the item(s) described by itemDesc. If an item has descendants, then they are no longer displayed. If an item is already closed, then this command has no effect on that item. If -animate is specified, then the item's button will animate as it transitions between states if the theme supports it; in this case only one item may be specified. If -recurse is specified, then all descendants of the items described by itemDesc will also be collapsed. For every item that actually will be collapsed, two events are generated: a <Collapse-before> event before the item state is changed, and a <Collapse-after> event after the item state was changed.

pathName item compare itemDesc1 op itemDesc2

From both items described by the itemDescs the index is retrieved (as returned from the item order widget command). Then these indexes are compared using the operator op, which must be either <, <=, ==, >=, >, or !=. The return value of this command is 1 if the comparison evaluated to true, 0 otherwise.

pathName item complex itemDesc ?list...?

This horrible command is now deprecated. Use item element configure instead. For every column of the treectrl there may be specified one list. Each list should look like this:

{ {element option value ...} {element option value ...} ...}

Every option must be known by the element's type (see ELEMENTS AND STYLES below). Each option will be set to value for the element in this one column in this item.

pathName item configure itemDesc ?option? ?value? ?option value ...?

If no option is specified, returns a list describing all of the available options for the item given by itemDesc (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, 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 option is specified).

If one or more option-value pairs are specified, then the command modifies the given item option(s) to have the given value(s); in this case the command returns an empty string. This is the only case where itemDesc may refer to multiple items.

The following options are supported by this command (see item create for the meaning of each option):

-button boolean|auto
-height height
-tags tagList
-visible boolean
-wrap boolean
pathName item count ?itemDesc?

If no additional arguments are given, the result is a decimal string giving the number of items created by the item create widget command which haven't been deleted by the item delete widget command, plus 1 for the ever-present root item. If the optional argument itemDesc is given, then the result is the number of items that match that item description.

pathName item create ?option value ...?

Creates some new items and optionally returns a list of unique identifiers for those items. The new items have the states open and enabled set by default. If the treectrl widget currently has the focus, the state focus is also set.

The following options are supported by this command:

-button boolean|auto

The value of this option must have one of the forms accepted by Tcl_GetBoolean or be the word auto (or any abbreviation of it). It indicates whether or not an expand/collapse button should be drawn next to the item, typically to indicate that the item has children. If the value of this option is auto, then a button is displayed next to the item whenever the item has any children whose item option -visible is true. The button will only be displayed if:

  1. the column specified by the treectrl option -treecolumn is visible, and

  2. the treectrl option -showbuttons is true, and

  3. for the root item, the treectrl option -showrootbutton is true, and

  4. for immediate children of the root item, the treectrl option -showrootchildbuttons is true.

-count numItems

Specifies the number of items to create. Must be >= 0. Defaults to 1.

-enabled boolean

Specifies whether the items should be enabled. Default is true.

-height height

Specifies a fixed height in any of the forms acceptable to Tk_GetPixels. Must be >= 0. If height is zero then the item's height is unspecified. Defaults to 0. See also the widget options -itemheight and -minitemheight.

-nextsibling itemDesc

Specifies the item before which the new items will be inserted. The new items will have the same parent as itemDesc.

-open boolean

Specifies whether the items should be open or closed. Default is true.

-parent itemDesc

Specifies the item which the new items will be the children of. The new items will be appended to the list of children of itemDesc. When no parent is specified, the new items are orphan items (see the widget command orphans) and will not be displayed in the list.

-prevsibling itemDesc

Specifies the item after which the new items will be inserted. The new items will have the same parent as itemDesc.

-returnid boolean

Specifies whether or not to return a list of item identifiers for the newly created items. Specifying false is useful when creating a large number of items in the console or to improve performance. Default is true.

-tags tagList

TagList is a list of tag names to be added to the new items. The item tag command can also be used to manipulate this list of tags.

-visible boolean

Boolean must have one of the forms accepted by Tcl_GetBoolean. It indicates that the item should be displayed in the list. The item will only be displayed if:

  1. each ancestor is a descendant of the root item (not an orphan), and

  2. each ancestor's -visible option is true

-wrap boolean

Boolean must have one of the forms accepted by Tcl_GetBoolean. It indicates that this item should be the first one in a horizontal range or vertical range of items. See also the widget option -wrap.

pathName item delete first ?last?

Deletes the specified item(s). First and last must be valid item descriptions. If last isn't specified, then first may specify multiple items. If both first and last are specified, they must each decribe a single item with a common ancestor; then the range of items between first and last is deleted. The order of first and last doesn't matter.

Deleting an item deletes any child items of the deleted item recursively. If the current active item is deleted, the root item becomes the new active item. If the current selection anchor item is deleted, the root item becomes the new anchor item. There is no way to delete the root item of the treectrl widget; in all cases the specification of the root item is ignored.

For each call to this command, two events may be generated. If any of the deleted items are selected, then they are removed from the selection and a <Selection> event is generated just before the items are deleted. If any items are going to be deleted, then an <ItemDelete> event is generated just before the items are deleted.

pathName item descendants itemDesc

Returns a list containing the item ids of the descendants of the item specified by itemDesc, i.e. the children, grandchildren, great-grandchildren etc, of the item.

pathName item dump itemDesc

Debug command. Returns a list with 4 words in the form index index indexVis indexVis.

pathName item element command itemDesc column element ?arg ...?

This command is used to manipulate elements of the item. The exact behavior of the command depends on the command argument that follows the element argument. The following forms of the command are supported:

pathName item element actual itemDesc column element option

Deprecated. Use item element perstate instead.

pathName item element cget itemDesc column element option

This command returns the value of the option named option associated with element inside column of the item described by itemDesc, if it was already configured for the actual item. Option may have any of the values accepted by the type of the specified element (see ELEMENTS AND STYLES below)

pathName item element configure itemDesc column element ?option? ?value? ?option value ...?

This command modifies configuration options for an element in a column of an item. If no option is specified, the command returns a list describing all of the available options for the element (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, 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 option is specified).

If one or more option-value pairs are specified, then the command modifies the given option(s) to have the given value(s) in the element inside column of the item(s) described by itemDesc; in this case the command returns an empty string. This is the only case where itemDesc may refer to multiple items.

It is possible to configure multiple elements in multiple columns with a single call. To configure another element in the same column, append a '+' argument followed by the element name. To configure elements in another column, append a ',' argument followed by the column. For example:

.t item element configure $I \
	$C1 $E1 -text "hello" + $E2 -text "world" , \
	$C2 $E3 -fill Blue , \
	$C3 $E1 -text "apples and oranges"

Each of the column description arguments to this command may refer to multiple columns if at least one option-value pair is given.

pathName item element perstate itemDesc column element option ?stateList?

This command returns the current value of the per-state option named option for element inside column of the item described by itemDesc. If stateList is specified, the list of state names (static and dynamic, see STATES) is used in place of the current state for item and column.

pathName item enabled itemDesc ?boolean?

Returns 1 if the item described by itemDesc has the state enabled switched on, 0 otherwise. If boolean is specified, then the enabled state of every item described by the item description itemDesc is set accordingly. New items are enabled by default when created. Disabled items cannot be selected, and are ignored by the default key-navigation and mouse bindings.

pathName item expand itemDesc ?-animate? ?-recurse?

Switches on the open state of the item(s) described by itemDesc. If an item has descendants, then they are now displayed. If an item is already open, then this command has no effect on that item. If -animate is specified, then the item's button will animate as it transitions between states if the theme supports it; in this case only one item may be specified. If -recurse is specified, then all descendants of the items described by itemDesc will also be expanded. For every item that actually will be expanded, two events are generated: an <Expand-before> event before the item state is changed, and an <Expand-after> event after the item state was changed.

pathName item firstchild parent ?child?

If child is not specified, returns the item id of the first child of the item described by parent. If child is specified, it must describe an item that is neither the root item nor an ancestor of parent. Then it will become the new first child of parent.

pathName item id itemDesc

This command resolves the item description itemDesc into a list of unique item identifiers. If itemDesc doesn't refer to any existing items, then this command returns an empty list.

pathName item image itemDesc ?column? ?image? ?column image ...?

This command sets or retrieves the value of the per-state -image option for the first image element in one or more columns. If no column is specified, this command returns a list of values, one per column. If no image is specified, this command returns the value for column.

If one or more column-image pairs is specified, then the value of the -image option in each column is set to image. In this case itemDesc may refer to multiple items and each column may refer to multiple columns.

Note that this command is provided as a convenience. Use the item element configure or item element cget commands if you want to set or retrieve the value of the -image option for a specific image element.

pathName item isancestor itemDesc descendant

Returns 1 if the item described by itemDesc is a direct or indirect parent of the item decribed by descendant, 0 otherwise.

pathName item isopen itemDesc

Returns 1 if the item described by itemDesc has the state open switched on, 0 otherwise.

pathName item lastchild parent ?child?

If child is not specified, returns the item id of the last child of the item described by parent. If child is specified, it must describe an item that is not an ancestor of parent. Then it will become the new last child of parent.

pathName item nextsibling sibling ?next?

If next is not specified, returns the item id of the next sibling of the item described by sibling. If next is specified, it must describe an item that is not an ancestor of sibling. Then it will become the new next sibling of sibling.

pathName item numchildren itemDesc

Returns the number of children of the item described by itemDesc.

pathName item order itemDesc ?-visible?

This command returns the position of the item itemDesc relative to its toplevel ancestor (usually the root item, unless the ancestor is an orphan). If you imagine all the items flattened into a vertical list, the result of this command is the row the item falls in. If the optional argument -visible is given, only the items whose ancestors are expanded, and whose -visible option is true, get counted; in this case -1 is returned if the item is not visible.

pathName item parent itemDesc

Returns the item id of the parent of the item described by itemDesc.

pathName item prevsibling sibling ?prev?

If prev is not specified, returns the item id of the previous sibling of the item described by sibling. If prev is specified, it must describe an item that is not an ancestor of sibling. Then it will become the new previous sibling of sibling.

pathName item range first last

Returns a list containing the item ids of all items in the range between first and last, inclusive. The order between first and last doesn't matter, and the result is always sorted by the increasing order of the items (as returned by the item order command). The items specified by first and last must share a common ancestor.

pathName item remove itemDesc

Removes the item described by itemDesc from the list of children of its parent, so that it will become an orphan.

pathName item rnc itemDesc

Returns a list of two integers, which corresponds to the row and column of the item described by itemDesc. The row and column corresponds to the on-screen arrangement of items as determined by the -orient and -wrap options. If the item is not displayed, this command returns an empty string.

pathName item sort itemDesc ?option ...?

Sorts the children of the item described by itemDesc, and redisplays the tree with the items in the new order.

The range of items which should be sorted can be restricted by means of the -first and/or -last options, which should be children of the item described by itemDesc; the order between these two limiting items doesn't matter.

The sort column can be specified by means of the -column option; this option can be used repeatedly to define a multicolumn sort. The sorting is done by looking at the text of the element specified by the -element option, which must be a text element defined in the style of the sorting column, by default the first text element is used.

If the -notreally option is specified, no rearranging of the items is done; instead the sorted items are returned as result of the command.

By default ASCII sorting is used with the result returned in increasing order. Any of the following options may be specified to control the sorting process of the previously specified column (unique abbreviations are accepted):

-ascii

Use string comparison with ASCII collation order. This is the default.

-command command

Use command as a comparison command. To compare two items, evaluate a Tcl script consisting of command with the numerical ids of the two items appended as additional arguments. The script should return an integer less than, equal to, or greater than zero if the first item is to be considered less than, equal to, or greater than the second, respectively.

-decreasing

Sort the items in decreasing order ("largest" items first).

-dictionary

Use dictionary-style comparison. This is the same as -ascii except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, in -dictionary mode, bigBoy sorts between bigbang and bigboy, and x10y sorts between x9y and x11y.

-increasing

Sort the items in increasing order ("smallest" items first). This is the default.

-integer

Convert to integers and use integer comparison.

-real

Convert to floating-point values and use floating comparison.

pathName item span itemDesc ?column? ?numColumns? ?column numColumns ...?

This command sets or retrieves the number of columns that a style covers. If no column is specified, the return value is a list of spans, one per column. If no numColumns is specified, the return value is the span for column.

If one or more column-numColumns pairs is specified, the span for each column is set to numColumns. In this case itemDesc may refer to multiple items and each column may refer to multiple columns.

pathName item state command itemDesc ?arg ...?

This command is used to manipulate the states of an item. The exact behavior of the command depends on the command argument that follows the style argument. The following forms of the command are supported:

pathName item state define stateName

Defines a new state with the name stateName, which must not be the name of an existing state.

pathName item state forcolumn itemDesc column ?stateDescList?

Just like item state set but manipulates dynamic states for a single item column, not the item as a whole. If stateDescList is unspecified, this command returns a list containing the names of all the dynamic states which are switched on in column.

If stateDescList is specified, then itemDesc may refer to multiple items and column may refer to multiple columns.

pathName item state get itemDesc ?stateName?

If no stateName is specified, returns a list containing the names of all (static and dynamic) states which are currently switched on for the item described by itemDesc. If a stateName is specified, 1 is returned if the specified state is currently switched on for the item, 0 otherwise.

pathName item state linkage stateName

Returns a string indicating whether the specified state is user-defined by means of the item state define widget command (dynamic) or predefined by the treectrl widget itself (static).

pathName item state names

Returns a list containing the names of all user-defined states.

pathName item state set itemDesc ?lastItem? stateDescList

Every element of stateDescList must be the name of a dynamic state (see STATES below), optionally preceded by a ~ or ! character. Every state with a leading ! will be switched off for the item described by itemDesc, every state with a leading ~ will be toggled, and every state without leading ! or ~ will be switched on. If lastItem is specified, the state changes will be made for all items in the range between itemDesc and lastItem. If lastItem unspecified, then the state changes are made for all items described by itemDesc.

pathName item state undefine ?stateName ...?

Every stateName must be the name of a user-defined state. Removes this state from the list of user-defined states.

pathName item style command itemDesc ?arg ...?

This command is used to manipulate the styles of an item. The exact behavior of the command depends on the command argument that follows the style argument. The following forms of the command are supported:

pathName item style elements itemDesc column

This command returns a list containing the names of elements which were configured by the item element configure command for the item described by itemDesc in column. If there is no style assigned to column an error is returned.

pathName item style map itemDesc column style map

Like the item style set command, this command may be used to assign a style to a specific column of an item. Unlike item style set, this command can transfer configuration values of elements in the current style to elements in the new style specified by style. Map must be a list of elementOld-elementNew pairs, where elementOld is an element in the current style, and elementNew is an element in the style specified by style. Both elementOld and elementNew must be of the same type (bitmap, text etc). ItemDesc may refer to multiple items and column may refer to multiple columns.

pathName item style set itemDesc ?column? ?style? ?column style ...?

This command sets or retrieves the style assigned to one or more columns. If no column is specified, this command returns a list containing the names of the styles set for all columns of the item described by itemDesc. If no style is specified, this command returns the name of the style set for the item described by itemDesc in column.

If one or more column-style pairs is specified, then the style in each column is set to style. In this case itemDesc may refer to multiple items and each column may refer to multiple columns.

pathName item tag option ?arg arg ...?

This command is used to manipulate tags on items. The exact behavior of the command depends on the option argument that follows the item tag argument. The following forms of the command are supported:

pathName item tag add itemDesc tagList

Adds each tag in tagList to the items specified by the item description itemDesc. Duplicate tags are ignored. The list of tags for an item can also be changed via an item's -tags option.

pathName item tag expr itemDesc tagExpr

Evaluates the tag expression tagExpr against every item specified by the item description itemDesc. The result is 1 if the tag expression evaluates to true for every item, 0 otherwise.

pathName item tag names itemDesc

Returns a list of tag names assigned to the items specified by the item description itemDesc. The result is the union of any tags assigned to the items.

pathName item tag remove itemDesc tagList

Removes each tag in tagList from the items specified by the item description itemDesc. It is not an error if any of the items do not use any of the tags. The list of tags for an item can also be changed via an item's -tags option.

pathName item text itemDesc ?column? ?text? ?column text ...?

This command sets or retrieves the value of the -text option for the first text element in one or more columns. If no column is specified, this command returns a list of values, one per column. If no text is specified, this command returns the value for column.

If one or more column-text pairs is specified, then the value of the -text option in each column is set to text. In this case itemDesc may refer to multiple items and each column may refer to multiple columns.

Note that this command is provided as a convenience. Use the item element configure or item element cget commands if you want to set or retrieve the value of the -text option for a specific text element.

pathName item toggle itemDesc ?-animate? ?-recurse?

Changes the open state of the item(s) described by itemDesc. If the open state is currently switched off, then this command does the same as the item expand widget command; otherwise the same as the item collapse widget command. If -animate is specified, then the item's button will animate as it transitions between states if the theme supports it; in this case only one item may be specified. If -recurse is specified, then the open state of all descendants of the items described by itemDesc will also be toggled.

pathName marquee option ?arg ...?

This command is used to manipulate the marquee, which can be used to implement a resizable selection rectangle, in a file browser for example. One corner point of the marquee is fixed as long as the marquee is visible and called the anchor; the diagonally opposite corner is dragged with the mouse while resizing the marquee and simply called the corner.

All coordinates handled by this widget command are canvas coordinates, i.e. the canvasx or canvasy widget command should be used to translate window coordinates to canvas coordinates.

By default, the marquee is displayed as a 1-pixel thick dotted rectangle. If either of the -fill or -outline options is specified, then the marquee is drawn as a filled and/or outlined rectangle of the specified color(s). The -fill option should specify a transparent gradient to avoid hiding what is inside the marquee. See GRADIENTS for more info.

The exact behavior of the command depends on the option argument that follows the marquee argument. The following forms of the command are supported:

pathName marquee anchor ?x y?

Returns a list containing the x and y coordinates of the anchor, if no additional arguments are specified. If two coordinates are specified, sets the anchor to the given coordinates x and y.

pathName marquee cget option

This command returns the current value of the marquee option named option. Option may have any of the values accepted by the marquee configure widget command.

pathName marquee configure ?option? ?value? ?option value ...?

This command is similar to the configure widget command except that it modifies the marquee options instead of modifying options for the overall treectrl widget. If no option is specified, the command returns a list describing all of the available marquee options (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named marquee option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given marquee option(s) to have the given value(s); in this case the command returns an empty string.

The following marquee options are supported:

-fill color

Specifies the color to fill the marquee rectangle with. See the comments above about using a transparent gradient here.

-outline color

Specifies the color to outline the marquee rectangle with.

-outlinewidth color

Specifies the width of the outline drawn inside the marquee's rectangle. The outline is not drawn if this value is less than 1. This option has no effect if the -outline option is unspecified, i.e., the default dotted rectangle is unaffected by this option. outlineWidth may be in any of the forms acceptable to Tk_GetPixels. Defaults to 1.

-visible boolean

Specifies a boolean value which determines whether the marquee is displayed.

pathName marquee coords ?x1 y1 x2 y2?

Returns a list containing the x and y coordinates of the anchor followed by the x and y coordinates of the corner, if no additional arguments are specified. If four coordinates are specified, sets the anchor to the given coordinates x1 and y1 and the corner to the coordinates x2 and y2.

pathName marquee corner ?x y?

Returns a list containing the x and y coordinates of the corner, if no additional arguments are specified. If two coordinates are specified, sets the corner to the given coordinates x and y.

pathName marquee identify

Returns a list with information about any items intersecting the marquee. The format of the returned list is:

{
    {item {column element element ...} {column element element ...} ...}
    {item {column element element ...} {column element element ...} ...}
    ...
}

There may be zero sublists following an item id if the marquee is in the button/line area of an item. There may be zero element names following a column id if the item-column has no style or if the marquee does not intersect any elements in that column.

pathName notify option ?arg ...?

Many Tk widgets communicate with the outside world via -command callbacks and/or virtual events. For example, the Text widget evaluates its -yscrollcommand when the view in the widget changes, and generates a <<Modified>> virtual event when text is inserted or deleted. A treectrl widget replaces both methods of communication with its own event mechanism accessed through the notify subcommands.

The exact behavior of the command depends on the option argument that follows the notify argument. The following forms of the command are supported:

pathName notify bind ?object? ?pattern? ?+??script?

This command associates Tcl scripts with events generated by a treectrl widget. If all three arguments are specified, notify bind will arrange for script (a Tcl script) to be evaluated whenever the event(s) specified by pattern are generated by this treectrl widget. If script is prefixed with a "+", then it is appended to any existing binding for pattern; otherwise script replaces any existing binding. If script is an empty string then the current binding for pattern is destroyed, leaving pattern unbound. In all of the cases where a script argument is provided, notify bind returns an empty string.

If pattern is specified without a script, then the script currently bound to pattern is returned, or an empty string is returned if there is no binding for pattern. If neither pattern nor script is specified, then the return value is a list whose elements are all the patterns for which there exist bindings for object.

The object argument determines which window(s) the binding applies to. If object begins with a dot, as in .a.b.c, then it must be the path name for a window; otherwise it may be an arbitrary string. Like the regular bind command, bindings on window names are automatically removed if that window is destroyed.

pathName notify configure object pattern ?option? ?value? ?option value ...?

This command sets and retrieves options for bindings created by the notify bind command.

If no option is specified, the command returns a list with option-value pairs describing all the available binding options for pattern on object. If option is specified with no value, then the command returns the current value of that option. If one or more option-value pairs are specified, then the command modifies the given option(s) to have the given value(s) for the binding; in this case the command returns an empty string.

The following binding options are supported:

-active boolean

Specifies if the binding should be active. As long as this option is specified as false, a binding script will not be evaluated when the corresponding event is generated.

pathName notify detailnames eventName

Returns a list containing the names of all details, which are installed for the event with the name eventName by means of the notify install widget command or by the treectrl widget itself.

pathName notify eventnames

Returns a list containing the names of all events, which are installed by means of the notify install widget command or by the treectrl widget itself.

pathName notify generate pattern ?charMap? ?percentsCommand?

This command causes the treectrl widget to generate an event. This command is typically used to generate dynamic events created by the notify install command, but may be used to generate static events also. The event specified by pattern is generated, and any active binding scripts on the event are evaluated after undergoing %-substitution. If there are details defined for the event, pattern must describe an <eventName-detail> pair, otherwise pattern should be <eventName>.

The optional charMap is a list of char-value pairs as in the form returned by array get. Each char has to be exactly one character. The charMap is used in %-substitution.

If percentsCommand is specified, then it will be used to perform %-substitution on any scripts bound to the event. If percentsCommand is not specified and the event is dynamic, then the %-subtitution command passed to notify install will be used if it was provided. If the event is static or no %-substitution command is available, then all %-substitution is done using charMap only . See notify install for a description of percentsCommand.

pathName notify install pattern ?percentsCommand?

This command installs a new event or detail specified by pattern. Events created by this command are called dynamic, whereas events created by the treectrl widget itself are called static. This command may be called to set or retrieve the percentsCommand for an existing dynamic event.

The optional percentsCommand is a list containing the name of a Tcl command, plus any optional arguments, to which five additional arguments will be appended. The command will be called to perform %-substitution on any scripts bound to the event specified by pattern (see EVENTS AND SCRIPT SUBSTITUTIONS). PercentsCommand should be defined as follows:

proc percentsCommand {?arg arg ...? char object event detail charMap} {
	switch -- $char {
		...
	}
	return $value
}

The optional arg arguments are part of the percentsCommand list. Char is the %-character to be substituted. Object is the same as the argument to notify bind. Event and detail specify the event. CharMap is the same as the argument to notify generate. PercentsCommand should return the value to replace the %-character by. If an error occurs evaluating percentsCommand, the %-character is replaced by itself.

notify install returns the current percentsCommand for the event, or an error if the event is not dynamic.

pathName notify install detail eventName detail ?percentsCommand?

Deprecated. Use notify install with a pattern of <eventName-detail> instead.

pathName notify install event eventName ?percentsCommand?

Deprecated. Use notify install with a pattern of <eventName> instead.

pathName notify linkage pattern

Returns a string indicating whether the specified event or detail is created by means of the notify install widget command (dynamic) or by the treectrl widget itself (static).

pathName notify linkage eventName ?detail?

Deprecated. Use notify linkage with a pattern of <eventName> or <eventName-detail> instead.

pathName notify unbind object ?pattern?

If no pattern is specified, all bindings on object are removed. If pattern is specified, then the current binding for pattern is destroyed, leaving pattern unbound.

pathName notify uninstall pattern

If the event or detail specified by pattern is static (i.e. created by the treectrl widget itself), an error is generated. Otherwise the dynamic event or detail is removed. If an event name is specified without a detail, all details for that event are also removed.

pathName notify uninstall detail eventName detail

Deprecated. Use notify uninstall with a pattern of <eventName-detail> instead.

pathName notify uninstall event eventName

Deprecated. Use notify uninstall with a pattern of <eventName> instead.

pathName numcolumns

Deprecated. Use the column count command instead.

pathName numitems

Deprecated. Use the item count command instead.

pathName orphans

Returns a list containing the item ids of all items which have no parent. When an item is created, it has no parent by default, and can later become an orphan by means of the item remove widget command. The root item is not returned.

pathName range first last

Deprecated. Use the item range command instead.

pathName scan option args

This command is used to implement scanning on treectrls. It has two forms, depending on option:

pathName scan mark x y

Records x and y and the treectrl's current view; used in conjunction with later scan dragto commands. Typically this command is associated with a mouse button press in the widget and x and y are the coordinates of the mouse. It returns an empty string.

pathName scan dragto x y ?gain?

This command computes the difference between its x and y arguments (which are typically mouse coordinates) and the x and y arguments to the last scan mark command for the widget. It then adjusts the view by gain times the difference in coordinates, where gain defaults to 10. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the treectrl at high speed through its window. The return value is an empty string.

pathName see itemDesc ?columnDesc? ?option value ...?

Adjust the view in the treectrl so that the item described by itemDesc is visible. If the item is already visible then the command has no effect; otherwise the treectrl scrolls to bring the item into view, and the corresponding <Scroll-x> and/or <Scroll-y> events are generated. If columnDesc is specified then a specific column of the item is scrolled into view instead of the entire item.

The following options are supported:

-center flags

Flags is a string that contains zero or more of the characters x or y. This option is used to center the item horizontally and/or vertically in the window. The item will be centered regardless of whether it is already visible.

pathName selection option args

This command is used to adjust the selection within a treectrl. It has several forms, depending on option:

pathName selection add first ?last?

First and last (if specified) must be valid item descriptions. If both first and last are specified, then they may refer to a single item only; in this case the command adds every unselected item in the range between first and last, inclusive, to the selection without affecting the selected state of items outside that range. If only first is specified, then every unselected item specified by first is added to the selection. A <Selection> event is generated if any items were added to the selection.

pathName selection anchor ?itemDesc?

If itemDesc is specified, the selection anchor is set to the described item. The selection anchor is the end of the selection that is fixed while dragging out a selection with the mouse. The item description anchor may be used to refer to the anchor item. This command doesn't modify the selection state of any item. Returns the unique id of the selection anchor item.

pathName selection clear ?first? ?last?

First and last (if specified) must be valid item descriptions. If both first and last are specified, then they may refer to a single item only; in this case any selected items between first and last (inclusive) are removed from the selection without affecting the selected state of items outside that range. If only first is specified, then every selected item specified by first is removed from the selection. If neither first nor last are specified, then all selected items are removed from the selection. A <Selection> event is generated if any items were removed from the selection.

pathName selection count

Returns an integer indicating the number of items in the treectrl that are currently selected.

pathName selection get ?first? ?last?

When no additional arguments are given, the result is an unsorted list containing the item ids of all of the items in the treectrl that are currently selected. If there are no items selected in the treectrl, then an empty string is returned. The optional arguments first and last are treated as indices into the sorted list of selected items; these arguments allow in-place lindex and lrange operations on the selection. For example:

.t selection get 0       ; # return the first selected item
.t selection get end     ; # return the last selected item
.t selection get 1 end-1 ; # return every selected item except the first and last
pathName selection includes itemDesc

Returns 1 if the item described by itemDesc is currently selected, 0 if it isn't.

pathName selection modify select deselect

Both arguments select and deselect are a possibly-empty list of item descriptions. Any unselected items in select are added to the selection, and any selected items in deselect are removed from the selection (except for those items which are also in select). A <Selection> event is generated if any items were selected or deselected.

pathName state option args

This command is used to manipulate the list of user-defined item states, see section STATES below. Item states can also be managed using the item state command. To manage states for header-rows, use the header state widget command. The exact behavior of the command depends on the option argument that follows the state argument. The following forms of the command are supported:

pathName state define stateName

Defines a new state with the name stateName, which must not be the name of an existing state.

pathName state linkage stateName

Returns a string indicating whether the specified state is user-defined by means of the state define widget command (dynamic) or predefined by the treectrl widget itself (static).

pathName state names

Returns a list containing the names of all user-defined states.

pathName state undefine ?stateName ...?

Every stateName must be the name of a user-defined state. Removes this state from the list of user-defined states.

pathName style option ?element? ?arg arg ...?

This command is used to manipulate styles, which can be thought of as a geometry manager for elements. The exact behavior of the command depends on the option argument that follows the style argument. The following forms of the command are supported:

pathName style cget style option

This command returns the current value of the option named option associated with the style given by style. Option may have any of the values accepted by the style configure widget command.

This command also accepts the -statedomain option.

pathName style configure style ?option? ?value? ?option value ...?

This command is similar to the configure widget command except that it modifies options associated with the style given by style instead of modifying options for the overall treectrl widget. If no option is specified, the command returns a list describing all of the available options for style (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, 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 option is specified). If one or more option-value pairs are specified, then the command modifies the given option(s) to have the given value(s) in style; in this case the command returns an empty string.

The following options are supported:

-buttony offset

Specifies the distance from the top of the item that the expand/collapse button should be drawn. If offset is an empty string (the default) then the button is centered vertically in the item. The value may have any of the forms acceptable to Tk_GetPixels. This option only has effect when the style is set in an item in the tree column.

-orient varName

This option specifies which orientation should be used when laying out the elements associated with this style. Must be either horizontal (the default) or vertical or an abbreviation of one of these.

pathName style create name ?option value ...?

Creates a new style with the unique user-defined name name. After name there may be any number of option-value pairs, each of which sets one of the configuration options for the style. See the style configure command for the possible options. The result of this command is the name of the new style (the same as the name option).

This command also accepts the -statedomain option with a value of either header or item to specify where this style will be displayed.

pathName style delete ?style ...?

Deletes each of the named styles and returns an empty string. If a style is deleted while it is still used to display one or more items, it is also removed from the style list of these items.

pathName style elements style ?elementList?

Specifies the elements which should be layed out by this style. Each element of elementList must be the name of an element created by the widget command element create. Duplicate names in elementList are ignored. An element which was specified in a former call of this command for style but is not included in elementList, will be deleted from the elements layed out by style.

Every element used by a style must have been created with the same value for the -statedomain option.

If the elementList argument is not specified, a list is returned containing the currently defined elements of style.

pathName style layout style element ?option? ?value? ?option value ...?

This command is similar to the configure widget command except that it modifies options used by style for laying out element instead of modifying options for the overall treectrl widget. If no option is specified, the command returns a list with option-value pairs describing all of the available options for the layout. If option is specified with no value, then the command returns the value of the named option. If one or more option-value pairs are specified, then the command modifies the given option(s) to have the given value(s) for the layout; in this case the command returns an empty string.

The options of a layout have effect on exactly the one element element managed by style. The following options are supported:

-detach boolean

Specifies whether the element should be positioned by itself, i.e. independent from the other elements. The default is false.

-center flags

Flags is a string that contains zero or more of the characters x or y. x causes the element to be centered horizontally, y causes the element to be centered vertically. When more than one element has -center layout, all the elements between the first and last with -center layout in the style's list of elements are centered as a group. Consider the following when there is another element to the right of MyElement:

.t style layout MyStyle MyElement -expand we
.t style layout MyStyle MyElement -center x

With the first call, MyElement will be centered only within the space that is not occupied by the other element, so MyElement will appear off-center towards the left of the style. With the second call, MyElement will be centered within the style so long as it doesn't overlap the other element.

-draw boolean

This is a per-state option that determines whether an element should be drawn. If the value of the option evaluates to false for a given item state, then the element is not drawn, although it still consumes space in the layout.

-expand flags

This option allows the external padding around the element to increase when a style has more screen space than it needs. Flags is a string that contains zero or more of the characters n, s, w or e. Each letter refers to the padding on the top, bottom, left, or right that should be allowed to increase. This option is typically used to justify an element. The default is an empty string.

-iexpand flags

This option allows the internal padding of the element and the display area of the element to increase when a style has more screen space than it needs. Flags is a string that contains zero or more of the characters x, y, n, s, w or e. For n, s, w and e, each letter refers to the padding on the top, bottom, left, or right that should be allowed to increase. For x and y, each letter refers to the horizontal and vertical screen space the element can display itself in (i.e., the space between the padding). Note that if the -union option is specified for this element, then the x and y flags have no effect, since the size of an element with -union layout is determined by the elements it surrounds. The default is an empty string.

-indent boolean

For item styles, this option specifies whether the element should be positioned to the right of the button/line area in the tree column. When false, the element is displayed beneath the buttons and lines in the tree column. This option is ignored unless the -detach option is true.

For header styles, this option specifies whether the element should be positioned to the right of the -canvaspadx padding. This option is ignored unless the -detach option is true or the -union option is specified.

The default is true.

-ipadx amount
-ipady amount

Amount specifies how much internal padding to leave on the left and right (for -ipadx) or top and bottom (for -ipady) sides of the element. Amount may be a list of two values to specify padding for the two sides separately. The default value is 0. This option is typically used with the -union layout option, to create space around the enclosed elements.

-minheight pixels
-height pixels
-maxheight pixels

Specifies the minimum, fixed, and maximum height of the display area of the element. The default is unspecified.

-minwidth pixels
-width pixels
-maxwidth pixels

Specifies the minimum, fixed, and maximum width of the display area of the element. The default is unspecified.

-padx amount
-pady amount

Amount specifies how much external padding to leave on the left and right (for -padx) or top and bottom (for -pady) sides of the element. Amount may be a list of two values to specify padding for the two sides separately. The default value is 0.

-squeeze flags

This option allows the display area of an element to decrease when a style has less space than it needs. Flags is a string that contains zero or more of the characters x or y. x allows display area to decrease horizontally, y allows display area to decrease vertically. This option is typically used for text elements and will cause the text element to display an ellipsis (...) and/or wrap lines. The default is an empty string.

-sticky flags

This option controls how the actual display information (image, text, etc) of an element is positioned (or stretched) within its display area. Flags is a string that contains zero or more of the characters n, s, w or e. Each letter refers to the top, bottom, left or right side of the display area that the display information should "stick" to. The default is nswe.

-union elementList

Specifies a list of other elements which this element will surround. The size of an element with -union layout is determined by the size and position of the elements in elementList. The -ipadx and -ipady options in this case refer to the distance of the edges of the display area of this element from those elements it surrounds. This option is typically used to display a selection rectangle around a piece of text. If none of the elements in elementList are visible, then the element is not displayed.

-visible boolean

This is a per-state option that controls visibility of an element. If the value of the option evaluates to false for a given item state, then the element is not displayed and consumes no space in the layout.

pathName style names

Returns a list containing the names of all existing styles.

pathName theme option ?arg ...?

This command is used to interact with the platform-specific theme. The exact behavior of the command depends on the option argument that follows the theme argument. The following forms of the command are supported:

pathName theme platform

Returns the API used to draw themed parts of the treectrl. On Mac OS X the result is always aqua. On MS Windows the result is visualstyles if the uxtheme.dll was loaded and visual themes are in use, otherwise X11 is returned to indicate the Tk Xlib calls are drawing the themed parts. On Unix systems the result is gtk if the Gtk+ version of treectrl was built, otherwise X11 is returned.

pathName theme setwindowtheme appname

The command is available on MS Windows only. If appname is "Explorer" then the item buttons look like those in the Explorer file browser (disclosure triangles under Windows Vista/7). If appname is an empty string then the buttons revert to their default appearance according to the system's current visual style.

pathName toggle ?-recurse? ?itemDesc ...?

Use item toggle instead.

pathName xview ?args?

This command is used to query and change the horizontal position of the information displayed in the treectrl's window. It can take any of the following forms:

pathName xview

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 tree's area is off-screen to the left, the middle 40% is visible in the window, and 40% of the tree is off-screen to the right. These are the same values passed to scrollbars via the -xscrollcommand option.

pathName xview moveto fraction

Adjusts the view in the window so that fraction of the total width of the tree is off-screen to the left. Fraction must be a fraction between 0 and 1. A <Scroll-x> event is generated.

pathName xview scroll number what

This command shifts the view in the window left or right according to number and what. Number must be an integer. What must be either units or pages or an abbreviation of one of these. If what is units, the view adjusts left or right in units determined by the -xscrollincrement option (which may be zero, see the description of that option). If what is pages then the view adjusts in units of nine-tenths the window's width. If number is negative then information farther to the left becomes visible; if it is positive then information farther to the right becomes visible. A <Scroll-x> event is generated.

pathName yview ?args?

This command is used to query and change the vertical position of the information displayed in the treectrl's window. It can take any of the following forms:

pathName yview

Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the vertical span that is visible in the window. For example, if the first element is .6 and the second element is 1.0, the lowest 40% of the tree's area is visible in the window. These are the same values passed to scrollbars via the -yscrollcommand option.

pathName yview moveto fraction

Adjusts the view in the window so that fraction of the tree's area is off-screen to the top. Fraction is a fraction between 0 and 1. A <Scroll-y> event is generated.

pathName yview scroll number what

This command adjusts the view in the window up or down according to number and what. Number must be an integer. What must be either units or pages. If what is units, the view adjusts up or down in units of the -yscrollincrement option (which may be zero, see the description of that option). If what is pages then the view adjusts in units of nine-tenths the window's height. If number is negative then higher information becomes visible; if it is positive then lower information becomes visible. A <Scroll-y> event is generated.

HEADERS

A treectrl widget can display zero or more rows of column headers. When a treectrl widget is created, a single row of column headers (aka a header-row) is created as well; this top header-row cannot be deleted. Additional header-rows can be created with the header create command and deleted with header delete.

There are no commands for changing the order of header-rows; they are displayed from top to bottom in the order they were created.

Drag-and-drop reordering of column headers is supported within a widget. To control column header drag-and-drop, use the header dragconfigure command.

Header-rows in a treectrl may be specified in a number of ways. See HEADER DESCRIPTION below.

The appearance of individual column headers within a header-row may be customized in two different ways:

  1. By configuring various column header options with the header configure command

  2. By assigning a style to a column header with the header style command.

When one of the options below is specified as per-state, the state names are those described in STATES for headers only, i.e. do not use item state names.

The following options are supported for each individual column header:

-arrow direction

Indicates whether or not a sort arrow should be drawn in the column header. Direction must have one of the values none (the default), up, or down.

-arrowbitmap bitmap

Specifies as a per-state option the name of a bitmap to use to draw the arrow if this column's -arrow option is not none.

-arrowgravity direction

Indicates onto which side the sort arrow should be packed, if there is more space available for drawing the arrow then needed. direction must be either left (the default) or right.

-arrowimage image

Specifies as a per-state option the name of an image to use to draw the sort arrow if this column's -arrow option is not none. If an image is specified for a certain state, it overrides the -arrowbitmap option.

-arrowpadx amount

Amount specifies how much padding to leave on the left and right of the sort arrow. Amount may be a list of two values to specify padding for left and right separately; it defaults to 6.

-arrowpady amount

Amount specifies how much padding to leave on the top and bottom of the sort arrow. Amount may be a list of two values to specify padding for top and bottom separately; it defaults to 0.

-arrowside side

Indicates on which side of the bitmap/image/text the sort arrow should be drawn. Side must be either left or right (the default).

-bitmap bitmap

Specifies the name of a bitmap to display to the left of the column title.

-background color

Specifies as a per-state option the color to use for the background of the column header.

-borderwidth size

Specifies a non-negative value indicating the width of the 3-D border to draw around the outside of the column header (if such a border is being drawn; the -relief column option determines this). The value may have any of the forms acceptable to Tk_GetPixels.

-button boolean

Indicates whether or not the column header should be treated like a pushbutton. When this option is true, the default bindings track <Button-1> events in the header and generate a <Header-invoke> event when a <ButtonRelease-1> event occurs in the header. See DYNAMIC EVENTS.

-font fontName

Specifies the font to use for displaying the column title inside the column header. When the value of this option is unspecified, the font specified by the widget option -headerfont is used.

-image image

Specifies the name of an image to display to the left of the column title. This option overrides the -bitmap column option.

-imagepadx amount

Amount specifies how much padding to leave on the left and right of the image (or bitmap). Amount may be a list of two values to specify padding for left and right separately; it defaults to 6.

-imagepady amount

Amount specifies how much padding to leave on the top and bottom of the image (or bitmap). Amount may be a list of two values to specify padding for top and bottom separately; it defaults to 0.

-justify justification

This option determines how the image and text in the column header are positioned. Must be one of left (the default), center, or right.

-state state

Specifies one of three states for the column header: normal, active, or pressed. The active state is used when the mouse is over the header. The pressed state is used when the mouse button is pressed in the header.

Changing the value of this option also affects the current set of header states for the column header, which may affect both the per-state options mentioned here (such as -arrowimage) as well as the elements in any style that may be assigned to the column header.

-text text

Specifies a text string to be displayed as the column title.

-textcolor color

Specifies as a per-state option the color to display the column title with. When the value of this option is unspecified, the title will be drawn according to the system theme color, if any, otherwise the widget option -headerforeground is used. The default is unspecified.

-textlines count

Specifies the maximum number of lines of text to display in the column title. If this value is zero, the number of lines displayed is determined by any newline characters and the effects of wrapping when the column width is less than needed. The default is 1. Note: Under OSX/Aqua this value is always set to 1 when the treectrl's -usetheme option is true, because the Appearance Manager uses a fixed height for the column header; there is only room for a single line of text.

-textpadx amount

Amount specifies how much padding to leave on the left and right of the text. Amount may be a list of two values to specify padding for left and right separately; it defaults to 6.

-textpady amount

Amount specifies how much padding to leave on the top and bottom of the text. Amount may be a list of two values to specify padding for top and bottom separately; it defaults to 0.

HEADER DESCRIPTION

Many of the commands for a treectrl take as an argument a description of which header-rows to operate on. A header description is a properly-formed tcl list of keywords and arguments. The first word of a header description must be one of the following:

id

Specifies a unique header-row identifier, where id should be the return value of a prior call of the header create widget command, or 0 to specify the ever-present top header-row.

QUALIFIERS

Specifies a list of qualifiers. This gives the same result as all followed by QUALIFIERS; i.e., every header-row is tested for a match.

tagExpr QUALIFIERS

TagExpr is a tag expression (see ITEM AND COLUMN TAGS) against which every header-row's tags are tested for a match. You may run into trouble if tagExpr looks like a header-row id or other keyword; also, tagExpr must look like a single list element since header-row descriptions are properly-formed lists. To be safe you may want to use the tag qualifier followed by tagExpr.

.t header dragconfigure {tag -funky} -draw yes
all QUALIFIERS

Matches every header-row which satisfies QUALIFIERS.

first QUALIFIERS

Indicates the top header-row of the treectrl, or the first header-row starting from the top that satisfies QUALIFIERS.

end QUALIFIERS
last QUALIFIERS

Indicates the last header-row which satisfies QUALIFIERS.

The word QUALIFIERS above represents a series of zero or more of the following terms that changes which header-row is chosen:

tag tagExpr

TagExpr is a tag expression (see ITEM AND COLUMN TAGS) against which a header-row's tags are tested for a match.

visible

When this qualifier is given, only header-rows that are displayed are matched. A header-row is displayed only if both the -showheader widget option and -visible header-row option are true. Also, if only the tail column is visible, then header-rows are not displayed.

!visible

When this qualifier is given, only header-rows that are *not* displayed are matched.

COLUMNS

A treectrl widget is capable of displaying multiple columns next to each other. An item can be considered as a row, which reaches over all columns.

Columns in a treectrl may be specified in a number of ways. See COLUMN DESCRIPTION below.

There is always one special column, the tail column, which fills all space to the right of the last ordinary column. This column has no unique ID; it can only be specified by the keyword tail.

For compatibility with older versions of treectrl (which did not support more than one row of column headers) any of the configuration options mentioned in the HEADERS section, such as -arrow, -text, etc, may be passed to the top header-row through the column configure command and queried with the column cget command.

The following options are supported for columns:

-expand boolean

Indicates whether or not any extra horizontal space should be distributed to this column. This option has no effect if the -width option is set.

-gridleftcolor color
-gridrightcolor color

Specifies the color of the lines drawn down the left and right edges of the column. These so-called "grid lines" are drawn over the elements of each item style in the column and down into the whitespace region below any items. The default value for each option is an empty string meaning no lines are drawn.

-itembackground colorList

Specifies a list of zero or more colors, which are used as alternating background colors for items in this column. See also the -backgroundmode widget option for more on this.

-itemjustify justification

This option determines how the item styles in this column are aligned horizontally. Must be one of left, center, or right. The default value is an empty string (for compatibility with older versions), in which case the column option -justify is used to align item styles in this column.

-itemstyle style

Style is the name of a style that should be set in this column for newly-created items.

-justify justification

This option determines how item styles in this column are aligned horizontally unless overriden by the -itemjustify option for this column. Must be one of left (the default), center, or right.

For compatibility with older versions of treectrl (which did not allow multiple rows of column headers), changing the value of this option also changes the -justify option of the column header in the top header-row.

-lock lock

This option allows a column to stick to the left or right edge of the window. A locked column scrolls vertically but not horizontally. Must be one of none (the default), left, or right.

-maxwidth size

Specifies the maximum size, in screen units, that will be permitted for this column. If size is an empty string, then there is no limit on the maximum size of the column. This option has no effect if the -width option is set.

-minwidth size

Specifies the minimum size, in screen units, that will be permitted for this column. If size is an empty string, then the minimum size of the column is zero. This option has no effect if the -width option is set.

-resize boolean

Specifies a boolean value that indicates whether the user should be allowed to resize the column by dragging the edge of the column's header. Default is true.

-squeeze boolean

Specifies a boolean value that indicates whether or not the column should shrink when the content width of the treectrl is less than the total needed width of all visible columns. Defaults to false, which means the column will not get smaller than its needed width. The column will not get smaller than the value of its -minwidth option, if specified. This option has no effect if the -width option is set.

-stepwidth size

Deprecated. Use the treectrl's -itemwidthmultiple option instead.

-tags tagList

TagList is a list of tag names that can be used to identify the column. See also the column tag command.

-uniform group

When a non-empty value is supplied, this option places the column in a uniform group with other columns that have the same value for -uniform. The space for columns belonging to a uniform group is allocated so that their sizes are always in strict proportion to their -weight values. This option is based on the grid geometry manager.

-visible boolean

Indicates whether or not the column should be displayed.

-weight integer

Sets the relative weight for apportioning any extra space among columns. A weight of zero (0) indicates the column will not deviate from its requested size. A column whose weight is two will grow at twice the rate as a column of weight one when extra space is allocated to columns. This option is based on the grid geometry manager.

-width size

Specifies a fixed width for the column. If this value is an empty string, then the column width is calculated as the maximum of: a) the width requested by items; b) the width requested by the column's header; and c) the column's -minwidth option. This calculated width is also affected by the -expand, -squeeze, -uniform and -weight options. In any case, the calculated width will not be greater than the -maxwidth option, if specified.

-widthhack boolean

Deprecated. Use the treectrl's -itemwidthequal option instead.

COLUMN DESCRIPTION

Many of the commands and options for a treectrl take as an argument a description of which column to operate on. See the EXAMPLES section for examples. The initial part of a column description must begin with one of the following terms:

id

Specifies the unique column identifier, where id should be the return value of a prior call of the column create widget command. See also the -columnprefix option.

QUALIFIERS

Specifies a list of qualifiers. This gives the same result as all followed by QUALIFIERS; i.e., every column is tested for a match.

tagExpr QUALIFIERS

TagExpr is a tag expression (see ITEM AND COLUMN TAGS) against which every column's tags are tested for a match. This keyword cannot be followed by any modifiers unless a single column is matched. You may run into trouble if tagExpr looks like a column id or other keyword; also, tagExpr must look like a single list element since column descriptions are properly-formed lists. To be safe you may want to use the tag qualifier followed by tagExpr.

all QUALIFIERS

Indicates every column, including the tail column if the command allows it, which match QUALIFIERS.

first QUALIFIERS

Indicates the leftmost column of the treectrl which matches QUALIFIERS.

end QUALIFIERS
last QUALIFIERS

Indicates the rightmost column of the treectrl (but not the tail column) which matches QUALIFIERS.

list columnDescs

ColumnDescs is a list (a single argument, i.e. "list {a b c}" not "list a b c") of other column descriptions. This keyword cannot be followed by any modifiers unless a single column is matched.

order n QUALIFIERS

Indicates the nth column in the list of columns as returned by the column order command.

range first last QUALIFIERS

First and last specify a range of columns. This keyword cannot be followed by any modifiers unless a single column is specified.

tail

Indicates the ever-present tail column of the treectrl.

tree

Indicates the column specified by the -treecolumn option of the treectrl.

The initial part of the column description (matching any of the values above) may be followed by one or more modifiers. A modifier changes the column used relative to the description up to this point. It may be specified in any of the following forms:

next QUALIFIERS

Use the column to the right matching QUALIFIERS.

prev QUALIFIERS

Use the column to the left matching QUALIFIERS.

span N QUALIFIERS

Starting with (and counting) the single column specified by the column description so far, walk at most N columns rightwards, stopping if any of the following conditions is met:

  1. A column does not match QUALIFIERS.

  2. A column's -lock option does not match the first column's -lock option.

The word QUALIFIERS above represents a sequence of zero or more of the following terms that changes which column is chosen:

tag tagExpr

TagExpr is a tag expression (see ITEM AND COLUMN TAGS) against which a column's tags are tested for a match.

!tail

When this qualifier is given, the tail column is not matched.

visible

When this qualifier is given, only columns whose -visible option is TRUE are considered.

!visible

When this qualifier is given, only columns whose -visible option is FALSE are considered.

STATES

For every column header and every item a set of boolean states is managed. These states play an integral role in the appearance of headers and items; that role is described in detail in PER-STATE OPTIONS. The set of states available to headers is separate from the set of states available to items.

HEADER STATES

The following states are predefined for every column header:

active
normal
pressed

These states mirror the value of a column header's configuration option -state. Exactly one of these states is set at any time in each column header.

down
up

These states mirror the value of a column header's configuration option -arrow. If the -arrow option is none, then neither of these states is set.

background

This state is set for every header-row if the toplevel window containing the treectrl is not the foreground active window. This state cannot be modified by means of a widget command, but is maintained in reaction to the <Activate> and <Deactivate> windowing system events.

focus

This state is set for every header-row if the treectrl widget currently has the focus. It cannot be modified by means of a widget command, but is maintained in reaction to the <FocusIn> and <FocusOut> windowing system events.

ITEM STATES

The following states are predefined for every item:

active

At all times this state is set for exactly one item. The active item is used with keyboard navigation. When the treectrl widget is created or when the active item is deleted, the root item will become the active item. This state can be modified by means of the widget command activate.

enabled

This state is set for every item when it is created. Disabled items cannot be selected and are ignored by the default bindings when navigating via the keyboard. This state can be modified by means of the widget command item enabled.

focus

This state is set for every item if the treectrl widget currently has the focus. It cannot be modified by means of a widget command, but is maintained in reaction to the <FocusIn> and <FocusOut> events.

open

If this state is switched on, the descendants of the item are displayed - the item is expanded. If this state is switched off, the descendants of the item are not displayed - the item is collapsed. For a new item this state is switched on by default. This state can be modified by means of the widget commands item expand, item collapse, or item toggle.

selected

This state is set for every item included in the selection. It can be modified by means of the widget command selection.

By means of the state define widget command, up to 27 additional states can be defined.

PER-STATE OPTIONS

The visual appearance of an item can change depending on the state the item is in, such as being the active item, being included in the selection, being collapsed, or some combination of those or other states. When a configuration option is described as per-state, it means the option describes a value which varies depending on the state of the item. If a per-state option is specified as a single value, the value is used for all states. Otherwise the per-state option must be specified as an even-numbered list. For example, to use the font "Times 12 bold" in a text element regardless of the item state you can write:

$T element configure MyTextElement -font {{Times 12 bold}}

However, to use a different font when the item is selected you could write:

$T element configure MyTextElement -font {{Courier 10} selected {Times 12 bold} {}}

In the example above, the -font option reads "value stateList value stateList". If stateList is an empty list, the preceding value is used regardless of the item state. A non-empty stateList specifies a list of states which must be set for the item in order to use the preceding value. Each stateList can also include state names preceded by a ! sign, indicating the state must *not* be set for the item. For example:

$T element configure MyRectElement -fill {blue {selected focus} gray {selected !focus}}

In the example above, the rect element is filled with blue when the treectrl has the focus and the item is selected. If the treectrl does not have the focus, the example specifies that gray should be used for selected items. Also note that if the item is not selected, no color is specified for the -fill option.

Each value-stateList pair is checked in order from left to right. The value associated with the first stateList that matches the current item state is used. So stateLists should be listed from most-specific to least-specific.

$T element configure MyRectElement -fill {gray {selected} blue {selected focus}}

Written this way, gray will always be used for selected items since it appears first, and blue will never be used for selected items regardless of the focus.

A value followed by an empty stateList should always be last since it will be chosen regardless of the item's state.

ELEMENTS AND STYLES

Elements and styles are the core visual building blocks that determine the appearance of items (and optionally column headers). An element can be of type bitmap, border, header, image, rect, text or window. One or more elements can be assigned to a style which manages the layout of those elements. It may be helpful to think of an element as a Tk widget and a style as a Tk geometry manager such as grid, pack or place.

When an element is created by the element create command, that element is referred to as a master element. Similarly, a style that is created by style create is called a master style. When a master style is assigned to a column of an item by the item style set command, a new instance style is allocated which refers back to the master style and its master elements. In this way, a single master style may be shared by multiple columns of multiple items. If a master element or master style is modified, those changes affect all the items whose instance styles and elements refer to those masters.

Although you probably want the font and selection-rectangle colors to be shared by all items, you most likely don't want the text to be the same for every column of every item. The item element configure command can be used to override a master element's configuration options for a specific column of an item. When you call item element configure (or item text or item image), a new instance element is allocated, if one wasn't already, and that instance element's options will override the master element's.

All of the element configuration options described below are unspecified by default, meaning that no value whatsoever has been given to the option. It may seem strange to you that a boolean option would be unspecified instead of simply "true" or "false". The reason for this is that when an instance element used by an item has no value specified for an option, that instance element refers to the master element for the value of that option. This allows items which are displaying a certain element to be redisplayed when the master element's options change. The benefits of this are that you don't need to configure the font or text color for every item in a treectrl individually, saving CPU cycles and memory.

You may be thinking that to change the color of a selection rectangle you would call item element configure when an item was selected, but that is not usually the case. It would be wasteful to allocate a new instance element for a selection rectangle just because an item became selected. The solution is to allow the appearance of the selection rectangle master element to change based on the selected state of the item. This is described in PER-STATE OPTIONS.

For each element type there is a section below describing the options which can modify an element of that type.

BITMAP ELEMENT

An element of type bitmap can be used to display a bitmap in an item. The following options are supported for bitmap elements:

-background color

Specifies as a per-state option the color to use for each of the bitmap's '0' valued pixels. If the value for a certain state is an empty string (the default), the bitmap is drawn transparent.

-bitmap bitmap

Specifies as a per-state option the bitmap to display in the element.

-draw boolean

Deprecated; use the style layout option -draw instead. Specifies as a per-state option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn.

-foreground color

Specifies as a per-state option the color to use for each of the bitmap's '1' valued pixels. If the value for a certain state is an empty string (the default), the bitmap's foreground color is black.

BORDER ELEMENT

An element of type border can be used to display a 3D border in an item. The following options are supported for border elements:

-background color

Specifies as a per-state option the color to use for the background of the border. If the value for a certain state is an empty string (the default), the element will not be drawn.

-draw boolean

Deprecated; use the style layout option -draw instead. Specifies as a per-state option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn.

-filled boolean

Specifies whether the interior of the border should be filled with the background color. If this option is unspecified (the default), it it treated as false which means that only the edges of the border will be drawn.

-height size

Specifies the height of the border. If this value is unspecified (the default), the border will be exactly as tall as its display area as determined by the style layout options.

-relief relief

Specifies as a per-state option the relief of the border. If the value for a certain state is an empty string (the default), it is treated as flat. For acceptable values see the description of the -relief option in the options manual page.

-thickness thickness

Specifies the thickness of the edges of the border.

-width size

Specifies the width of the border. If this value is unspecified (the default), the border will be exactly as wide as its display area as determined by the style layout options.

HEADER ELEMENT

An element of type header can be used to display a themed (or non-themed) column header background and sort arrow. Header elements are best used surrounding other elements via the style layout option -union, so that the sort arrow can be displayed correctly.

Some of the options for this type of element get their default values from the header state flags that are set in the column header in which the element is displayed. In particular, the -arrow option gets its default value by checking the up and down state flags, and the -state option gets its default value by checking the active, normal, and pressed state flags. If elements of this type are displayed in an item instead of a column header, then this behavior isn't used since those state flags aren't meaningful for items.

The following options are supported for header elements:

-arrow direction

Indicates whether or not a sort arrow should be drawn. Direction must have one of the values none, up, or down. If unspecified, the value defaults to none (but see the note above regarding header states).

-arrowbitmap bitmap

Specifies as a per-state option the name of a bitmap to use to draw the sort arrow if this element's -arrow option is not none. This option is ignored when drawing themed headers on Mac OS X.

-arrowgravity direction

Indicates onto which side the sort arrow should be packed, if there is more space available for drawing the arrow than needed. Direction must be either left or right. If unspecified, the value defaults to left. This option is ignored when drawing themed headers on Mac OS X.

-arrowimage image

Specifies as a per-state option the name of an image to use to draw the sort arrow if this element's -arrow option is not none. If an image is specified for a certain state, it overrides the -arrowbitmap option. This option is ignored when drawing themed headers on Mac OS X.

-arrowpadx amount

Amount specifies how much padding to leave on the left and right of the sort arrow. Amount may be a list of two values to specify padding for the left and right separately. If unspecified, the value defaults to 6. Padding to the right of the sort arrow is ignored when drawing themed headers on Mac OS X.

-arrowpady amount

Amount specifies how much padding to leave on the top and bottom of the sort arrow. Amount may be a list of two values to specify padding for the top and bottom separately. If unspecified, the value defaults to 0. This option is ignored when drawing themed headers on Mac OS X.

-arrowside side

Indicates on which side of the element the sort arrow should be drawn. Side must be either left or right. If unspecified, the value defaults to right.

-background color

Specifies as a per-state option the color to use for the non-themed background and 3D border. If unspecified, the value defaults to either the Tk button widget's -background or -activebackground color.

-borderwidth size

Specifies a non-negative value indicating the width of the non-themed 3D border to draw around the inner edges of the element (if such a border is being drawn; the -relief option determines this). The value may have any of the forms acceptable to Tk_GetPixels. If unspecified, the value defaults to 2.

-state state

Specifies one of three states for the element: normal, active, or pressed. The active state is used when the mouse is over the header. The pressed state is used when the mouse button is pressed in the header. If unspecified, the value defaults to normal (but see the note above regarding header states).

IMAGE ELEMENT

An element of type image can be used to display an image in an item. The following options are supported for image elements:

-draw boolean

Deprecated; use the style layout option -draw instead. Specifies as a per-state option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn.

-height size

Specifies the requested height of the display area for this element. If unspecified (the default), the element requests a height equal to the height of the image, or zero if there is no image.

-image image

Specifies as a per-state option the image to display in the element.

-tiled boolean

Specifies a boolean indicating whether or not the image should be tiled horizontally and vertically within the display area for the element. The default is false.

-width size

Specifies the requested width of the display area for this element. If unspecified (the default), the element requests a width equal to the width of the image, or zero if there is no image.

RECTANGLE ELEMENT

An element of type rect can be used to display a rectangle in an item. The following options are supported for rectangle elements:

-draw boolean

Deprecated; use the style layout option -draw instead. Specifies as a per-state option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn.

-fill color

Specifies as a per-state option the color to be used to fill the rectangle's area. If the color for a certain state is an empty string (the default), then the rectangle will not be filled (but the outline may still be drawn).

-height size

Specifies the height of the rectangle. If this value is unspecified (the default), the rectangle will be exactly as tall as its display area as determined by the style layout options.

-open open

Specifies as a per-state option which edges of the rectangle should be left open. This option may be used to get an incomplete drawing of the outline and rounded corners, often to give the appearance of the rectangle extending over adjacent columns or items. Open is a string that contains zero or more of the characters n, s, e or w. Each letter refers to an edge (north, south, east, or west) on which the outline and rounded corners will not be drawn. The default is the empty string, which causes all rounded corners and the outline to be drawn.

-outline color

Specifies as a per-state option the color to be used to draw the outline of the rectangle. If the color for a certain state is an empty string (the default), then no outline is drawn for the rectangle.

-outlinewidth outlineWidth

Specifies the width of the outline to be drawn around the rectangle's region. outlineWidth may be in any of the forms acceptable to Tk_GetPixels. If this option is specified as an empty string (the default), then no outline is drawn.

-rx radius
-ry radius

Specifies the x and y radius of each corner of a rounded rectangle in any of the forms acceptable to Tk_GetPixels.

-showfocus boolean

Specifies a boolean value indicating whether a "focus ring" should be drawn around the rectangle, if the item containing the rectangle is the active item and the treectrl widget currently has the focus. If this option is specified as an empty string (the default), then a focus rectangle is not drawn.

-width size

Specifies the width of the rectangle. If this value is unspecified (the default), the rectangle will be exactly as wide as its display area as determined by the style layout options.

TEXT ELEMENT

An element of type text can be used to display a text in an item. The following options are supported for text elements:

-draw boolean

Deprecated; use the style layout option -draw instead. Specifies as a per-state option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn.

-data data

Specifies a value that together with the -datatype and -format options will be displayed as text.

-datatype dataType

Specifies the type of information in the -data option. Acceptable values are double, integer, long, string, or time.

-fill color

Specifies as a per-state option the foreground color to use when displaying text.

In items, if the color for a certain state is an empty string (the default), then the text will be displayed using the color specified by the treectrl's -foreground option.

In headers, if the color for a certain state is an empty string, then the text will be displayed using the system theme color on Gtk+; if that color is not specified then the -headerforeground option is used.

-font font

Specifies as a per-state option the font to use when displaying the text. If the font for a certain state is an empty string, the text is displayed using the font specified by the treectrl's -font option in items or the -headerfont option in headers.

-format formatString

This option specifies the format string used to display the value of the -data option. If -datatype is time, formatString should be a valid format string for the Tcl clock command. For all other -datatype values formatString should be a valid format string for the Tcl format command. If this value is unspecified the following defaults are used: for -datatype double "%g", for -datatype integer "%d", for -datatype long "%ld", for -datatype string "%s", and for -datatype time the default format string of the Tcl clock command.

-justify how

Specifies how to justify the text when multiple lines are displayed. How must be one of the values left, right, or center. If this option is specified as an empty string (the default), left is used.

-lines lineCount

Specifies the maximum number of lines to display. If more than lineCount lines would be displayed, the last line will be truncated with an ellipsis at the right. If this option is specified as zero or an empty string (the default), there is no limit to the number of lines displayed.

-lmargin1 pixels

Pixels is a screen distance that specifies how much a line of text should be indented. If a line of text wraps, this option only applies to the first line on the display; the -lmargin2 option controls the indentation for subsequent lines. If this option is specified as zero or an empty string (the default), then the line is not indented. This option was based on the Tk Text widget tag option of the same name.

-lmargin2 pixels

Pixels is a screen distance that specifies how much a line of text should be indented. If a line of text wraps, this option only applies to the second and later display lines for a line of text. If this option is specified as zero or an empty string (the default), then the line is not indented. This option was based on the Tk Text widget tag option of the same name.

-text string

String specifies a string to be displayed by the element. String may contain newline characters in which case multiple lines of text will be displayed. If this option is specified, the -data, -datatype, -format, and -textvariable options are ignored.

-textvariable varName

Specifies the name of a variable. The value of the variable is a string to be displayed by the element; if the variable value changes then the element will automatically update itself to display the new value. If this option is specified, the -data, -datatype, and -format options are ignored.

-underline charIndex

Specifies the integer index of a character to underline. 0 corresponds to the first character. If charIndex is unspecified (the default), less than zero or greater than the index of the last displayed character, the underline is not drawn.

-width size

Specifies the maximum line length in any of the forms acceptable to Tk_GetPixels. For text to wrap lines the value of the -width option must be less than the needed width of the text, or the display area for this element must be less than the needed width of the text. For the display area to be less than the needed width of the text, one of the style layout options -maxwidth, -width or -squeeze must be used.

-wrap mode

Mode specifies how to handle lines in the text that are longer than the maximum line length. Acceptable values are none, char or word. If this option is unspecified (the default), word is used. See the -width option for a description of how the maximum line length is determined.

WINDOW ELEMENT

An element of type window can be used to display a Tk window in an item. The following options are supported for window elements:

-clip boolean

Specifies whether the associated Tk window is a borderless frame which should be used to clip its child window so it doesn't overlap the header, borders, or other items or columns. When this option is true, the treectrl manages the geometry of both the -window widget and its first child widget; in this case the -window widget (which should be a borderless frame) is kept sized and positioned so that it is never out-of-bounds.

-destroy boolean

Specifies whether the associated Tk window should be destroyed when the element is deleted. The element is deleted when the item containing the element is deleted, when the column containing the element is deleted, or when the style assigned to the item's column is changed. If this option is unspecified (the default), it is treated as false and the Tk window will not be destroyed.

-draw boolean

Deprecated; use the style layout option -draw instead. Specifies as a per-state option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn.

-window pathName

Specifies the window to associate with this element. The window specified by pathName must either be a child of the treectrl widget or a child of some ancestor of the treectrl widget. PathName may not refer to a top-level window. This option cannot be specified by the element create or element configure commands, only by the item element configure command; i.e., the element must be associated with a particular item.

ITEM DESCRIPTION

Many of the commands for a treectrl take as an argument a description of which items to operate on. An item description is a properly-formed tcl list of keywords and arguments. The first word of an item description must be one of the following:

id

Specifies the unique item identifier, where id should be the return value of a prior call of the item create widget command, or 0 to specify the ever-present root item. See also the -itemprefix option.

QUALIFIERS

Specifies a list of qualifiers. This gives the same result as all followed by QUALIFIERS; i.e., every item is tested for a match.

tagExpr QUALIFIERS

TagExpr is a tag expression (see ITEM AND COLUMN TAGS) against which every item's tags are tested for a match. This keyword cannot be followed by any modifiers unless a single item is matched. You may run into trouble if tagExpr looks like an item id or other keyword; also, tagExpr must look like a single list element since item descriptions are properly-formed lists. To be safe you may want to use the tag qualifier followed by tagExpr.

active

Indicates the item that is currently active, i.e. normally the item specified as argument of the last successful activate widget command, or the root item if no such call happened yet.

anchor

Indicates the anchor item of the selection, i.e. normally the item specified as argument of the last successful selection anchor widget command, or the root item if no such call happened yet.

all QUALIFIERS

Indicates every item including orphans which match QUALIFIERS. This keyword cannot be followed by any modifiers unless a single item is matched.

first QUALIFIERS

Indicates the first item of the treectrl (the root item), or the first item matching QUALIFIERS.

end QUALIFIERS
last QUALIFIERS

Indicates the last item which matches QUALIFIERS.

list itemDescs

ItemDescs is a list (a single argument, i.e. "list {a b c}" not "list a b c") of other item descriptions. This keyword cannot be followed by any modifiers unless a single item is matched.

nearest x y

Indicates the item nearest to the point given by x and y.

rnc row column

Indicates the item in the given row and column. The row and column corresponds to the on-screen arrangement of items as determined by the -orient and -wrap options. You can memorize rnc as an abbreviation of "row 'n' column".

range first last QUALIFIERS

First and last specify a range of items. This keyword cannot be followed by any modifiers unless a single item is matched.

root

Indicates the root item of the treectrl.

The initial part of the item description (matching any of the values above) may be followed by one or more modifiers. A modifier changes the item used relative to the description up to this point. It may be specified in any of the following forms:

above

Use the item one row above in this column.

ancestors QUALIFIERS

Use the ancestors of the item (like item ancestors but QUALIFIERS may change which ancestors match). This keyword cannot be followed by any modifiers.

below

Use the item one row below in this column.

bottom

Use the item in the last row of this column.

child n QUALIFIERS

Use the nth child of the item.

children QUALIFIERS

Use the children of the item (like item children but QUALIFIERS may change which children match). This keyword cannot be followed by any modifiers.

descendants QUALIFIERS

Use the descendants of the item (like item descendants but QUALIFIERS may change which descendants match). This keyword cannot be followed by any modifiers.

firstchild QUALIFIERS

Use the first child of the item.

lastchild QUALIFIERS

Use the last child of the item.

left

Use the item one column to the left in the same row.

leftmost

Use the item of the first column in the same row.

next QUALIFIERS

Use the next item, which is the first item from the following list: the first child, the next sibling or the next sibling of the nearest ancestor which has one.

nextsibling QUALIFIERS

Use the next sibling of the item.

parent

Use the parent of the item.

prev QUALIFIERS

Use the last child of the previous sibling, or the parent if there is no previous sibling.

prevsibling QUALIFIERS

Use the previous sibling of the item.

right

Use the item one column to the right in the same row.

rightmost

Use the item of the last column in the same row.

sibling n QUALIFIERS

Use the nth child of the item's parent.

top

Use the item in the first row of this column.

The word QUALIFIERS above represents a series of zero or more of the following terms that changes which item is chosen:

depth depth

Matches items whose depth (as returned by the depth command) is equal to depth.

state stateList

StateList is a list of item state names (static and dynamic, see STATES). Only items that have the given states set (or unset if the '!' prefix is used) are considered.

tag tagExpr

TagExpr is a tag expression (see ITEM AND COLUMN TAGS) against which an item's tags are tested for a match.

visible

When this qualifier is given, only items that are displayed are considered.

!visible

When this qualifier is given, only items that are *not* displayed are considered.

To get the first item in the list that is enabled:

$T item id "first state enabled"

To get the ancestors that are not open of the last item in the list:

$T item id "last ancestors state !open"

To get the visible descendants of the root item:

$T item id "root descendants visible"

To get the every hidden item with tag "a" or "b":

$T item id "all !visible tag a||b"
$T item id "!visible tag a||b"
$T item id "tag a||b !visible"
$T item id "a||b !visible"

EVENTS AND SCRIPT SUBSTITUTIONS

The script argument to notify bind is a Tcl script, which will be evaluated whenever the given event is generated. Script will be executed in the same interpreter that the notify bind command was executed in, and it will run at global level (only global variables will be accessible). If script contains any % characters, then the script will not be evaluated directly. Instead, a new script will be generated by replacing each %, and the character following it, with information from the current event. Unlike the regular Tk bind mechanism, each event generated by a treectrl widget has its own set of %-substitutions.

The following %-substitutions are valid for all static events:

%%

Replaced with a single %

%d

The detail name

%e

The event name

%P

The pattern, either <event> or <event-detail>

%W

The object argument to the notify bind command

%T

The treectrl widget which generated the event

%?

A list of the format {char value char value ...} for each %-substitution character and the value it is replaced by

The following events may be generated by a treectrl widget:

<ActiveItem>

Generated whenever the active item changes.

%c

The current active item

%p

The previous active item

<Collapse-before>

Generated before an item is collapsed.

%I

The item id

<Collapse-after>

Generated after an item is collapsed.

%I

The item id

<Expand-before>

Generated before an item is expanded. This event is useful if you want to add child items to the item just before the item is expanded.

%I

The item id

<Expand-after>

Generated after an item is expanded.

%I

The item id

<ItemDelete>

Generated when items are about to be deleted by the item delete command.

%i

List of items ids being deleted.

<ItemVisibility>

Generated when items become visible on screen and when items are no longer visible on screen. This event is useful if you have a very large number of items and want to assign styles only when items are actually going to be displayed.

%h

List of items ids which are no longer visible.

%v

List of items ids which are now visible.

<Scroll-x>

Generated whenever the view in the treectrl changes in such a way that a horizontal scrollbar should be redisplayed.

%l

Same as the first fraction appended to -xscrollcommand. Think lower.

%u

Same as the second fraction appended to -xscrollcommand. Think upper.

<Scroll-y>

Generated whenever the view in the treectrl changes in such a way that a vertical scrollbar should be redisplayed.

%l

Same as the first fraction appended to -yscrollcommand. Think lower.

%u

Same as the second fraction appended to -yscrollcommand. Think upper.

<Selection>

Generated whenever the selection changes. This event gives information about how the selection changed.

%c

Same as the selection count widget command

%D

List of newly-deselected item ids

%S

List of newly-selected item ids

DYNAMIC EVENTS

In addition to the pre-defined static events such as <ActiveItem> and <Selection>, new dynamic events can be created by using the notify install command.

The library scripts provide an example of using a dynamic event called <Header-invoke>, which is generated when the mouse button is clicked and released over a column header.

# Example application code
treectrl .t
.t notify install <Header-invoke>
.t notify bind MyTag <Header-invoke> {
	puts "column header %C clicked in header-row %H in treectrl %T"
}
# Library code in treectrl.tcl
proc ::TreeCtrl::Release1 {w x y} {
	...
	$w notify generate <Header-invoke> [list H $Priv(header) C $Priv(column)] \
		[list ::TreeCtrl::PercentsCmd $w]
	...
}

In the example above, a new treectrl widget is created and the <Header-invoke> event is installed. A script is bound to the event with notify bind which will print out the column ID, header ID and widget name to the console. In a real application, any script bound to <Header-invoke> would be used to sort the list based on the column header that was clicked.

Note there is no percentsCommand argument to notify install; instead, the call to notify generate specifies the %-substitution command. The charMap argument to notify generate provides a list of %-substitution characters and values which is used by ::TreeCtrl::PercentsCmd. In the example, any %C in any script bound to the <Header-invoke> event would be replaced by the value of $Priv(column), and %H would be replaced by $Priv(header). The library procedure ::TreeCtrl::PercentsCmd also supports the same common %-substitution characters as the built-in static events, such as %T, %P, %? etc.

The following dynamic events may be generated by the library scripts:

<ColumnDrag-begin>

This event is generated just after the user begins dragging a column header. At the time this event is generated, the header dragconfigure option -imagecolumn is set to the unique ID of the column being dragged, the -imageoffset option is set to the horizontal distance the mouse pointer has moved, and the -imagespan option is set to the span of the column header that was initially clicked.

<ColumnDrag-indicator>

This event is generated each time a new place to drop the dragged column header is found. At the time this event is generated, the header dragconfigure option -indicatorcolumn is set to the unique ID of the column before or after which the dragged column will be dropped, and the -indicatorspan option is set to the span of the column header for this newly-chosen indicator column.

<ColumnDrag-receive>

This event is generated when the user has successfully dragged and dropped a column header to a new position. The library scripts do not actually move the dragged column. You must bind a script to this event to move the column. See EXAMPLES.

<ColumnDrag-end>

This event is generated after the user finally releases the left mouse button while dragging a column header. This event is generated after all the other <ColumnDrag> events even when the column wasn't dragged to a new location (i.e., even when no <ColumnDrag-receive> event was generated).

%H

The header-row that contains the column header.

%C

The column whose header is dragged within the header-row.

%b

The column to move the dragged column(s) before. Valid for <ColumnDrag-receive> only.

<Drag-begin>
<Drag-receive>
<Drag-end>

Generated whenever the user drag-and-drops a file into a directory. This event is generated by the filelist-bindings.tcl library code, which is not used by default. See the "Explorer" demos.

%I

The item that the user dropped the dragged items on.

%l

(lowercase L) The list of dragged items.

<Edit-begin>
<Edit-accept>
<Edit-end>

The filelist-bindings.tcl code will display a text-editing window if the user clicks on a selected file/folder name. See the "Explorer" demos.

%I

The item containing the edited text element.

%C

The column containing the edited text element.

%E

The name of the edited text element.

%t

The edited text.

<Header-invoke>

Generated whenever the user clicks and releases the left mouse button in a column header if the column header's -button option is true. You can bind a script to this event to sort the list.

%H

The header-row that contains the column header.

%C

The column whose header was clicked.

<Header-state>

Generated when the column header option -state is changed by the library scripts during Motion and Button events.

%H

The header-row that displays the column header.

%C

The column within the header-row whose header option -state changed.

%s

The new value of the column header option -state.

DEFAULT BINDINGS

Tk automatically creates class bindings for treectrl widgets that give them the following default behavior.

  1. Clicking mouse button 1 over an item positions the active cursor on the item, sets the input focus to this widget, and resets the selection of the widget to this item, if it is not already in the selection.

  2. Clicking mouse button 1 with the Control key down will reposition the active cursor and add the item to the selection without ever removing any items from the selection.

  3. If the mouse is dragged out of the widget while button 1 is pressed, the treectrl will automatically scroll to make more items visible (if there are more items off-screen on the side where the mouse left the window).

  4. The Left and Right keys move the active cursor one item to the left or right; for an hierarchical tree with vertical orientation nothing will happen, since it has no two items in the same row. The selection is set to include only the active item. If Left or Right is typed with the Shift key down, then the active cursor moves and the selection is extended to include the new item.

  5. The Up and Down keys move the active cursor one item up or down. The selection is set to include only the active item. If Up or Down is typed with the Shift key down, then the active cursor moves and the selection is extended to include the new item.

  6. The Next and Prior keys move the active cursor forward or backwards by one screenful, without affecting the selection.

  7. Control-Next and Control-Prior scroll the view right or left by one page without moving the active cursor or affecting the selection. Control-Left and Control-Right behave the same.

  8. The Home and End keys scroll to the left or right end of the widget without moving the active cursor or affecting the selection.

  9. The Control-Home and Control-End keys scroll to the top or bottom of the widget, they also activate and select the first or last item. If also the Shift key is down, then the active cursor moves and the selection is extended to include the new item.

  10. The Space and Select keys set the selection to the active item.

  11. Control-/ selects the entire contents of the widget.

  12. Control-\\ clears any selection in the widget.

  13. The + and - keys expand or collapse the active item, the Return key toggles the active item.

  14. The mousewheel scrolls the view of the widget four lines up or down depending on the direction, the wheel was turned. The active cursor or the selection is not affected.

GRADIENTS

Color gradients are an easy way to give your lists a more modern appearance. Since Tk provides no support for drawing gradients, the TkPath extension was used as a guide when implementing gradients in TkTreeCtrl. The current implementation has some limitations, however:

  1. Only linear gradients are supported.

  2. Gradients can only be painted left-to-right or top-to-bottom, not at arbitrary angles.

  3. Gradients look bad on low-color displays. Before using gradients, you should check that the display's color depth is at least 15 or 16 by calling the winfo depth command.

  4. Gradients are fully opaque when XFillRectangle() is used to draw them (see below). This means the opacity value of each color stop is ignored. Keep that in mind if your application is cross-platform.

  5. Rounded rectangles cannot be filled or outlined with a gradient when XFillRectangle() is used to draw gradients (see below). Instead, the rounded rectangle is painted with the gradient's first -stops color.

Gradients may be used in the following places:

  1. The -gridleftcolor and -gridrightcolor options of columns.

  2. The -itembackground option of columns.

  3. The -fill and -outline options of rect elements.

  4. The -fill and -outline options of the marquee configure command.

On Microsoft Windows, GDI+ is used where it is available (gdiplus.dll is dynamically loaded at run-time). On Mac OS X, CoreGraphics is used to draw gradients. With the Gtk+ build of treectrl, libcairo is used to draw gradients. When native gradient support is available, all the talk below about -steps can safely be ignored.

When no native support for gradients is available, gradients are drawn simply by filling sub-rectangles using XFillRectangle(). The number of sub-rectangles drawn and number of colors that make up the displayed gradient are controlled by the gradient's -steps and -stops options. The number of sub-rectangles is equal to the length of the -stops option multiplied by the value of the -steps option. For example:

$T gradient create myGradient -stops {{0 white} {1 gray}} -steps 8

This gradient will be drawn with 2x8=16 sub-rectangles of color. The higher the -steps value, the smoother the color transitions will be, and the slower the gradient will be to draw. For the best appearance, make the number of sub-rectangles drawn less than or equal to the height or width of the gradient being drawn. So if you have a rect element 18 pixels tall, use a vertical gradient that has steps X stops=18. Avoid using gradients with steps X stops greater than the height or width of the rectangle being drawn, because then colors will overlap.

GRADIENT COORDINATES

By default, a gradient brush is exactly the same size as whatever rectangle is being painted. For example, if a column's -itembackground option specifies a gradient name, then the background of an item is painted with all the colors of the gradient. So a vertical gradient from blue to green will start blue at the top and end with green at the bottom of every item.

By specifying any of the -bottom, -left, -right or -top gradient options the size of the gradient brush does not need to match that of the rectangle being painted. These options can be used to make a gradient appear to span across the entire width or height of the treectrl window, or across the entire canvas, for example.

There is no point specifying -left or -right if the gradient is vertical, since the gradient's colors are constant horizontally, so changing the horizontal size of the brush won't change the appearance of the gradient. The same reasoning applies for the -top and -bottom options for a horizontal gradient.

package require treectrl
set T [treectrl .t -itemheight 20 -showheader no]
$T gradient create G1 -orient vertical -top {0.0 canvas} -bottom {1.0 canvas} \
	-stops {{0.0 blue} {0.5 green} {1.0 red}} -steps 25
$T column create -expand yes -itembackground G1
pack $T -expand yes -fill both

EXAMPLES

Get the unique identifier for the leftmost visible column:

set id [$T column index "first visible"]

Delete the leftmost column:

$T column delete "order 0"

Take the visible column that is to the left of the last column, and move that column in front of the tail column:

$T column move "last prev visible" tail

Get the unique identifier for the first visible item:

set id [$T item index "first visible"]

Delete the parent of the item that is under the point x,y:

$T item delete "nearest $x $y parent"

Add the 10th child of the second child of the root item to the selection:

$T selection add "root firstchild nextsibling child 10"

Move a column that the user drag-and-dropped:

$T header dragconfigure -enable yes
$T notify install <ColumnDrag-receive>
$T notify bind MyTag <ColumnDrag-receive> {
	%T column move %C %b
}

See Also

bind(n), bitmap(n), image(n), listbox(n), options(n)

Keywords

tree, widget

tktreectrl-2.4.1/doc/treectrl.man0000644000076400010400000063720111646360367017326 0ustar TimAdministrators[comment {Copyright (c) 2002-2003 Christian Krone. See the file "license.terms" for information on usage and redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.} ] [manpage_begin treectrl n 2.4.1] [moddesc {Tk Commands}] [titledesc {Create and manipulate hierarchical multicolumn widgets}] [require treectrl 2.4.1] [description] [list_begin definitions] [call [cmd treectrl] [arg pathName] [opt [arg options]]] [list_end] [para] The [cmd treectrl] command creates a new window (given by the [arg pathName] argument) and makes it into a treectrl widget. Additional options, described above, may be specified on the command line or in the option database to configure aspects of the treectrl such as its background color and relief. The [cmd treectrl] command returns the path name of the new window. At the time this command is invoked, there must not exist a window named [arg pathName], but [arg pathName]'s parent must exist. [para] A treectrl is a listbox widget which displays items in a one- or two-dimensional arrangement. Items have a parent-child relationship with other items. Items may be arranged from top-to-bottom or from left-to-right. Items may be spread about one or more columns. Each item-column may be configured to span one or more adjacent item-columns. The visibility of items can be set individually. [para] Items have a set of states, which are boolean properties. For each column of an item there is a style associated, which determines how to display the item's column taking into account the item's current state set. New states may be defined to further control the appearance of items; these custom states may be turned on or off in individual columns of items. [para] Multiple rows of column headers are supported. Column headers have platform-native appearance on Windows, Mac OS X, and Gtk+. The appearance of column headers may be customized using styles. [para] Columns may be rearranged by the user using drag-and-drop. One column can be specified to display the data in a hierarchical structure. The visibility of columns can be set individually. [para] A treectrl can display a user-resizable selection rectangle called the marquee. Another feature, the drag image, may be used to provide feedback during drag-and-drop operations. Both of these are features commonly found in file browsers. [para] A treectrl can generate events when various things happen, such as changes to the selection, or a parent item being toggled open or closed. Scripts may be bound to these events. New events can be defined. [para] A treectrl can display a background image. The background image can be configured to be scrolled and tiled on each axis individually. [section {STANDARD OPTIONS}] [list_begin options] [opt_def [option -background]] [opt_def [option -borderwidth]] [opt_def [option -cursor]] [opt_def [option -font]] [opt_def [option -highlightbackground]] [opt_def [option -highlightcolor]] [opt_def [option -highlightthickness]] [opt_def [option -orient]] [opt_def [option -relief]] [opt_def [option -takefocus]] [opt_def [option -xscrollcommand]] [opt_def [option -yscrollcommand]] [opt_def [option -foreground]] [list_end] See the [cmd option] manual entry for details on the standard options. [section {WIDGET SPECIFIC OPTIONS}] [list_begin tkoptions] [tkoption_def -backgroundimage backgroundImage BackgroundImage] Specifies the name of an image to draw as the list background. Other options control whether the image is tiled and whether the image scrolls. If the image is transparent it is drawn on top of any column [option -itembackground] colors. [tkoption_def -backgroundmode backgroundMode BackgroundMode] Specifies how the background color of items is chosen in each column. The value should be one of [const row], [const column], [const order], or [const ordervisible]. The default is [const row]. This option has only an effect for columns which have [option -itembackground] defined as list of two or more colors (see section [sectref COLUMNS] below for more on this). If [const row] or [const column] is specified, the background color is chosen based on the location of the item in the 1- or 2-dimensional grid of items as layed out on the screen; this layout of items is affected by the [option -orient] and [option -wrap] options as well as item visibility. When [const order] or [const ordervisible] is specified, the background color is chosen based on the result of the [cmd {item order}] command, regardless of the layout of items. [tkoption_def -bgimage bgImage BgImage] Synonym for -backgroundimage. [tkoption_def -bgimageanchor bgImageAnchor BgImageAnchor] Specifies how the background image should be aligned in any of the forms acceptable to [fun Tk_GetAnchor]. Must be one of the values [const n], [const ne], [const e], [const se], [const s], [const sw], [const w], [const nw], or [const center]. The default is [const nw]. When the background image scrolls, the anchor position is relative to the [sectref {THE CANVAS} {canvas}], otherwise it is relative to the contentbox. [tkoption_def -bgimageopaque bgImageOpaque BgImageOpaque] Specifies a boolean indicating whether or not the background image is fully opaque. This is needed because there is no way in Tk to determine whether an image contains transparency or not. The default value is true, so if you use a transparent -backgroundimage you must set this to false. [tkoption_def -bgimagescroll bgImageScroll BgImageScroll] Specifies whether the background image scrolls along with the items or whether it remains locked in place relative to the edges of the window. The value must be a string that contains zero or more of the characters [const x] or [const y]. The default is [const xy]. [tkoption_def -bgimagetile bgImageTile BgImageTile] Specifies whether the background image is tiled along the x and/or y axes. The value must be a string that contains zero or more of the characters [const x] or [const y]. The default is [const xy]. [tkoption_def -buttonbitmap buttonBitmap ButtonBitmap] Specifies the name of a bitmap be used to display the expand/collapse button of an item. This is a [sectref {PER-STATE OPTIONS} per-state] option. If a bitmap is specified for a certain item state, it overrides the effects of -usetheme. [tkoption_def -buttoncolor buttonColor ButtonColor] Specifies the foreground color which should be used for drawing the outline and the plus or minus sign of an item's expand/collapse button. [tkoption_def -buttonimage buttonImage ButtonImage] Specifies the name of an image to be used to display the expand/collapse button of an item. This is a [sectref {PER-STATE OPTIONS} per-state] option. If an image is specified for a certain item state, it overrides the effects of -buttonbitmap and -usetheme. [tkoption_def -buttonsize buttonSize ButtonSize] Specifies the width and height of the expand/collapse button of an item in any of the forms acceptable to [fun Tk_GetPixels]. [tkoption_def -buttonthickness buttonThickness ButtonThickness] Specifies the width of the outline and the plus or minus sign of the expand/collapse button of an item in any of the forms acceptable to [fun Tk_GetPixels]. [tkoption_def -buttonttracking buttonTracking ButtonTracking] Specifies a boolean that determines if the expand/collapse buttons are tracked like pushbuttons when clicking them. When true, buttons are not toggled until the event occurs over them. When false, buttons are toggled as soon as the event occurs over them. This option defaults to true on Mac OS X and Gtk+, false on Win32 and X11. [tkoption_def -canvaspadx canvasPadX CanvasPadX] Specifies the width of extra whitespace on the left and right edges of the [sectref {THE CANVAS} {canvas}] in any of the forms acceptable to [fun Tk_GetPixels]. The option value may be a list of one or two screen distances to specify padding for the two edges separately. The default is 0. [tkoption_def -canvaspady canvasPadY CanvasPadY] Specifies the height of extra whitespace on the top and bottom edges of the [sectref {THE CANVAS} {canvas}] in any of the forms acceptable to [fun Tk_GetPixels]. The option value may be a list of one or two screen distances to specify padding for the two edges separately. The default is 0. [tkoption_def -columnprefix columnPrefix ColumnPrefix] Specifies an ascii string that changes the way column ids are reported and processed. If this option is a non-empty string, the usual integer value of a column id is prefixed with the given string. This can aid debugging but it is important your code doesn't assume column ids are integers if you use it. [tkoption_def -columnproxy columnProxy ColumnProxy] If this option specifies a non empty value, it should be a screen distance in any of the forms acceptable to [fun Tk_GetPixels]. Then a 1 pixel thick vertical line will be drawn at the specified screen distance from the left edge of the treectrl widget, which reaches from top to bottom of the treectrl widget and uses an inverting color (i.e black on lighter background, white on darker background). This line can be used to give the user a visual feedback during column resizing. [tkoption_def -columnresizemode columnResizeMode ColumnResizeMode] Specifies the visual feedback used when resizing columns. The value should be one of [const proxy] or [const realtime]. For [const proxy], a 1-pixel thick vertical line is drawn representing where the right edge of the column will be after resizing. For [const realtime], the column's size is changed while the user is dragging the right edge of the column. The default is [const realtime]. [tkoption_def -columntagexpr columnTagExpr ColumnTagExpr] Specifies a boolean that enables or disables tag expressions in column descriptions. See [sectref {ITEM AND COLUMN TAGS}]. [tkoption_def -defaultstyle defaultStyle DefaultStyle] This option is deprecated; use the column option [option -itemstyle] instead. Specifies a list of styles, one per column, to apply to each item created by the [cmd "item create"] command. The number of styles in the list can be different from the number of tree columns. Each list element should be a valid style name or an empty string to indicate no style should be applied to a specific column. The list of styles is updated if a style is deleted or if a column is moved. [tkoption_def -doublebuffer doubleBuffer DoubleBuffer] This option no longer has any effect, but was left in for compatibility. It used to control the amount of double-buffering that was used when displaying a treectrl. [tkoption_def -headerfont headerFont Font] Specifies the font to draw text in column headers with. The default value is TkHeadingFont where available (on Tk 8.5+). This option can be overridden by setting the [option -font] option for individual column headers. [tkoption_def -headerfg headerForeground Foreground] Synonym for -headerforeground. [tkoption_def -headerforeground headerForeground Foreground] Specifies the color to draw text in column headers with. The default value is the Tk button foreground color (usually black). On Gtk+, the system theme may override this color. This option (and the Gtk+ system theme color) can be overridden by setting the [option -textcolor] option for individual column headers. [tkoption_def -height height Height] Specifies the desired height for the window in any of the forms acceptable to [fun Tk_GetPixels]. The default is 200 pixels. If this option is less than or equal to zero then the window will not request any size at all. [tkoption_def -indent indent Indent] Specifies the screen distance an item is indented relative to its parent item in any of the forms acceptable to [fun Tk_GetPixels]. The default is 19 pixels. [tkoption_def -itemgapx itemGapX ItemGapX] Specifies the horizontal spacing between adjacent items in any of the forms acceptable to [fun Tk_GetPixels]. The default is 0. [tkoption_def -itemgapy itemGapY ItemGapY] Specifies the vertical spacing between adjacent items in any of the forms acceptable to [fun Tk_GetPixels]. The default is 0. [tkoption_def -itemheight itemHeight ItemHeight] Specifies a fixed height for every item in any of the forms acceptable to [fun Tk_GetPixels]. If non-zero, this option overrides the requested height of an item and the -minitemheight option. If an item's own -height option is specified then that is the height used for the item. In any case, items are never shorter than the maximum height of a button if they display one. The default is 0. [tkoption_def -itemprefix itemPrefix ItemPrefix] Specifies an ascii string that changes the way item ids are reported and processed. If this option is a non-empty string, the usual integer value of an item id is prefixed with the given string. This can aid debugging but it is important your code doesn't assume item ids are integers if you use it. [tkoption_def -itemtagexpr itemTagExpr ItemTagExpr] Specifies a boolean that enables or disables tag expressions in item descriptions. See [sectref {ITEM AND COLUMN TAGS}]. [tkoption_def -itemwidth itemWidth ItemWidth] Specifies a fixed width for every item in any of the forms acceptable to [fun Tk_GetPixels]. If more than one column is visible, then this option has no effect. If the -orient option is vertical, and the -wrap option is unspecified, then this option has no effect (in that case all items are as wide as the column). [tkoption_def -itemwidthequal itemWidthEqual ItemWidthEqual] Specifies a boolean that says whether all items should have the same width. If more than one column is visible, then this option has no effect. If the -orient option is vertical, and the -wrap option is unspecified, then this option has no effect (in that case all items are as wide as the column). If the -itemwidth option is specified, then this option has no effect. [tkoption_def -itemwidthmultiple itemWidthMultiple ItemWidthMultiple] Specifies a screen distance that every item's width will be evenly divisible by in any of the forms acceptable to [fun Tk_GetPixels]. If more than one column is visible, then this option has no effect. If the -orient option is vertical, and the -wrap option is unspecified, then this option has no effect (in that case all items are as wide as the column). If the -itemwidth option is specified, then this option has no effect. [tkoption_def -linecolor lineColor LineColor] Specifies the color which should be used for drawing the connecting lines between related items. [tkoption_def -linestyle lineStyle LineStyle] Specifies the appearance of the connecting lines between related items. The value should be [const dot], which is the default, or [const solid]. [tkoption_def -linethickness lineThickness LineThickness] Specifies the thickness of the connecting lines between related items in any of the forms acceptable to [fun Tk_GetPixels]. [tkoption_def -minitemheight minItemHeight MinItemHeight] Specifies a minimum height for every item in any of the forms acceptable to [fun Tk_GetPixels]. The default is 0, which means that every item has the height requested by the arrangement of elements in each column. This option has no effect if either the -itemheight widget option or -height item option is specified. In any case, items are never shorter than the maximum height of an expand/collapse button. [tkoption_def -rowproxy rowProxy RowProxy] If this option specifies a non empty value, it should be a screen distance in any of the forms acceptable to [fun Tk_GetPixels]. Then a 1 pixel thick horizontal line will be drawn at the specified screen distance from the top edge of the treectrl widget, which reaches from left to right of the treectrl widget and uses an inverting color (i.e black on lighter background, white on darker background). This line can be used to give the user a visual feedback during row resizing. [tkoption_def -scrollmargin scrollMargin ScrollMargin] Specifies a positive screen distance in any of the forms acceptable to [fun Tk_GetPixels]. This option is used by the default bindings to determine how close to the edges of the contentbox the mouse pointer must be before scrolling occurs. Specifying a positive value is useful when items may be drag-and-dropped. Defaults to 0. [tkoption_def -selectmode selectMode SelectMode] 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 [const single], [const browse], [const multiple], or [const extended]; the default value is [const browse]. [tkoption_def -showbuttons showButtons ShowButtons] Specifies a boolean value that determines whether this widget leaves indentation space to display the expand/collapse buttons next to items. The default value is true. The item option [option -button] determines whether an item has a button. See also the widget options [option -showrootbutton] and [option -showrootchildbuttons]. [tkoption_def -showheader showHeader ShowHeader] Specifies a boolean value that determines whether this widget should display the header line with the column names at the top of the widget. The default value is true. [tkoption_def -showlines showLines ShowLines] Specifies a boolean value that determines whether this widget should draw the connecting lines between related items. The default value is true on Win32 and X11, false on Mac OS X and Gtk+. [tkoption_def -showroot showRoot ShowRoot] Specifies a boolean value that determines whether this widget should draw the root item. By suppressing the drawing of the root item the widget can have multiple items that appear as toplevel items. The default value is true. [tkoption_def -showrootbutton showRootButton ShowRootButton] Specifies a boolean value that determines whether this widget leaves indentation space to display the expand/collapse button next to the root item. The default value is false. The item option [option -button] determines whether the root item has a button. [tkoption_def -showrootchildbuttons showRootChildButtons ShowRootChildButtons] Specifies a boolean value that determines whether this widget should draw the expand/collapse buttons next to children of the root item. The default value is true. [tkoption_def -showrootlines showRootLines ShowRootLines] Specifies a boolean value that determines whether this widget should draw the connecting lines between children of the root item. The default value is true. [tkoption_def -treecolumn treeColumn TreeColumn] Specifies a [sectref {COLUMN DESCRIPTION} {column description}] that determines which column displays the expand/collapse buttons and connecting lines between items. The default is unspecified. [tkoption_def -usetheme useTheme UseTheme] Specifies a boolean value that determines whether this widget should draw parts of itself using a platform-specific theme manager. The default is true. [tkoption_def -width width Width] Specifies the desired width for the window in any of the forms acceptable to [fun Tk_GetPixels]. The default is 200 pixel. If this option is less than or equal to zero then the window will not request any size at all. [tkoption_def -wrap wrap Wrap] Specifies whether items are arranged in a 1- or 2-dimensional layout. [para] If the value is an empty string (the default), then items are arranged from top to bottom (-orient=vertical) or from left to right (-orient=horizontal) in a 1-dimensional layout. [para] If the value is "[emph N] [const items]", then no more than [emph N] items will appear in a vertical group (-orient=vertical) or horizontal group (-orient=horizontal). [para] If the value is "[emph N] [const pixels]", then no vertical group of items will be taller than [emph N] pixels (-orient=vertical) or no horizontal group of items will be wider than [emph N] pixels (-orient=horizontal). [para] If the value is [const window], then a no vertical group of items will be taller than the window (-orient=vertical) or no horizontal group of items will be wider than the window (-orient=horizontal). [para] It is also possible to cause wrapping to occur on a per-item basis by using the item option -wrap. See the [cmd {item create}] command for that option. [tkoption_def -xscrolldelay xScrollDelay ScrollDelay] This option controls how quickly horizontal scrolling occurs while dragging the mouse with button 1 pressed. The value should be a list of 1 or 2 integers interpreted as milliseconds. If 2 values are specified, then the first value determines the intial delay after the first scroll, and the second value determines the delay for all scrolling after the first. If only 1 value is specified, each scroll takes place after that delay. [tkoption_def -xscrollincrement xScrollIncrement ScrollIncrement] Specifies an increment for horizontal scrolling, in any of the usual forms permitted for screen distances. If the value of this option is greater than zero, the horizontal view in the window will be constrained so that the [sectref {THE CANVAS} canvas] x coordinate at the left edge of the window is always an even multiple of [option -xscrollincrement]; furthermore, the units for scrolling (e.g., the change in view when the left and right arrows of a scrollbar are selected) will also be [option -xscrollincrement]. If the value of this option is less than or equal to zero, then horizontal scrolling snaps to the left of an item, or part of an item if items are wider than the contentbox. [tkoption_def -xscrollsmoothing xScrollSmoothing ScrollSmoothing] Specifies whether scrolling should be done as if -xscrollincrement=1 whenever scrolling is performed by non-unit amounts. When the value of this option is true and the xview command is called to scroll by "units", scrolling occurs according to the -xscrollincrement option, and all other scrolling is done as if the -xscrollincrement option was set to 1. The effect is that when dragging the scrollbar thumb scrolling is very smooth, but when clicking the scrollbar buttons scrolling is done in coarser increments. The default value is false. [tkoption_def -yscrolldelay yScrollDelay ScrollDelay] This option controls how quickly vertical scrolling occurs while dragging the mouse with button 1 pressed. The value should be a list of 1 or 2 integers interpreted as milliseconds. If 2 values are specified, then the first value determines the intial delay after the first scroll, and the second value determines the delay for all scrolling after the first. If only 1 value is specified, each scroll takes place after that delay. [tkoption_def -yscrollincrement yScrollIncrement ScrollIncrement] Specifies an increment for vertical scrolling, in any of the usual forms permitted for screen distances. If the value of this option is greater than zero, the vertical view in the window will be constrained so that the [sectref {THE CANVAS} canvas] y coordinate at the top edge of the window is always an even multiple of [option -yscrollincrement]; furthermore, the units for scrolling (e.g., the change in view when the top and bottom arrows of a scrollbar are selected) will also be [option -yscrollincrement]. If the value of this option is less than or equal to zero, then vertical scrolling snaps to the top of an item, or part of an item if items are taller than the contentbox. [tkoption_def -yscrollsmoothing yScrollSmoothing ScrollSmoothing] Specifies whether scrolling should be done as if -yscrollincrement=1 whenever scrolling is performed by non-unit amounts. When the value of this option is true and the yview command is called to scroll by "units", scrolling occurs according to the -yscrollincrement option, and all other scrolling is done as if the -yscrollincrement option was set to 1. The effect is that when dragging the scrollbar thumb scrolling is very smooth, but when clicking the scrollbar buttons scrolling is done in coarser increments. The default value is false. [list_end] [section {THE CANVAS}] Throughout this manual page the term [emph canvas] is sometimes used. The canvas can be thought of as the virtual sheet of paper upon which all visible items are drawn. The treectrl window displays different areas of the canvas within its borders as the list is scrolled. [section {ITEM AND COLUMN TAGS}] Columns and items may have any number of tags associated with them. A tag is just a string of characters, and it may take any form, including that of an integer, although the characters '(', ')', '&', '|', '^' and '!' should be avoided. [para] The same tag may be associated with many columns or items. This is commonly done to group items in various interesting ways; for example, in a file browser all directories might be given the tag "directory". [para] Tag expressions are used in [sectref {COLUMN DESCRIPTION} {column descriptions}] and [sectref {ITEM DESCRIPTION} {item descriptions}] to specify which columns and items to operate on. A tag expression can be a single tag name or a logical expression of tags using operators '&&', '||', '^' and '!', and parenthesized subexpressions. For example: [example_begin] .t item id "tag {(a && !b) || (!a && b)}" [example_end] or equivalently: [example_begin] .t item id "tag {a ^ b}" [example_end] will return the unique ids of any items with either "a" or "b" tags, but not both. [para] Within a tag expression a tag name may be enclosed in double quotes to avoid special processing of the operator characters. For example: [example_begin] .t item id {tag {"a&&b"||c}} [example_end] will return the unique ids of any items with either "a&&b" or "c" tags; in this example the && is not treated as an operator. A double-quote may be escaped within a quoted tag name using a backslash '\'. [para] Tag operators may be bypassed completely by setting the [option -columntagexpr] and [option -itemtagexpr] options. This can be useful if your application has column or item tags containing arbitrary text. [example_begin] .t configure -itemtagexpr false .t item delete "tag a&&b" [example_end] [section {WIDGET COMMAND}] The [cmd treectrl] command creates a new Tcl command whose name is the same as the path name of the treectrl's window. This command may be used to invoke various operations on the widget. It has the following general form: [para] [arg pathName] [arg option] [opt [arg {arg arg ...}]] [para] [arg PathName] is the name of the command, which is the same as the treectrl widget's path name. [arg Option] and the [arg arg]s determine the exact behavior of the command. The following commands are possible for treectrl widgets: [list_begin definitions] [call [arg pathName] [cmd activate] [arg itemDesc]] Sets the active item to the one described by [arg itemDesc], and switches on the state [const active] for that item. The active item can be referred to by the item description [const active]. If this command changes which item is active an [const ] event is generated. If the active item is deleted the root item becomes the new active item. [call [arg pathName] [cmd bbox] [opt [arg area]]] Returns a list with four elements giving the bounding box (left, top, right and bottom) of an area of the window. If [arg area] is not specified, then the result is the bounding box of the entire window. If [arg area] is [const content], then the result is the part of the window not including borders, headers, or locked columns. If [arg area] is [const header], then the result is the part of the window not including borders where column titles are displayed. If [arg area] is [const left], then the result is the part of the window not including borders or headers where left-locked columns are displayed. If [arg area] is [const right], then the result is the part of the window not including borders or headers where right-locked columns are displayed. [para] If [arg area] is one of [const header.left], [const header.none] or [const header.right] then the area of the column headers occupied by columns with -lock=left, -lock=none or -lock=right is returned. [para] An empty string is returned if the display area has no height or width, which can be true for various reasons such as the window is too small, or the header is not displayed, or there aren't any locked columns. [call [arg pathName] [cmd canvasx] [arg windowx]] Translates the given window x-coordinate [arg windowx] in the treectrl to [sectref {THE CANVAS} {canvas}] coordinate space. The [cmd marquee] command expects canvas coordinates. [call [arg pathName] [cmd canvasy] [arg windowy]] Translates the given window y-coordinate [arg windowy] in the treectrl to [sectref {THE CANVAS} {canvas}] coordinate space. The [cmd marquee] command expects canvas coordinates. [call [arg pathName] [cmd cget] [arg option]] Returns the current value of the configuration option given by [arg option]. [arg Option] may have any of the values accepted by the [cmd tree] command. [call [arg pathName] [cmd collapse] [opt [option -recurse]] \ [opt [arg {itemDesc ...}]]] Deprecated. Use [cmd {item collapse}] instead. [call [arg pathName] [cmd column] [arg option] [arg column] \ [opt [arg {arg ...}]]] This command is used to manipulate the columns of the treectrl widget (see section [sectref COLUMNS] below). The exact behavior of the command depends on the [arg option] argument that follows the [cmd column] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {column bbox}] [arg columnDesc]] Returns a list with four elements giving the bounding box of the header of the column specified by the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc]. The returned coordinates are relative to the top-left corner of the widget. If the column option [option -visible]=false or if the widget option [option -showheader]=false, then an empty list is returned. [call [arg pathName] [cmd {column cget}] [arg columnDesc] [arg option]] This command returns the current value of the option named [arg option] for the column specified by the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc], [arg ColumnDesc] may also be the string [const tail] to specify the tail column. [arg Option] may have any of the values accepted by the [cmd {column configure}] widget command. [call [arg pathName] [cmd {column configure}] [arg columnDesc] \ [opt [arg option]] [opt [arg value]] [opt [arg {option value ...}]]] This command is similar to the [cmd configure] widget command except that it modifies options associated with the columns specified by the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc] instead of modifying options for the overall treectrl widget. [arg ColumnDesc] may be the string [const tail] to specify the tail column. If [arg columnDesc] refers to more than one column, then at least one option-value pair must be given. If no [arg option] is specified, the command returns a list describing all of the available options for [arg columnDesc] (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no [arg value], 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 [arg option] is specified). If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given option(s) to have the given value(s) for [arg columnDesc]; in this case the command returns an empty string. [para] See [sectref COLUMNS] below for details on the options available for columns. [para] For compatibility with older versions of treectrl (which did not support more than one row of column headers) any of the configuration options mentioned in the [sectref HEADERS] section, such as [option -arrow], [option -text], etc, may be passed to the top header-row through this command. [call [arg pathName] [cmd {column compare}] [arg column1] [arg op] [arg column2]] For both [sectref {COLUMN DESCRIPTION} {column descriptions}] [arg column1] and [arg column2] the index is retrieved (as returned from the [cmd {column order}] widget command). Then these indexes are compared using the operator [arg op], which must be either [const <], [const <=], [const ==], [const >=], [const >], or [const !=]. The return value of this command is 1 if the comparison evaluated to true, 0 otherwise. [call [arg pathName] [cmd {column count}] [opt [arg columnDesc]]] If no additional arguments are given, the result is a decimal string giving the number of columns created by the [cmd "column create"] widget command which haven't been deleted by the [cmd "column delete"] widget command; in this case the [const tail] column is not counted. If [arg columnDesc] is given, then the result is the number of columns that match that [sectref {COLUMN DESCRIPTION} {column description}]. [call [arg pathName] [cmd {column create}] [opt [arg {option value ...}]]] This command creates a new column in the treectrl widget. The new column is placed to the right of all other columns (except the [const tail] column). Any [arg option]-[arg value] arguments configure the new column according to the [cmd "column configure"] command. The return value is the unique identifier of the new column. [call [arg pathName] [cmd {column delete}] [arg first] [opt [arg last]]] Deletes the specified column(s). [arg First] and [arg last] must be valid [sectref {COLUMN DESCRIPTION} {column descriptions}]. If both [arg first] and [arg last] are specified, then they may refer to a single column only. The [const tail] column cannot be deleted and it is an error to specify it. The order of [arg first] and [arg last] doesn't matter, and [arg first] may be equal to [arg last]. [call [arg pathName] [cmd {column dragcget}] [arg option]] Deprecated. Use [cmd {header dragcget}] instead. [call [arg pathName] [cmd {column dragconfigure}] \ [opt [arg option]] [opt [arg value]] [opt [arg {option value ...}]]] Deprecated. Use [cmd {header dragconfigure}] instead. [call [arg pathName] [cmd {column index}] [arg columnDesc]] Deprecated. Use [cmd {column id}] instead. [call [arg pathName] [cmd {column id}] [arg columnDesc]] This command resolves the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc] into a list of unique column identifiers. If the column(s) described by [arg columnDesc] don't exist, this command returns an empty list. [call [arg pathName] [cmd {column list}] [opt [arg -visible]]] This command returns a list of identifiers for every column (except the tail) from left to right. If [arg -visible] is given, only columns whose -visible option is true are returned. [call [arg pathName] [cmd {column move}] [arg columnDesc] [arg beforeDesc]] Moves the column specified by [arg columnDesc] to the left of the column specified by [arg beforeDesc]. Both [arg columnDesc] and [arg beforeDesc] must be valid [sectref {COLUMN DESCRIPTION} {column descriptions}]. If [arg beforeDesc] is the string [const tail], the column [arg columnDesc] will become the last column. [call [arg pathName] [cmd {column neededwidth}] [arg columnDesc]] This command returns a decimal string giving the needed width of the column specified by the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc]. The needed width is the maximum of the width of the column header and the width of the widest style in any visible item. [para] When an item style or column header spans multiple columns, the needed width of a column is affected by the widths of other columns in the span, in which case the result of this command isn't particularly useful. [call [arg pathName] [cmd {column order}] [arg columnDesc] [opt [arg -visible]]] This command returns a decimal string giving the position of the column specified by the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc] in the list of columns starting from zero for the leftmost column. If [arg -visible] is given, only columns whose -visible option is true are considered, and -1 is returned if [arg columnDesc]'s -visible option is false. [call [arg pathName] [cmd {column tag}] [arg option] [opt [arg {arg arg ...}]]] This command is used to manipulate tags on columns. The exact behavior of the command depends on the [arg option] argument that follows the [cmd {column tag}] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {column tag add}] [arg columnDesc] [arg tagList]] Adds each tag in [arg tagList] to the columns specified by the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc]. Duplicate tags are ignored. The list of tags for a column can also be changed via a column's [option -tags] option. [call [arg pathName] [cmd {column tag expr}] [arg columnDesc] [arg tagExpr]] Evaluates the tag expression [arg tagExpr] against every column specified by the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc]. The result is 1 if the tag expression evaluates to true for every column, 0 otherwise. [call [arg pathName] [cmd {column tag names}] [arg columnDesc]] Returns a list of tag names assigned to the columns specified by the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc]. The result is the union of any tags assigned to the columns. [call [arg pathName] [cmd {column tag remove}] [arg columnDesc] [arg tagList]] Removes each tag in [arg tagList] from the columns specified by the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc]. It is not an error if any of the columns do not use any of the tags. The list of tags for a column can also be changed via a column's [option -tags] option. [list_end] [call [arg pathName] [cmd {column width}] [arg columnDesc]] This command returns a decimal string giving the width in pixels of the column specified by the [sectref {COLUMN DESCRIPTION} {column description}] [arg columnDesc], even if the treectrl is configured to not display the column headers by means of the [option -showheader] option. [list_end] [call [arg pathName] [cmd compare] [arg itemDesc1] [arg op] [arg itemDesc2]] Deprecated. Use the [cmd {item compare}] command instead. [call [arg pathName] [cmd configure] [opt [arg option]] \ [opt [arg {value option value ...}]]] Query or modify the configuration options of the widget. If no [arg option] is specified, returns a list describing all of the available options for [arg pathName] (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no [arg value], 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 [arg option] is specified). If one or more [arg option]-[arg value] 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. [arg Option] may have any of the values accepted by the [cmd treectrl] command. [call [arg pathName] [cmd contentbox]] Returns a list with four elements giving the bounding box of the screen area used to display items. This is the area of the window not including borders, column headers, or locked columns. An empty string is returned if the display area has no height or width, which can happen if the window is too small. The result of this command is the same as that of [cmd {bbox content}]. [call [arg pathName] [cmd debug] [arg option] [opt [arg {arg arg ...}]]] This command is used to facilitate debugging of the treectrl widget. The exact behavior of the command depends on the [arg option] argument that follows the [cmd debug] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {debug alloc}]] Returns a string giving partial statistics on memory allocations, if the package was built with TREECTRL_DEBUG defined. [call [arg pathName] [cmd {debug cget}] [arg option]] This command returns the current value of the debugging option named [arg option]. [arg Option] may have any of the values accepted by the [cmd {debug configure}] widget command. [call [arg pathName] [cmd {debug configure}] \ [opt [arg option]] [opt [arg value]] [opt [arg {option value ...}]]] This command is similar to the [cmd configure] widget command except that it modifies debugging options instead of modifying options for the overall treectrl widget. If no [arg option] is specified, the command returns a list describing all of the available debugging options (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no [arg value], 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 [arg option] is specified). If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given debugging option(s) to have the given value(s); in this case the command returns an empty string. [para] The following debugging options are supported: [list_begin options] [opt_def [option -displaydelay] [arg millis]] Specifies a time duration in milliseconds, which should be waited after something has been drawn to the screen. Setting this option has only an effect, if the debugging options [option -enable] and [option -display] are switched on. [opt_def [option -data] [arg boolean]] If this option is switched on (together with the debugging option [option -enable]), at various places a consistence check on the internal data structure is made (e.g. for every item is checked, if the registered number of children is equal to the number of child items). If an inconsistency was found, a Tcl background error is raised. [opt_def [option -display] [arg boolean]] If this option is switched on (together with the debugging option [option -enable]), at varios places additional debugging output is printed to stdout. [opt_def [option -drawcolor] [arg color]] When specified, areas of the window are painted with this color when drawing in those areas is about to occur. Setting this option has only an effect if the debugging options [option -enable] and [option -display] are switched on. [opt_def [option -enable] [arg boolean]] All other debugging options only take effect if this option is also switched on. [opt_def [option -erasecolor] [arg color]] When specified, areas of the window which have been marked as "invalid" (for example, when part of the window is exposed) are painted with this color. If you use an unusual color for this option (like [const pink]), superflous screen redraws can be spotted more easily. Setting this option has only an effect if the debugging options [option -enable] and [option -display] are switched on. [opt_def [option -span] [arg boolean]] Debugging related to column spanning. [opt_def [option -textlayout] [arg boolean]] Debugging related to text-element layout. [list_end] [call [arg pathName] [cmd {debug dinfo}] [arg option]] Returns a string describing display-related stuff. [arg Option] must be one of [const alloc], [const ditem], [const onscreen] or [const range]. [call [arg pathName] [cmd {debug expose}] [arg x1] [arg y1] [arg x2] [arg y2]] Causes the area of the window bounded by the given window-coords to be marked as invalid. This simulates uncovering part of the window. [list_end] [call [arg pathName] [cmd depth] [opt [arg itemDesc]]] If the additional argument [arg itemDesc] is given, then the result is a decimal string giving the depth of the item described by [arg itemDesc]. If no [arg itemDesc] is specified, then the maximum depth of all items in the treectrl widget is returned instead. Depth is defined as the number of ancestors an item has. [call [arg pathName] [cmd dragimage] [arg option] [opt [arg {arg ...}]]] This command is used to manipulate the drag image, which is used to provide feedback when items are drag-and-dropped within the window. The drag image is displayed as the dotted outlines of one or more items, columns and/or elements. The exact behavior of the command depends on the [arg option] argument that follows the [cmd dragimage] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {dragimage add}] [arg itemDesc] \ [opt [arg column]] [opt [arg element]]] Adds the shapes of the item described by [arg itemDesc] to the shapes of the dragimage. Specifying additional arguments reduces the number of rectangles that are added to the dragimage. If no additional arguments is specified, for every element of the item in every column a dotted rectangles is added. If [arg column] is specified, all elements in other columns are ignored. If also [arg element] is specified, only a rectangle for this one element of the specified item in the given column is added. [call [arg pathName] [cmd {dragimage cget}] [arg option]] This command returns the current value of the dragimage option named [arg option]. [arg Option] may have any of the values accepted by the [cmd {dragimage configure}] widget command. [call [arg pathName] [cmd {dragimage clear}]] Removes all shapes (if there are any) from the dragimage. This command does not modify the dragimage offset. [call [arg pathName] [cmd {dragimage configure}] [opt [arg option]] \ [opt [arg value]] [opt [arg {option value ...}]]] This command is similar to the [cmd configure] widget command except that it modifies the dragimage options instead of modifying options for the overall treectrl widget. If no [arg option] is specified, the command returns a list describing all of the available dragimage options (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no [arg value], then the command returns a list describing the one named dragimage option (this list will be identical to the corresponding sublist of the value returned if no [arg option] is specified). If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given dragimage option(s) to have the given value(s); in this case the command returns an empty string. [para] The following dragimage options are supported: [list_begin options] [opt_def [option -visible] [arg boolean]] Specifies a boolean value which determines whether the dragimage should currently be visible. [list_end] [call [arg pathName] [cmd {dragimage offset}] [opt [arg {x y}]]] Returns a list containing the x and y offsets of the dragimage, if no additional arguments are specified. The dragimage offset is the screen distance the image is displayed at relative to the item(s) its shape is derived from. If two coordinates are specified, sets the dragimage offset to the given coordinates [arg x] and [arg y]. [list_end] [call [arg pathName] [cmd element] [arg option] [opt [arg element]] \ [opt [arg {arg arg ...}]]] This command is used to manipulate elements (see [sectref {ELEMENTS AND STYLES}] below). The exact behavior of the command depends on the [arg option] argument that follows the [cmd element] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {element cget}] [arg element] [arg option]] This command returns the current value of the option named [arg option] associated with the element given by [arg element]. [arg Option] may have any of the values accepted by the [cmd {element configure}] widget command. [para] This command also accepts the [option -statedomain] option. [call [arg pathName] [cmd {element configure}] [arg element] \ [opt [arg option]] [opt [arg value]] [opt [arg {option value ...}]]] This command is similar to the [cmd configure] widget command except that it modifies options associated with the element given by [arg element] instead of modifying options for the overall treectrl widget. If no [arg option] is specified, the command returns a list describing all of the available options for [arg element] (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no [arg value], 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 [arg option] is specified). If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given option(s) to have the given value(s) in [arg element]; in this case the command returns an empty string. See [sectref {ELEMENTS AND STYLES}] below for details on the options available for elements. [call [arg pathName] [cmd {element create}] [arg name] [arg type] \ [opt [arg {option value ...}]]] Creates a new master element of type [arg type] with the unique user-defined name [arg name] and configures it with zero or more option/value pairs. See the subsections on individual element types in [sectref {ELEMENTS AND STYLES}] for the options that are valid for each type of element. This command returns the name of the new element (the same as the [arg name] argument). [para] This command also accepts the [option -statedomain] option with a value of either [const header] or [const item] to specify where this element will be displayed. [call [arg pathName] [cmd {element delete}] [opt [arg {element ...}]]] Deletes each of the named elements and returns an empty string. If an element is deleted while it is still configured as an element of one or more styles by means of the [cmd {style elements}] widget command, it is also removed from the element lists of these styles. [call [arg pathName] [cmd {element names}]] Returns a list containing the names of all existing elements. [call [arg pathName] [cmd {element perstate}] [arg element] [arg option] [arg stateList]] This command returns the value of the [sectref {PER-STATE OPTIONS} per-state] option named [arg option] for [arg element] for a certain state. [arg StateList] is a list of state names (static and dynamic, see [sectref STATES]) which specifies the state to use. [call [arg pathName] [cmd {element type}] [arg element]] Returns the type of the element given by [arg element], such as [const rect] or [const text]. [list_end] [call [arg pathName] [cmd expand] [opt [option -recurse]] \ [opt [arg {itemDesc ...}]]] Deprecated. Use [cmd {item expand}] instead. [call [arg pathName] [cmd gradient] [arg option] [opt [arg {arg ...}]]] This command is used to manipulate color gradients. See [sectref {GRADIENTS}] for more information about using gradients. The exact behavior of the command depends on the [arg option] argument that follows the [cmd gradient] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {gradient cget}] [arg gradient] [arg option]] Returns the current value of the configuration option for the gradient specified by [arg gradient] whose name is [arg option]. [arg Option] may have any of the values accepted by the [cmd "gradient configure"] command. [call [arg pathName] [cmd {gradient configure}] [arg gradient] [opt [arg {option value ...}]]] If no [arg option] is specified, the command returns a list describing all of the available gradient options (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no [arg value], then the command returns a list describing the one named gradient option (this list will be identical to the corresponding sublist of the value returned if no [arg option] is specified). If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given gradient option(s) to have the given value(s); in this case the command returns an empty string. [para] The following options are supported (see [cmd "gradient create"] for the meaning of each option): [list_begin options] [opt_def [option -bottom] [arg coordSpec]] [opt_def [option -left] [arg coordSpec]] [opt_def [option -orient] [arg direction]] [opt_def [option -right] [arg coordSpec]] [opt_def [option -steps] [arg stepCount]] [opt_def [option -stops] [arg stopsList]] [opt_def [option -top] [arg coordSpec]] [list_end] [call [arg pathName] [cmd {gradient create}] [arg name] [opt [arg {option value ...}]]] Creates a new gradient with the name [arg name], which must be a unique name not used by another gradient created by this treectrl widget. [para] The following options are supported: [list_begin options] [opt_def [option -bottom] [arg coordSpec]] [opt_def [option -left] [arg coordSpec]] [opt_def [option -right] [arg coordSpec]] [opt_def [option -top] [arg coordSpec]] Each of these options specifies one edge of the gradient brush. If the option is specified as an empty string (the default), the gradient brush's edge is the same as that of whatever rectangle is being painted using the gradient. See [sectref {GRADIENT COORDINATES}] for details on gradient brush coordinates. [para] The format of each of these options is a list of 2 or more values {value coordType ?arg ...?}, where [arg value] is a floating point number (usually from 0.0 to 1.0) and [arg coordType] is one of [const area], [const canvas], [const column] or [const item]. The [const area] keyword must be followed by one of the same area names that the [cmd bbox] command accepts. The [const column] keyword may be followed by a column description specifying exactly one column. The [const item] keyword may be followed by an item description specifying exactly one item. [opt_def [option -orient] [arg direction]] This option specifies the direction a linear gradient changes color in. Must be either [const horizontal] (the default) or [const vertical] or an abbreviation of one of these. [opt_def [option -steps] [arg stepCount]] Specifies the number of bands of color drawn for each color stop described by the [option -stops] option. The default value is 1, the maximum is 25. This option has no effect if gradients are drawn using something better than Tk API calls. See [sectref {GRADIENTS}] for more on this. [opt_def [option -stops] [arg stopsList]] Specifies the color stops along this gradient. The argument [arg stopsList] has the following form: [example_begin] {{offset color ?opacity?} {offset color ?opacity?} ...} [example_end] Each [arg offset] is a floating point number from 0.0 to 1.0 specifying the distance from the start of the gradient where the [arg color] begins. Each [arg color] is a Tk color name or description. Each optional [arg opacity] is a floating point number from 0.0 to 1.0 specifying how transparent the gradient is. [para] If [arg stopsList] is non-empty there must be at least two stops specified, and the first offset must be 0.0 and the last offset must be 1.0. Any other stop offsets must be listed in increasing order. Specifying opacity has no effect if gradients are drawn using Tk API calls. See [sectref {GRADIENTS}] for more on this. [list_end] [call [arg pathName] [cmd {gradient delete}] [opt [arg {name ...}]]] Deletes each gradient specified by [arg name]. If the gradient is still being used then it is not actually deleted until all elements etc using the gradient have stopped using it. A deleted-but-in-use gradient is not recognized by the various gradient commands. Creating a new gradient with the same name as a deleted-but-in-use gradient resurrects the deleted gradient. [call [arg pathName] [cmd {gradient names}]] Returns a list of names of all the gradients that have been created by this treectrl widget. [call [arg pathName] [cmd {gradient native}] [opt [arg preference]]] Without any arguments, this command returns a boolean indicating whether or not the platform supports native transparent gradients. The [arg preference] argument is a boolean that indicates whether native gradients should be used; this can be used to test the appearance of the application. [list_end] [call [arg pathName] [cmd header] [arg option] [opt [arg {arg ...}]]] This command is used to manipulate column headers. The exact behavior of the command depends on the [arg option] argument that follows the [cmd header] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {header bbox}] [arg headerDesc] [opt [arg column]] \ [opt [arg element]]] See the [cmd {item bbox}] command. [call [arg pathName] [cmd {header compare}] [arg headerDesc1] [arg op] [arg headerDesc2]] See the [cmd {item compare}] command. [call [arg pathName] [cmd {header configure}] [arg headerDesc] [opt [arg {arg ...}]]] There are two forms of this command distinguished by whether or not a [sectref {COLUMN DESCRIPTION} {column description}] appears after the [arg headerDesc] argument. If the first argument after [arg headerDesc] begins with a '-' character it is assumed to be an option name, not a column description, in which case the command applies to the header-row. If the first argument after [arg headerDesc] does not being with a '-' it is assumed to be a column description, in which case the command applies to a header-column. [list_begin definitions] [def "[arg pathName] [cmd {header configure}] [arg headerDesc] [opt [arg option]] [opt [arg value]] [opt [arg {option value ...}]]"] If no [arg option] is specified, returns a list describing all of the available options for the header given by [arg headerDesc] (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no value, 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 [arg option] is specified). [para] If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given option(s) to have the given value(s); in this case the command returns an empty string. This is the only case where [arg headerDesc] may refer to multiple header-rows. [para] The following options are supported by this command (see [cmd {header create}] for the meaning of each option): [list_begin options] [opt_def [option -height] [arg height]] [opt_def [option -tags] [arg tagList]] [opt_def [option -visible] [arg boolean]] [list_end] [def "[arg pathName] [cmd {header configure}] [arg headerDesc] [arg column] [opt [arg option]] [opt [arg value]] [opt [arg {option value ...}]]"] If no [arg option] is specified, returns a list describing all of the available options for the single column [arg column] of the header-row given by [arg headerDesc] (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no value, 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 [arg option] is specified). [para] If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given option(s) to have the given value(s); in this case the command returns an empty string. This is the only case where both [arg headerDesc] may refer to multiple header-rows and [arg column] may refer to multiple header-columns. [para] The following options are supported by this command (see [sectref HEADERS]) for the meaning of each option): [list_begin options] [opt_def [option -arrow] [arg direction]] [opt_def [option -arrowbitmap] [arg bitmap]] [opt_def [option -arrowgravity] [arg direction]] [opt_def [option -arrowimage] [arg image]] [opt_def [option -arrowpadx] [arg amount]] [opt_def [option -arrowpady] [arg amount]] [opt_def [option -arrowside] [arg side]] [opt_def [option -background] [arg color]] [opt_def [option -bitmap] [arg bitmap]] [opt_def [option -borderwidth] [arg size]] [opt_def [option -button] [arg boolean]] [opt_def [option -font] [arg fontName]] [opt_def [option -image] [arg image]] [opt_def [option -imagepadx] [arg amount]] [opt_def [option -imagepady] [arg amount]] [opt_def [option -justify] [arg justification]] [opt_def [option -state] [arg state]] [opt_def [option -text] [arg text]] [opt_def [option -textcolor] [arg color]] [opt_def [option -textlines] [arg count]] [opt_def [option -textpadx] [arg amount]] [opt_def [option -textpady] [arg amount]] [list_end] [list_end] [call [arg pathName] [cmd {header count}] [opt [arg headerDesc]]] If no additional arguments are given, the result is a decimal string giving the number of header-rows created by the [cmd {header create}] widget command which haven't been deleted by the [cmd {header delete}] widget command, plus 1 for the ever-present top header-row created along with the widget. If the optional argument [arg headerDesc] is given, then the result is the number of header-rows that match that [sectref {HEADER DESCRIPTION} {header description}]. [call [arg pathName] [cmd {header create}] [opt [arg {option value}]]] Creates a new header-row and returns its unique identifier. The following configuration options are supported: [list_begin options] [opt_def [option -height] [arg height]] Specifies a fixed height for the header-row in any of the forms acceptable to [fun Tk_GetPixels]. Must be >= 0. If [arg height] is zero then the header-row's height is the maximum height of all of its column headers. Defaults to 0. [opt_def [option -tags] [arg tagList]] [arg TagList] is a list of tag names to be added to the new header-row. The [cmd {header tag}] command can also be used to manipulate this list of tags. [opt_def [option -visible] [arg boolean]] [arg Boolean] must have one of the forms accepted by [fun Tcl_GetBoolean]. It indicates whether or not the header-row should be displayed. If the widget option [option -showheader] is false then the header-row will not be displayed regardless of the value of this option. [list_end] [call [arg pathName] [cmd {header delete}] [arg headerDesc]] Deletes the header-rows given by the [sectref {HEADER DESCRIPTION} {header description}] [arg headerDesc]. Attempts to delete the ever-present top header-row are ignored without raising an error. [call [arg pathName] [cmd {header dragcget}] [opt [arg {arg ...}]]] There are two forms of this command distinguished by whether or not a [sectref {HEADER DESCRIPTION} {header description}] appears as the first argument. If the first argument begins with a '-' character it is assumed to be an option name, not a header description, in which case the command applies to the header-drag-and-drop options for the widget. If the first argument does not being with a '-' it is assumed to be a header description, in which case the command applies to a header-row. [list_begin definitions] [def "[arg pathName] [cmd {header dragcget}] [arg option]"] This command returns the current value of the header-drag-and-drop option named [arg option] for the widget. The following configuration options are supported (see [cmd {header dragconfigure}] for the meaning of each option): [list_begin options] [opt_def [option -enable] [arg boolean]] [opt_def [option -imagealpha] [arg alpha]] [opt_def [option -imagecolor] [arg background]] [opt_def [option -imagecolumn] [arg column]] [opt_def [option -imageoffset] [arg offset]] [opt_def [option -imagespan] [arg count]] [opt_def [option -indicatorcolor] [arg color]] [opt_def [option -indicatorcolumn] [arg column]] [opt_def [option -indicatorside] [arg side]] [opt_def [option -indicatorspan] [arg count]] [list_end] [def "[arg pathName] [cmd {header dragcget}] [arg headerDesc] [arg option]"] This command returns the current value of the header-drag-and-drop option named [arg option] for a header-row. The following configuration options are supported (see [cmd {header dragconfigure}] for the meaning of each option): [list_begin options] [opt_def [option -draw] [arg boolean]] [opt_def [option -enable] [arg boolean]] [list_end] [list_end] [call [arg pathName] [cmd {header dragconfigure}] [opt [arg {arg ...}]]] There are two forms of this command distinguished by whether or not a [sectref {HEADER DESCRIPTION} {header description}] appears as the first argument. If the first argument begins with a '-' character it is assumed to be an option name, not a header description, in which case the command applies to the header-drag-and-drop options for the widget. If the first argument does not being with a '-' it is assumed to be a header description, in which case the command applies to a header-row. [list_begin definitions] [def "[arg pathName] [cmd {header dragconfigure}] \ [opt [arg option]] [opt [arg value]] [opt [arg {option value ...}]]"] This command queries and sets header-drag-and-drop options for the widget, not for individual header-rows. The following configuration options are supported: [list_begin options] [opt_def [option -enable] [arg boolean]] Controls whether the user is allowed to rearrange columns by drag-and-drop. The default is false. Each header-row also has an [option -enable] dragconfigure option. [opt_def [option -imagealpha] [arg alpha]] [arg Alpha] is an integer from 0 (invisible) to 255 (opaque) controlling the transparency of the drag image. Any value outside this range is clipped. The default is 200. [opt_def [option -imagecolor] [arg background]] Unused. [opt_def [option -imagecolumn] [arg column]] [arg Column] specifies the column to create the drag image from. [opt_def [option -imageoffset] [arg offset]] [arg Offset] is the horizontal screen distance the drag image is offset from its starting position. [opt_def [option -imagespan] [arg count]] [arg Count] is the number of columns, starting with -imagecolumn, that will be dragged as a group. [opt_def [option -indicatorcolor] [arg color]] Unused. [opt_def [option -indicatorcolumn] [arg column]] The 2-pixel-thick line will be drawn over the left or right edge of [arg column]. [opt_def [option -indicatorside] [arg side]] Unused. [opt_def [option -indicatorspan] [arg count]] [arg Count] is the number of columns, starting with -indicatorcolumn, that will be displaced as a group by the dragged column(s) [list_end] [def "[arg pathName] [cmd {header dragconfigure}] [arg header] \ [opt [arg option]] [opt [arg value]] [opt [arg {option value ...}]]"] This command queries and sets header-drag-and-drop options for header-rows, not for the widget as a whole. The following configuration options are supported: [list_begin options] [opt_def [option -draw] [arg boolean]] Controls whether a header-row displays any feedback during header drag-and-drop. The default is true. [opt_def [option -enable] [arg boolean]] Controls whether clicking and dragging in this header-row initiates drag-and-drop. The default is true. If the [option -enable] option for the [emph widget] is false (see above) then this option has no effect. [list_end] [list_end] [call [arg pathName] [cmd {header element}] [opt [arg {arg ...}]]] See the [cmd {item element}] command. [call [arg pathName] [cmd {header id}] [arg headerDesc]] This command resolves the [sectref {HEADER DESCRIPTION} {header description}] [arg headerDesc] into a list of unique header-row identifiers. If [arg headerDesc] doesn't refer to any existing header-rows, then this command returns an empty list. [call [arg pathName] [cmd {header image}] [arg headerDesc] [opt [arg column]] \ [opt [arg image]] [opt [arg {column image ...}]]] The behavior of this command depends on whether or not a column header was assigned a style containing an image element. If a column header has no style or no style with an image element then this command operates on the same -image option as [cmd {header configure}]. Otherwise this command operates on the -image option of the first image element in a column header's style. See the [cmd {item image}] command. [call [arg pathName] [cmd {header span}] [arg headerDesc] [opt [arg column]] \ [opt [arg numColumns]] [opt [arg {column numColumns ...}]]] See the [cmd {item span}] command. [call [arg pathName] [cmd {header state}] [arg command] [arg headerDesc] \ [opt [arg {arg ...}]]] See the [cmd {item state}] command. [call [arg pathName] [cmd {header style}] [arg command] [arg headerDesc] \ [opt [arg {arg ...}]]] See the [cmd {item style}] command. [call [arg pathName] [cmd {header text}] [arg headerDesc] [opt [arg column]] \ [opt [arg text]] [opt [arg {column text ...}]]] The behavior of this command depends on whether or not a column header was assigned a style containing a text element. If a column header has no style or no style with a text element then this command operates on the same -text option as [cmd {header configure}]. Otherwise this command operates on the -text option of the first text element in a column header's style. See [cmd {item text}]. [call [arg pathName] [cmd {header tag}] [arg command] [arg headerDesc] \ [opt [arg {arg ...}]]] See the [cmd {item tag}] command. [list_end] [call [arg pathName] [cmd identify] [opt [arg {-array varName}]] [arg x] [arg y]] This command returns information about the what is displayed at the given window coordinates [arg x] and [arg y]. When the [arg -array] option is used to specify the name of an array variable, elements of the array variable are set as follows: [list_begin enum] [enum] If the coordinates are outside the window, over the borders, or over any whitespace in the window, then: [para] $varName(where) is "" [enum] If the coordinates are over a column header, then: [para] $varName(where) is [const header] [para] $varName(header) is the unique id of the [sectref HEADERS header-row] [para] $varName(column) is the unique id of the column [para] $varName(element) is the name of an [sectref {ELEMENTS AND STYLES} element], or "" [para] $varName(side) is [const left] or [const right] if the coordinates are close to the edge of the column header, otherwise "" [enum] If the coordinates are over an item, then: [para] $varName(where) is [const item] [para] $varName(item) is the unique id of the item [para] $varName(column) is the unique id of the column [para] $varName(element) is the name of an [sectref {ELEMENTS AND STYLES} element], or "" [para] $varName(button) is a boolean indicating whether or not the coordinates are over the item's expand/collapse button [para] $varName(line) is the unique id of an ancestor of the item (but not the parent of the item) if the coordinates are over a line descending from that ancestor. If the coordinates are not over such a line then $varName(line) is "". This is used to collapse the ancestor when the line is clicked on. [list_end] When the [arg -array] option is not used, this command returns a list describing what is displayed at the given window coordinates. The format of this list can be like one of the following: [list_begin enum] [enum] {} [para] An empty list is returned if the coordinates are outside the window, over the borders, or over any whitespace in the window. [enum] [const header] C [opt [const left]|[const right]] [para] [const header] C [const elem] E [opt [const left]|[const right]] [para] [const header] H [const column] C [opt [const left]|[const right]] [para] [const header] H [const column] C [const elem] E [opt [const left]|[const right]] [para] Only when there is more than one [sectref HEADERS header-row] is there a unique id of a header-row [arg H] followed by the keyword [const column]. This is for compatibility with older versions when there was only one row of column headers allowed. [enum] [const item] I [const column] C [enum] [const item] I [const column] C [const elem] E [enum] [const item] I [const button] [para] This is the result when the coordinates are over the expand/collapse button next to an item. [enum] [const item] I [const line] I2 [para] This is the result when the coordinates are over a line descending from an ancestor [arg I2] of the item [arg I] (but not the parent of that item). This is used to collapse the ancestor when the line is clicked on. [list_end] [call [arg pathName] [cmd index] [arg itemDesc]] Deprecated. Use [cmd {item id}] instead. [call [arg pathName] [cmd item] [arg option] [opt [arg {arg ...}]]] This command is used to manipulate items. The exact behavior of the command depends on the [arg option] argument that follows the [cmd item] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {item ancestors}] [arg itemDesc]] Returns a list containing the item ids of the ancestors of the item specified by [arg itemDesc]. The first list value is the parent, the second is the parent's parent, an so on. The last list value will be the root item if [arg itemDesc] is a descendant of the root item. [call [arg pathName] [cmd {item bbox}] [arg itemDesc] [opt [arg column]] \ [opt [arg element]]] Returns a list with four elements giving the bounding box of the item described by [arg itemDesc]. If no further argument is specified, the bbox spans the area of the item over all non-locked columns. If a [arg column] is specified, only the area of the item in this column is considered. If an additional [arg element] is specified, the area of this [arg element] in [arg column] of the specified item is returned. The returned coordinates are relative to the top-left corner of the widget. If the item is not visible for any reason, the result in an empty string. [call [arg pathName] [cmd {item buttonstate}] [arg itemDesc] [opt [arg state]]] If [arg state] is specified, this command sets the state of the expand/collapse button for the single item specified by [arg itemDesc]. The [arg state] argument may be one of [const active], [const normal] or [const pressed]. The current (or newly-set) state of the button is returned. The button state is used by the system theme, if any, to change the appearance of the button. [call [arg pathName] [cmd {item cget}] [arg itemDesc] [arg option]] Returns the current value of the configuration option for the item specified by [arg itemDesc] whose name is [arg option]. [arg Option] may have any of the values accepted by the [cmd "item configure"] command. [call [arg pathName] [cmd {item children}] [arg itemDesc]] Returns a list containing the item ids of all children of the item specified by [arg itemDesc] in the correct order from the first child to the last child. [call [arg pathName] [cmd {item collapse}] [arg itemDesc] [opt [option -animate]] [opt [option -recurse]]] Switches off the [const open] state of the item(s) described by [arg itemDesc]. If an item has descendants, then they are no longer displayed. If an item is already closed, then this command has no effect on that item. If [option -animate] is specified, then the item's button will animate as it transitions between states if the theme supports it; in this case only one item may be specified. If [option -recurse] is specified, then all descendants of the items described by [arg itemDesc] will also be collapsed. For every item that actually will be collapsed, two events are generated: a [const ] event before the item state is changed, and a [const ] event after the item state was changed. [call [arg pathName] [cmd {item compare}] [arg itemDesc1] [arg op] [arg itemDesc2]] From both items described by the [arg itemDesc]s the index is retrieved (as returned from the [cmd {item order}] widget command). Then these indexes are compared using the operator [arg op], which must be either [const <], [const <=], [const ==], [const >=], [const >], or [const !=]. The return value of this command is 1 if the comparison evaluated to true, 0 otherwise. [call [arg pathName] [cmd {item complex}] [arg itemDesc] [opt [arg list...]]] This horrible command is now deprecated. Use [cmd {item element configure}] instead. For every column of the treectrl there may be specified one [arg list]. Each [arg list] should look like this: [example_begin] { {element option value ...} {element option value ...} ...} [example_end] Every [arg option] must be known by the element's type (see [sectref {ELEMENTS AND STYLES}] below). Each [arg option] will be set to [arg value] for the element in this one column in this item. [call [arg pathName] [cmd {item configure}] [arg itemDesc] [opt [arg option]] [opt [arg value]] [opt [arg {option value ...}]]] If no [arg option] is specified, returns a list describing all of the available options for the item given by [arg itemDesc] (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no value, 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 [arg option] is specified). [para] If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given item option(s) to have the given value(s); in this case the command returns an empty string. This is the only case where [arg itemDesc] may refer to multiple items. [para] The following options are supported by this command (see [cmd {item create}] for the meaning of each option): [list_begin options] [opt_def [option -button] [arg boolean|auto]] [opt_def [option -height] [arg height]] [opt_def [option -tags] [arg tagList]] [opt_def [option -visible] [arg boolean]] [opt_def [option -wrap] [arg boolean]] [list_end] [call [arg pathName] [cmd {item count}] [opt [arg itemDesc]]] If no additional arguments are given, the result is a decimal string giving the number of items created by the [cmd "item create"] widget command which haven't been deleted by the [cmd "item delete"] widget command, plus 1 for the ever-present root item. If the optional argument [arg itemDesc] is given, then the result is the number of items that match that [sectref {ITEM DESCRIPTION} {item description}]. [call [arg pathName] [cmd {item create}] [opt [arg {option value ...}]]] Creates some new items and optionally returns a list of unique identifiers for those items. The new items have the states [const open] and [const enabled] set by default. If the treectrl widget currently has the focus, the state [const focus] is also set. [para] The following options are supported by this command: [list_begin options] [opt_def [option -button] [arg boolean|auto]] The value of this option must have one of the forms accepted by [fun Tcl_GetBoolean] or be the word [const auto] (or any abbreviation of it). It indicates whether or not an expand/collapse button should be drawn next to the item, typically to indicate that the item has children. If the value of this option is [const auto], then a button is displayed next to the item whenever the item has any children whose item option [option -visible] is true. The button will only be displayed if: [list_begin enum] [enum] the column specified by the treectrl option [option -treecolumn] is visible, and [enum] the treectrl option [option -showbuttons] is true, and [enum] for the root item, the treectrl option [option -showrootbutton] is true, and [enum] for immediate children of the root item, the treectrl option [option -showrootchildbuttons] is true. [list_end] [opt_def [option -count] [arg numItems]] Specifies the number of items to create. Must be >= 0. Defaults to 1. [opt_def [option -enabled] [arg boolean]] Specifies whether the items should be enabled. Default is true. [opt_def [option -height] [arg height]] Specifies a fixed height in any of the forms acceptable to [fun Tk_GetPixels]. Must be >= 0. If [arg height] is zero then the item's height is unspecified. Defaults to 0. See also the widget options [option -itemheight] and [option -minitemheight]. [opt_def [option -nextsibling] [arg itemDesc]] Specifies the item before which the new items will be inserted. The new items will have the same parent as [arg itemDesc]. [opt_def [option -open] [arg boolean]] Specifies whether the items should be open or closed. Default is true. [opt_def [option -parent] [arg itemDesc]] Specifies the item which the new items will be the children of. The new items will be appended to the list of children of [arg itemDesc]. When no parent is specified, the new items are [emph orphan] items (see the widget command [cmd {orphans}]) and will not be displayed in the list. [opt_def [option -prevsibling] [arg itemDesc]] Specifies the item after which the new items will be inserted. The new items will have the same parent as [arg itemDesc]. [opt_def [option -returnid] [arg boolean]] Specifies whether or not to return a list of item identifiers for the newly created items. Specifying false is useful when creating a large number of items in the console or to improve performance. Default is true. [opt_def [option -tags] [arg tagList]] [arg TagList] is a list of tag names to be added to the new items. The [cmd {item tag}] command can also be used to manipulate this list of tags. [opt_def [option -visible] [arg boolean]] [arg Boolean] must have one of the forms accepted by [fun Tcl_GetBoolean]. It indicates that the item should be displayed in the list. The item will only be displayed if: [list_begin enum] [enum] each ancestor is a descendant of the root item (not an orphan), and [enum] each ancestor's [option -visible] option is true [list_end] [opt_def [option -wrap] [arg boolean]] [arg Boolean] must have one of the forms accepted by [fun Tcl_GetBoolean]. It indicates that this item should be the first one in a horizontal range or vertical range of items. See also the widget option [option -wrap]. [list_end] [call [arg pathName] [cmd {item delete}] [arg first] [opt [arg last]]] Deletes the specified item(s). [arg First] and [arg last] must be valid [sectref {ITEM DESCRIPTION} {item descriptions}]. If [arg last] isn't specified, then [arg first] may specify multiple items. If both [arg first] and [arg last] are specified, they must each decribe a single item with a common ancestor; then the range of items between [arg first] and [arg last] is deleted. The order of [arg first] and [arg last] doesn't matter. [para] Deleting an item deletes any child items of the deleted item recursively. If the current [const active] item is deleted, the root item becomes the new active item. If the current selection [const anchor] item is deleted, the root item becomes the new anchor item. There is no way to delete the root item of the treectrl widget; in all cases the specification of the root item is ignored. [para] For each call to this command, two events may be generated. If any of the deleted items are selected, then they are removed from the selection and a [const ] event is generated just before the items are deleted. If any items are going to be deleted, then an [const ] event is generated just before the items are deleted. [call [arg pathName] [cmd {item descendants}] [arg itemDesc]] Returns a list containing the item ids of the descendants of the item specified by [arg itemDesc], i.e. the children, grandchildren, great-grandchildren etc, of the item. [call [arg pathName] [cmd {item dump}] [arg itemDesc]] Debug command. Returns a list with 4 words in the form [const index] [emph index] [const indexVis] [emph indexVis]. [call [arg pathName] [cmd {item element}] [arg command] [arg itemDesc] \ [arg column] [arg element] [opt [arg {arg ...}]]] This command is used to manipulate elements of the item. The exact behavior of the command depends on the [arg command] argument that follows the [cmd element] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {item element actual}] [arg itemDesc] [arg column] \ [arg element] [arg option]] Deprecated. Use [cmd {item element perstate}] instead. [call [arg pathName] [cmd {item element cget}] [arg itemDesc] [arg column] \ [arg element] [arg option]] This command returns the value of the option named [arg option] associated with [arg element] inside [arg column] of the item described by [arg itemDesc], if it was already configured for the actual item. [arg Option] may have any of the values accepted by the type of the specified element (see [sectref {ELEMENTS AND STYLES}] below) [call [arg pathName] [cmd {item element configure}] [arg itemDesc] \ [arg column] [arg element] [opt [arg option]] [opt [arg value]] \ [opt [arg {option value ...}]]] This command modifies configuration options for an element in a column of an item. If no [arg option] is specified, the command returns a list describing all of the available options for the element (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no [arg value], 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 [arg option] is specified). [para] If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given option(s) to have the given value(s) in the [arg element] inside [arg column] of the item(s) described by [arg itemDesc]; in this case the command returns an empty string. This is the only case where [arg itemDesc] may refer to multiple items. [para] It is possible to configure multiple elements in multiple columns with a single call. To configure another element in the same column, append a '[const +]' argument followed by the element name. To configure elements in another column, append a '[const ,]' argument followed by the column. For example: [example_begin] .t item element configure $I \ $C1 $E1 -text "hello" + $E2 -text "world" , \ $C2 $E3 -fill Blue , \ $C3 $E1 -text "apples and oranges" [example_end] Each of the [sectref {COLUMN DESCRIPTION} {column description}] arguments to this command may refer to multiple columns if at least one [arg option]-[arg value] pair is given. [call [arg pathName] [cmd {item element perstate}] [arg itemDesc] [arg column] \ [arg element] [arg option] [opt [arg stateList]]] This command returns the current value of the [sectref {PER-STATE OPTIONS} per-state] option named [arg option] for [arg element] inside [arg column] of the item described by [arg itemDesc]. If [arg stateList] is specified, the list of state names (static and dynamic, see [sectref STATES]) is used in place of the current state for [arg item] and [arg column.] [list_end] [call [arg pathName] [cmd {item enabled}] [arg itemDesc] [opt [arg boolean]]] Returns 1 if the item described by [arg itemDesc] has the state [const enabled] switched on, 0 otherwise. If [arg boolean] is specified, then the [const enabled] state of every item described by the [sectref {ITEM DESCRIPTION} {item description}] [arg itemDesc] is set accordingly. New items are enabled by default when created. Disabled items cannot be selected, and are ignored by the default key-navigation and mouse bindings. [call [arg pathName] [cmd {item expand}] [arg itemDesc] [opt [option -animate]] [opt [option -recurse]]] Switches on the [const open] state of the item(s) described by [arg itemDesc]. If an item has descendants, then they are now displayed. If an item is already open, then this command has no effect on that item. If [option -animate] is specified, then the item's button will animate as it transitions between states if the theme supports it; in this case only one item may be specified. If [option -recurse] is specified, then all descendants of the items described by [arg itemDesc] will also be expanded. For every item that actually will be expanded, two events are generated: an [const ] event before the item state is changed, and an [const ] event after the item state was changed. [call [arg pathName] [cmd {item firstchild}] [arg parent] [opt [arg child]]] If [arg child] is not specified, returns the item id of the first child of the item described by [arg parent]. If [arg child] is specified, it must describe an item that is neither the root item nor an ancestor of [arg parent]. Then it will become the new first child of [arg parent]. [call [arg pathName] [cmd {item id}] [arg itemDesc]] This command resolves the [sectref {ITEM DESCRIPTION} {item description}] [arg itemDesc] into a list of unique item identifiers. If [arg itemDesc] doesn't refer to any existing items, then this command returns an empty list. [call [arg pathName] [cmd {item image}] [arg itemDesc] [opt [arg column]] \ [opt [arg image]] [opt [arg {column image ...}]]] This command sets or retrieves the value of the [sectref {PER-STATE OPTIONS} per-state] -image option for the first image element in one or more columns. If no [arg column] is specified, this command returns a list of values, one per column. If no [arg image] is specified, this command returns the value for [arg column]. [para] If one or more [arg column]-[arg image] pairs is specified, then the value of the -image option in each [arg column] is set to [arg image]. In this case [arg itemDesc] may refer to multiple items and each [arg column] may refer to multiple columns. [para] Note that this command is provided as a convenience. Use the [cmd "item element configure"] or [cmd "item element cget"] commands if you want to set or retrieve the value of the -image option for a specific image element. [call [arg pathName] [cmd {item isancestor}] [arg itemDesc] [arg descendant]] Returns 1 if the item described by [arg itemDesc] is a direct or indirect parent of the item decribed by [arg descendant], 0 otherwise. [call [arg pathName] [cmd {item isopen}] [arg itemDesc]] Returns 1 if the item described by [arg itemDesc] has the state [const open] switched on, 0 otherwise. [call [arg pathName] [cmd {item lastchild}] [arg parent] [opt [arg child]]] If [arg child] is not specified, returns the item id of the last child of the item described by [arg parent]. If [arg child] is specified, it must describe an item that is not an ancestor of [arg parent]. Then it will become the new last child of [arg parent]. [call [arg pathName] [cmd {item nextsibling}] [arg sibling] [opt [arg next]]] If [arg next] is not specified, returns the item id of the next sibling of the item described by [arg sibling]. If [arg next] is specified, it must describe an item that is not an ancestor of [arg sibling]. Then it will become the new next sibling of [arg sibling]. [call [arg pathName] [cmd {item numchildren}] [arg itemDesc]] Returns the number of children of the item described by [arg itemDesc]. [call [arg pathName] [cmd {item order}] [arg itemDesc] [opt [arg -visible]]] This command returns the position of the item [arg itemDesc] relative to its toplevel ancestor (usually the root item, unless the ancestor is an orphan). If you imagine all the items flattened into a vertical list, the result of this command is the row the item falls in. If the optional argument [arg -visible] is given, only the items whose ancestors are expanded, and whose -visible option is true, get counted; in this case -1 is returned if the item is not visible. [call [arg pathName] [cmd {item parent}] [arg itemDesc]] Returns the item id of the parent of the item described by [arg itemDesc]. [call [arg pathName] [cmd {item prevsibling}] [arg sibling] [opt [arg prev]]] If [arg prev] is not specified, returns the item id of the previous sibling of the item described by [arg sibling]. If [arg prev] is specified, it must describe an item that is not an ancestor of [arg sibling]. Then it will become the new previous sibling of [arg sibling]. [call [arg pathName] [cmd {item range}] [arg first] [arg last]] Returns a list containing the item ids of all items in the range between [arg first] and [arg last], inclusive. The order between [arg first] and [arg last] doesn't matter, and the result is always sorted by the increasing order of the items (as returned by the [cmd {item order}] command). The items specified by [arg first] and [arg last] must share a common ancestor. [call [arg pathName] [cmd {item remove}] [arg itemDesc]] Removes the item described by [arg itemDesc] from the list of children of its parent, so that it will become an orphan. [call [arg pathName] [cmd {item rnc}] [arg itemDesc]] Returns a list of two integers, which corresponds to the row and column of the item described by [arg itemDesc]. The row and column corresponds to the on-screen arrangement of items as determined by the -orient and -wrap options. If the item is not displayed, this command returns an empty string. [call [arg pathName] [cmd {item sort}] [arg itemDesc] [opt [arg {option ...}]]] Sorts the children of the item described by [arg itemDesc], and redisplays the tree with the items in the new order. [para] The range of items which should be sorted can be restricted by means of the [option -first] and/or [option -last] options, which should be children of the item described by [arg itemDesc]; the order between these two limiting items doesn't matter. [para] The sort column can be specified by means of the [option -column] option; this option can be used repeatedly to define a multicolumn sort. The sorting is done by looking at the [arg text] of the element specified by the [option -element] option, which must be a text element defined in the style of the sorting column, by default the first text element is used. [para] If the [option -notreally] option is specified, no rearranging of the items is done; instead the sorted items are returned as result of the command. [para] By default ASCII sorting is used with the result returned in increasing order. Any of the following options may be specified to control the sorting process of the previously specified column (unique abbreviations are accepted): [list_begin options] [opt_def [option -ascii]] Use string comparison with ASCII collation order. This is the default. [opt_def [option -command] [arg command]] Use [arg command] as a comparison command. To compare two items, evaluate a Tcl script consisting of [arg command] with the numerical ids of the two items appended as additional arguments. The script should return an integer less than, equal to, or greater than zero if the first item is to be considered less than, equal to, or greater than the second, respectively. [opt_def [option -decreasing]] Sort the items in decreasing order ("largest" items first). [opt_def [option -dictionary]] Use dictionary-style comparison. This is the same as [option -ascii] except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, in [option -dictionary] mode, [term bigBoy] sorts between [term bigbang] and [term bigboy], and [term x10y] sorts between [term x9y] and [term x11y]. [opt_def [option -increasing]] Sort the items in increasing order ("smallest" items first). This is the default. [opt_def [option -integer]] Convert to integers and use integer comparison. [opt_def [option -real]] Convert to floating-point values and use floating comparison. [list_end] [call [arg pathName] [cmd {item span}] [arg itemDesc] [opt [arg column]] \ [opt [arg numColumns]] [opt [arg {column numColumns ...}]]] This command sets or retrieves the number of columns that a style covers. If no [arg column] is specified, the return value is a list of spans, one per column. If no [arg numColumns] is specified, the return value is the span for [arg column]. [para] If one or more [arg column]-[arg numColumns] pairs is specified, the span for each [arg column] is set to [arg numColumns]. In this case [arg itemDesc] may refer to multiple items and each [arg column] may refer to multiple columns. [call [arg pathName] [cmd {item state}] [arg command] [arg itemDesc] \ [opt [arg {arg ...}]]] This command is used to manipulate the states of an item. The exact behavior of the command depends on the [arg command] argument that follows the [cmd style] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {item state define}] [arg stateName]] Defines a new state with the name [arg stateName], which must not be the name of an existing state. [call [arg pathName] [cmd {item state forcolumn}] [arg itemDesc] [arg column] \ [opt [arg stateDescList]]] Just like [cmd {item state set}] but manipulates dynamic states for a single item column, not the item as a whole. If [arg stateDescList] is unspecified, this command returns a list containing the names of all the dynamic states which are switched on in [arg column]. [para] If [arg stateDescList] is specified, then [arg itemDesc] may refer to multiple items and [arg column] may refer to multiple columns. [call [arg pathName] [cmd {item state get}] [arg itemDesc] \ [opt [arg {stateName}]]] If no [arg stateName] is specified, returns a list containing the names of all (static and dynamic) states which are currently switched on for the item described by [arg itemDesc]. If a [arg stateName] is specified, 1 is returned if the specified state is currently switched on for the item, 0 otherwise. [call [arg pathName] [cmd {item state linkage}] [arg stateName]] Returns a string indicating whether the specified state is user-defined by means of the [cmd {item state define}] widget command ([const dynamic]) or predefined by the treectrl widget itself ([const static]). [call [arg pathName] [cmd {item state names}]] Returns a list containing the names of all user-defined states. [call [arg pathName] [cmd {item state set}] [arg itemDesc] \ [opt [arg lastItem]] [arg stateDescList]] Every element of [arg stateDescList] must be the name of a dynamic state (see [sectref STATES] below), optionally preceded by a [const ~] or [const !] character. Every state with a leading [const !] will be switched off for the item described by [arg itemDesc], every state with a leading [const ~] will be toggled, and every state without leading [const !] or [const ~] will be switched on. If [arg lastItem] is specified, the state changes will be made for all items in the range between [arg itemDesc] and [arg lastItem]. If [arg lastItem] unspecified, then the state changes are made for all items described by [arg itemDesc]. [call [arg pathName] [cmd {item state undefine}] [opt [arg {stateName ...}]]] Every [arg stateName] must be the name of a user-defined state. Removes this state from the list of user-defined states. [list_end] [call [arg pathName] [cmd {item style}] [arg command] [arg itemDesc] \ [opt [arg {arg ...}]]] This command is used to manipulate the styles of an item. The exact behavior of the command depends on the [arg command] argument that follows the [cmd style] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {item style elements}] [arg itemDesc] [arg column]] This command returns a list containing the names of elements which were configured by the [cmd {item element configure}] command for the item described by [arg itemDesc] in [arg column]. If there is no style assigned to [arg column] an error is returned. [call [arg pathName] [cmd {item style map}] [arg itemDesc] [arg column] \ [arg style] [arg map]] Like the [cmd "item style set"] command, this command may be used to assign a style to a specific column of an item. Unlike [cmd "item style set"], this command can transfer configuration values of elements in the current style to elements in the new style specified by [arg style]. [arg Map] must be a list of [arg elementOld]-[arg elementNew] pairs, where [arg elementOld] is an element in the current style, and [arg elementNew] is an element in the style specified by [arg style]. Both [arg elementOld] and [arg elementNew] must be of the same type ([const bitmap], [const text] etc). [arg ItemDesc] may refer to multiple items and [arg column] may refer to multiple columns. [call [arg pathName] [cmd {item style set}] [arg itemDesc] [opt [arg column]] \ [opt [arg style]] [opt [arg {column style ...}]]] This command sets or retrieves the style assigned to one or more columns. If no [arg column] is specified, this command returns a list containing the names of the styles set for all columns of the item described by [arg itemDesc]. If no [arg style] is specified, this command returns the name of the style set for the item described by [arg itemDesc] in [arg column]. [para] If one or more [arg column]-[arg style] pairs is specified, then the style in each [arg column] is set to [arg style]. In this case [arg itemDesc] may refer to multiple items and each [arg column] may refer to multiple columns. [list_end] [call [arg pathName] [cmd {item tag}] [arg option] [opt [arg {arg arg ...}]]] This command is used to manipulate tags on items. The exact behavior of the command depends on the [arg option] argument that follows the [cmd {item tag}] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {item tag add}] [arg itemDesc] [arg tagList]] Adds each tag in [arg tagList] to the items specified by the [sectref {ITEM DESCRIPTION} {item description}] [arg itemDesc]. Duplicate tags are ignored. The list of tags for an item can also be changed via an item's [option -tags] option. [call [arg pathName] [cmd {item tag expr}] [arg itemDesc] [arg tagExpr]] Evaluates the tag expression [arg tagExpr] against every item specified by the [sectref {ITEM DESCRIPTION} {item description}] [arg itemDesc]. The result is 1 if the tag expression evaluates to true for every item, 0 otherwise. [call [arg pathName] [cmd {item tag names}] [arg itemDesc]] Returns a list of tag names assigned to the items specified by the [sectref {ITEM DESCRIPTION} {item description}] [arg itemDesc]. The result is the union of any tags assigned to the items. [call [arg pathName] [cmd {item tag remove}] [arg itemDesc] [arg tagList]] Removes each tag in [arg tagList] from the items specified by the [sectref {ITEM DESCRIPTION} {item description}] [arg itemDesc]. It is not an error if any of the items do not use any of the tags. The list of tags for an item can also be changed via an item's [option -tags] option. [list_end] [call [arg pathName] [cmd {item text}] [arg itemDesc] [opt [arg column]] \ [opt [arg text]] [opt [arg {column text ...}]]] This command sets or retrieves the value of the -text option for the first text element in one or more columns. If no [arg column] is specified, this command returns a list of values, one per column. If no [arg text] is specified, this command returns the value for [arg column]. [para] If one or more [arg column]-[arg text] pairs is specified, then the value of the -text option in each [arg column] is set to [arg text]. In this case [arg itemDesc] may refer to multiple items and each [arg column] may refer to multiple columns. [para] Note that this command is provided as a convenience. Use the [cmd "item element configure"] or [cmd "item element cget"] commands if you want to set or retrieve the value of the -text option for a specific text element. [call [arg pathName] [cmd {item toggle}] [arg itemDesc] [opt [option -animate]] [opt [option -recurse]]] Changes the [const open] state of the item(s) described by [arg itemDesc]. If the [const open] state is currently switched off, then this command does the same as the [cmd {item expand}] widget command; otherwise the same as the [cmd {item collapse}] widget command. If [option -animate] is specified, then the item's button will animate as it transitions between states if the theme supports it; in this case only one item may be specified. If [option -recurse] is specified, then the [const open] state of all descendants of the items described by [arg itemDesc] will also be toggled. [list_end] [call [arg pathName] [cmd marquee] [arg option] [opt [arg {arg ...}]]] This command is used to manipulate the marquee, which can be used to implement a resizable selection rectangle, in a file browser for example. One corner point of the marquee is fixed as long as the marquee is visible and called the anchor; the diagonally opposite corner is dragged with the mouse while resizing the marquee and simply called the corner. [para] All coordinates handled by this widget command are [sectref {THE CANVAS} {canvas}] coordinates, i.e. the [cmd canvasx] or [cmd canvasy] widget command should be used to translate window coordinates to canvas coordinates. [para] By default, the marquee is displayed as a 1-pixel thick dotted rectangle. If either of the [option -fill] or [option -outline] options is specified, then the marquee is drawn as a filled and/or outlined rectangle of the specified color(s). The [option -fill] option should specify a transparent gradient to avoid hiding what is inside the marquee. See [sectref GRADIENTS] for more info. [para] The exact behavior of the command depends on the [arg option] argument that follows the [cmd marquee] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {marquee anchor}] [opt [arg {x y}]]] Returns a list containing the x and y coordinates of the anchor, if no additional arguments are specified. If two coordinates are specified, sets the anchor to the given coordinates [arg x] and [arg y]. [call [arg pathName] [cmd {marquee cget}] [arg option]] This command returns the current value of the marquee option named [arg option]. [arg Option] may have any of the values accepted by the [cmd {marquee configure}] widget command. [call [arg pathName] [cmd {marquee configure}] [opt [arg option]] \ [opt [arg value]] [opt [arg {option value ...}]]] This command is similar to the [cmd configure] widget command except that it modifies the marquee options instead of modifying options for the overall treectrl widget. If no [arg option] is specified, the command returns a list describing all of the available marquee options (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no [arg value], then the command returns a list describing the one named marquee option (this list will be identical to the corresponding sublist of the value returned if no [arg option] is specified). If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given marquee option(s) to have the given value(s); in this case the command returns an empty string. [para] The following marquee options are supported: [list_begin options] [opt_def [option -fill] [arg color]] Specifies the color to fill the marquee rectangle with. See the comments above about using a transparent gradient here. [opt_def [option -outline] [arg color]] Specifies the color to outline the marquee rectangle with. [opt_def [option -outlinewidth] [arg color]] Specifies the width of the outline drawn inside the marquee's rectangle. The outline is not drawn if this value is less than 1. This option has no effect if the [option -outline] option is unspecified, i.e., the default dotted rectangle is unaffected by this option. [arg outlineWidth] may be in any of the forms acceptable to [fun Tk_GetPixels]. Defaults to 1. [opt_def [option -visible] [arg boolean]] Specifies a boolean value which determines whether the marquee is displayed. [list_end] [call [arg pathName] [cmd {marquee coords}] [opt [arg {x1 y1 x2 y2}]]] Returns a list containing the x and y coordinates of the anchor followed by the x and y coordinates of the corner, if no additional arguments are specified. If four coordinates are specified, sets the anchor to the given coordinates [arg x1] and [arg y1] and the corner to the coordinates [arg x2] and [arg y2]. [call [arg pathName] [cmd {marquee corner}] [opt [arg {x y}]]] Returns a list containing the x and y coordinates of the corner, if no additional arguments are specified. If two coordinates are specified, sets the corner to the given coordinates [arg x] and [arg y]. [call [arg pathName] [cmd {marquee identify}]] Returns a list with information about any items intersecting the marquee. The format of the returned list is: [example_begin] { {item {column element element ...} {column element element ...} ...} {item {column element element ...} {column element element ...} ...} ... } [example_end] There may be zero sublists following an item id if the marquee is in the button/line area of an item. There may be zero element names following a column id if the item-column has no style or if the marquee does not intersect any elements in that column. [list_end] [call [arg pathName] [cmd notify] [arg option] [opt [arg {arg ...}]]] Many Tk widgets communicate with the outside world via [option -command] callbacks and/or virtual events. For example, the Text widget evaluates its [option -yscrollcommand] when the view in the widget changes, and generates a <> virtual event when text is inserted or deleted. A treectrl widget replaces both methods of communication with its own event mechanism accessed through the [cmd notify] subcommands. [para] The exact behavior of the command depends on the [arg option] argument that follows the [cmd notify] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {notify bind}] [opt [arg object]] \ [opt [arg pattern]] [opt +][opt [arg script]]] This command associates Tcl scripts with events generated by a treectrl widget. If all three arguments are specified, [cmd {notify bind}] will arrange for [arg script] (a Tcl script) to be evaluated whenever the event(s) specified by [arg pattern] are generated by this treectrl widget. If [arg script] is prefixed with a "+", then it is appended to any existing binding for [arg pattern]; otherwise [arg script] replaces any existing binding. If [arg script] is an empty string then the current binding for [arg pattern] is destroyed, leaving [arg pattern] unbound. In all of the cases where a script argument is provided, [cmd {notify bind}] returns an empty string. [para] If [arg pattern] is specified without a [arg script], then the script currently bound to [arg pattern] is returned, or an empty string is returned if there is no binding for [arg pattern]. If neither [arg pattern] nor [arg script] is specified, then the return value is a list whose elements are all the patterns for which there exist bindings for [arg object]. [para] The [arg object] argument determines which window(s) the binding applies to. If [arg object] begins with a dot, as in .a.b.c, then it must be the path name for a window; otherwise it may be an arbitrary string. Like the regular [cmd bind] command, bindings on window names are automatically removed if that window is destroyed. [call [arg pathName] [cmd {notify configure}] [arg object] \ [arg pattern] [opt [arg option]] [opt [arg value]] \ [opt [arg {option value ...}]]] This command sets and retrieves options for bindings created by the [cmd {notify bind}] command. [para] If no [arg option] is specified, the command returns a list with [arg option]-[arg value] pairs describing all the available binding options for [arg pattern] on [arg object]. If [arg option] is specified with no [arg value], then the command returns the current value of that option. If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given option(s) to have the given value(s) for the binding; in this case the command returns an empty string. [para] The following binding options are supported: [list_begin options] [opt_def [option -active] [arg boolean]] Specifies if the binding should be active. As long as this option is specified as false, a binding script will not be evaluated when the corresponding event is generated. [list_end] [call [arg pathName] [cmd {notify detailnames}] [arg eventName]] Returns a list containing the names of all details, which are installed for the event with the name [arg eventName] by means of the [cmd {notify install}] widget command or by the treectrl widget itself. [call [arg pathName] [cmd {notify eventnames}]] Returns a list containing the names of all events, which are installed by means of the [cmd {notify install}] widget command or by the treectrl widget itself. [call [arg pathName] [cmd {notify generate}] [arg pattern] \ [opt [arg charMap]] [opt [arg percentsCommand]]] This command causes the treectrl widget to generate an event. This command is typically used to generate dynamic events created by the [cmd {notify install}] command, but may be used to generate static events also. The event specified by [arg pattern] is generated, and any active binding scripts on the event are evaluated after undergoing %-substitution. If there are details defined for the event, [arg pattern] must describe an <[arg eventName]-[arg detail]> pair, otherwise [arg pattern] should be <[arg eventName]>. [para] The optional [arg charMap] is a list of [arg char]-[arg value] pairs as in the form returned by [cmd {array get}]. Each [arg char] has to be exactly one character. The [arg charMap] is used in %-substitution. [para] If [arg percentsCommand] is specified, then it will be used to perform %-substitution on any scripts bound to the event. If [arg percentsCommand] is not specified and the event is dynamic, then the %-subtitution command passed to [cmd {notify install}] will be used if it was provided. If the event is static or no %-substitution command is available, then all %-substitution is done using [arg charMap] only . See [cmd {notify install}] for a description of [arg percentsCommand]. [call [arg pathName] [cmd {notify install}] [arg pattern] [opt [arg percentsCommand]]] This command installs a new event or detail specified by [arg pattern]. Events created by this command are called dynamic, whereas events created by the treectrl widget itself are called static. This command may be called to set or retrieve the [arg percentsCommand] for an existing dynamic event. [para] The optional [arg percentsCommand] is a list containing the name of a Tcl command, plus any optional arguments, to which five additional arguments will be appended. The command will be called to perform %-substitution on any scripts bound to the event specified by [arg pattern] (see [sectref {EVENTS AND SCRIPT SUBSTITUTIONS}]). [arg PercentsCommand] should be defined as follows: [example_begin] proc percentsCommand {?arg arg ...? char object event detail charMap} { switch -- $char { ... } return $value } [example_end] The optional [arg arg] arguments are part of the [arg percentsCommand] list. [arg Char] is the %-character to be substituted. [arg Object] is the same as the argument to [cmd {notify bind}]. [arg Event] and [arg detail] specify the event. [arg CharMap] is the same as the argument to [cmd {notify generate}]. [arg PercentsCommand] should return the value to replace the %-character by. If an error occurs evaluating [arg percentsCommand], the %-character is replaced by itself. [para] [cmd {notify install}] returns the current [arg percentsCommand] for the event, or an error if the event is not dynamic. [call [arg pathName] [cmd {notify install detail}] [arg eventName] \ [arg detail] [opt [arg percentsCommand]]] Deprecated. Use [cmd {notify install}] with a [arg pattern] of <[arg eventName]-[arg detail]> instead. [call [arg pathName] [cmd {notify install event}] [arg eventName] \ [opt [arg percentsCommand]]] Deprecated. Use [cmd {notify install}] with a [arg pattern] of <[arg eventName]> instead. [call [arg pathName] [cmd {notify linkage}] [arg pattern]] Returns a string indicating whether the specified event or detail is created by means of the [cmd {notify install}] widget command ([const dynamic]) or by the treectrl widget itself ([const static]). [call [arg pathName] [cmd {notify linkage}] [arg eventName] [opt [arg detail]]] Deprecated. Use [cmd {notify linkage}] with a [arg pattern] of <[arg eventName]> or <[arg eventName]-[arg detail]> instead. [call [arg pathName] [cmd {notify unbind}] [arg object] [opt [arg pattern]]] If no [arg pattern] is specified, all bindings on [arg object] are removed. If [arg pattern] is specified, then the current binding for [arg pattern] is destroyed, leaving [arg pattern] unbound. [call [arg pathName] [cmd {notify uninstall}] [arg pattern]] If the event or detail specified by [arg pattern] is static (i.e. created by the treectrl widget itself), an error is generated. Otherwise the dynamic event or detail is removed. If an event name is specified without a detail, all details for that event are also removed. [call [arg pathName] [cmd {notify uninstall detail}] \ [arg eventName] [arg detail]] Deprecated. Use [cmd {notify uninstall}] with a [arg pattern] of <[arg eventName]-[arg detail]> instead. [call [arg pathName] [cmd {notify uninstall event}] [arg eventName]] Deprecated. Use [cmd {notify uninstall}] with a [arg pattern] of <[arg eventName]> instead. [list_end] [call [arg pathName] [cmd numcolumns]] Deprecated. Use the [cmd {column count}] command instead. [call [arg pathName] [cmd numitems]] Deprecated. Use the [cmd {item count}] command instead. [call [arg pathName] [cmd orphans]] Returns a list containing the item ids of all items which have no parent. When an item is created, it has no parent by default, and can later become an orphan by means of the [cmd {item remove}] widget command. The root item is not returned. [call [arg pathName] [cmd range] [arg first] [arg last]] Deprecated. Use the [cmd {item range}] command instead. [call [arg pathName] [cmd scan] [arg option] [arg args]] This command is used to implement scanning on treectrls. It has two forms, depending on [arg option]: [list_begin definitions] [call [arg pathName] [cmd {scan mark}] [arg x] [arg y]] Records [arg x] and [arg y] and the treectrl's current view; used in conjunction with later [cmd {scan dragto}] commands. Typically this command is associated with a mouse button press in the widget and [arg x] and [arg y] are the coordinates of the mouse. It returns an empty string. [call [arg pathName] [cmd {scan dragto}] [arg x] [arg y] [opt [arg gain]]] This command computes the difference between its [arg x] and [arg y] arguments (which are typically mouse coordinates) and the [arg x] and [arg y] arguments to the last [cmd {scan mark}] command for the widget. It then adjusts the view by [arg gain] times the difference in coordinates, where [arg gain] defaults to 10. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the treectrl at high speed through its window. The return value is an empty string. [list_end] [call [arg pathName] [cmd see] [arg itemDesc] [opt [arg columnDesc]] [opt [arg {option value ...}]]] Adjust the view in the treectrl so that the item described by [arg itemDesc] is visible. If the item is already visible then the command has no effect; otherwise the treectrl scrolls to bring the item into view, and the corresponding [const ] and/or [const ] events are generated. If [arg columnDesc] is specified then a specific column of the item is scrolled into view instead of the entire item. [para] The following options are supported: [list_begin options] [opt_def [option -center] [arg flags]] [arg Flags] is a string that contains zero or more of the characters [const x] or [const y]. This option is used to center the item horizontally and/or vertically in the window. The item will be centered regardless of whether it is already visible. [list_end] [call [arg pathName] [cmd selection] [arg option] [arg args]] This command is used to adjust the selection within a treectrl. It has several forms, depending on [arg option]: [list_begin definitions] [call [arg pathName] [cmd {selection add}] [arg first] [opt [arg last]]] [arg First] and [arg last] (if specified) must be valid [sectref {ITEM DESCRIPTION} {item descriptions}]. If both [arg first] and [arg last] are specified, then they may refer to a single item only; in this case the command adds every unselected item in the range between [arg first] and [arg last], inclusive, to the selection without affecting the selected state of items outside that range. If only [arg first] is specified, then every unselected item specified by [arg first] is added to the selection. A [const ] event is generated if any items were added to the selection. [call [arg pathName] [cmd {selection anchor}] [opt [arg itemDesc]]] If [arg itemDesc] is specified, the selection anchor is set to the described item. The selection anchor is the end of the selection that is fixed while dragging out a selection with the mouse. The item description [const anchor] may be used to refer to the anchor item. This command doesn't modify the selection state of any item. Returns the unique id of the selection anchor item. [call [arg pathName] [cmd {selection clear}] [opt [arg first]] [opt [arg last]]] [arg First] and [arg last] (if specified) must be valid [sectref {ITEM DESCRIPTION} {item descriptions}]. If both [arg first] and [arg last] are specified, then they may refer to a single item only; in this case any selected items between [arg first] and [arg last] (inclusive) are removed from the selection without affecting the selected state of items outside that range. If only [arg first] is specified, then every selected item specified by [arg first] is removed from the selection. If neither [arg first] nor [arg last] are specified, then all selected items are removed from the selection. A [const ] event is generated if any items were removed from the selection. [call [arg pathName] [cmd {selection count}]] Returns an integer indicating the number of items in the treectrl that are currently selected. [call [arg pathName] [cmd {selection get}] [opt [arg first]] [opt [arg last]]] When no additional arguments are given, the result is an unsorted list containing the item ids of all of the items in the treectrl that are currently selected. If there are no items selected in the treectrl, then an empty string is returned. The optional arguments [arg first] and [arg last] are treated as indices into the sorted list of selected items; these arguments allow in-place [cmd lindex] and [cmd lrange] operations on the selection. For example: [example_begin] .t selection get 0 ; # return the first selected item .t selection get end ; # return the last selected item .t selection get 1 end-1 ; # return every selected item except the first and last [example_end] [call [arg pathName] [cmd {selection includes}] [arg itemDesc]] Returns 1 if the item described by [arg itemDesc] is currently selected, 0 if it isn't. [call [arg pathName] [cmd {selection modify}] [arg select] [arg deselect]] Both arguments [arg select] and [arg deselect] are a possibly-empty list of [sectref {ITEM DESCRIPTION} {item descriptions}]. Any unselected items in [arg select] are added to the selection, and any selected items in [arg deselect] are removed from the selection (except for those items which are also in [arg select]). A [const ] event is generated if any items were selected or deselected. [list_end] [call [arg pathName] [cmd state] [arg option] [arg args]] This command is used to manipulate the list of user-defined item states, see section [sectref STATES] below. Item states can also be managed using the [cmd {item state}] command. To manage states for [sectref HEADERS header-rows], use the [cmd {header state}] widget command. The exact behavior of the command depends on the [arg option] argument that follows the [cmd state] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {state define}] [arg stateName]] Defines a new state with the name [arg stateName], which must not be the name of an existing state. [call [arg pathName] [cmd {state linkage}] [arg stateName]] Returns a string indicating whether the specified state is user-defined by means of the [cmd {state define}] widget command ([const dynamic]) or predefined by the treectrl widget itself ([const static]). [call [arg pathName] [cmd {state names}]] Returns a list containing the names of all user-defined states. [call [arg pathName] [cmd {state undefine}] [opt [arg {stateName ...}]]] Every [arg stateName] must be the name of a user-defined state. Removes this state from the list of user-defined states. [list_end] [call [arg pathName] [cmd style] [arg option] [opt [arg element]] \ [opt [arg {arg arg ...}]]] This command is used to manipulate styles, which can be thought of as a geometry manager for elements. The exact behavior of the command depends on the [arg option] argument that follows the [cmd style] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {style cget}] [arg style] [arg option]] This command returns the current value of the option named [arg option] associated with the style given by [arg style]. [arg Option] may have any of the values accepted by the [cmd {style configure}] widget command. [para] This command also accepts the [option -statedomain] option. [call [arg pathName] [cmd {style configure}] [arg style] [opt [arg option]] \ [opt [arg value]] [opt [arg {option value ...}]]] This command is similar to the [cmd configure] widget command except that it modifies options associated with the style given by [arg style] instead of modifying options for the overall treectrl widget. If no [arg option] is specified, the command returns a list describing all of the available options for [arg style] (see [fun Tk_ConfigureInfo] for information on the format of this list). If [arg option] is specified with no [arg value], 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 [arg option] is specified). If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given option(s) to have the given value(s) in [arg style]; in this case the command returns an empty string. [para] The following options are supported: [list_begin options] [opt_def [option -buttony] [arg offset]] Specifies the distance from the top of the item that the expand/collapse button should be drawn. If [arg offset] is an empty string (the default) then the button is centered vertically in the item. The value may have any of the forms acceptable to [fun Tk_GetPixels]. This option only has effect when the style is set in an item in the tree column. [opt_def [option -orient] [arg varName]] This option specifies which orientation should be used when laying out the elements associated with this style. Must be either [const horizontal] (the default) or [const vertical] or an abbreviation of one of these. [list_end] [call [arg pathName] [cmd {style create}] [arg name] \ [opt [arg {option value ...}]]] Creates a new style with the unique user-defined name [arg name]. After [arg name] there may be any number of [arg option]-[arg value] pairs, each of which sets one of the configuration options for the style. See the [cmd {style configure}] command for the possible options. The result of this command is the name of the new style (the same as the [arg name] option). [para] This command also accepts the [option -statedomain] option with a value of either [const header] or [const item] to specify where this style will be displayed. [call [arg pathName] [cmd {style delete}] [opt [arg {style ...}]]] Deletes each of the named styles and returns an empty string. If a style is deleted while it is still used to display one or more items, it is also removed from the style list of these items. [call [arg pathName] [cmd {style elements}] [arg style] \ [opt [arg elementList]]] Specifies the elements which should be layed out by this style. Each element of [arg elementList] must be the name of an element created by the widget command [cmd {element create}]. Duplicate names in [arg elementList] are ignored. An element which was specified in a former call of this command for [arg style] but is not included in [arg elementList], will be deleted from the elements layed out by [arg style]. [para] Every element used by a style must have been created with the same value for the [option -statedomain] option. [para] If the [arg elementList] argument is not specified, a list is returned containing the currently defined elements of [arg style]. [call [arg pathName] [cmd {style layout}] [arg style] [arg element] \ [opt [arg option]] [opt [arg value]] [opt [arg {option value ...}]]] This command is similar to the [cmd configure] widget command except that it modifies options used by [arg style] for laying out [arg element] instead of modifying options for the overall treectrl widget. If no [arg option] is specified, the command returns a list with [arg option]-[arg value] pairs describing all of the available options for the layout. If [arg option] is specified with no [arg value], then the command returns the value of the named option. If one or more [arg option]-[arg value] pairs are specified, then the command modifies the given option(s) to have the given value(s) for the layout; in this case the command returns an empty string. [para] The options of a layout have effect on exactly the one element [arg element] managed by [arg style]. The following options are supported: [list_begin options] [opt_def [option -detach] [arg boolean]] Specifies whether the element should be positioned by itself, i.e. independent from the other elements. The default is false. [opt_def [option -center] [arg flags]] [arg Flags] is a string that contains zero or more of the characters [const x] or [const y]. [const x] causes the element to be centered horizontally, [const y] causes the element to be centered vertically. When more than one element has -center layout, all the elements between the first and last with -center layout in the style's list of elements are centered as a group. Consider the following when there is another element to the right of MyElement: [example_begin] .t style layout MyStyle MyElement -expand we .t style layout MyStyle MyElement -center x [example_end] With the first call, MyElement will be centered only within the space that is not occupied by the other element, so MyElement will appear off-center towards the left of the style. With the second call, MyElement will be centered within the style so long as it doesn't overlap the other element. [opt_def [option -draw] [arg boolean]] This is a [sectref {PER-STATE OPTIONS} per-state] option that determines whether an element should be drawn. If the value of the option evaluates to false for a given item state, then the element is not drawn, although it still consumes space in the layout. [opt_def [option -expand] [arg flags]] This option allows the external padding around the element to increase when a style has more screen space than it needs. [arg Flags] is a string that contains zero or more of the characters [const n], [const s], [const w] or [const e]. Each letter refers to the padding on the top, bottom, left, or right that should be allowed to increase. This option is typically used to justify an element. The default is an empty string. [opt_def [option -iexpand] [arg flags]] This option allows the internal padding of the element and the display area of the element to increase when a style has more screen space than it needs. [arg Flags] is a string that contains zero or more of the characters [const x], [const y], [const n], [const s], [const w] or [const e]. For [const n], [const s], [const w] and [const e], each letter refers to the padding on the top, bottom, left, or right that should be allowed to increase. For [const x] and [const y], each letter refers to the horizontal and vertical screen space the element can display itself in (i.e., the space between the padding). Note that if the [option -union] option is specified for this element, then the [const x] and [const y] flags have no effect, since the size of an element with [option -union] layout is determined by the elements it surrounds. The default is an empty string. [opt_def [option -indent] [arg boolean]] For item styles, this option specifies whether the element should be positioned to the right of the button/line area in the tree column. When false, the element is displayed beneath the buttons and lines in the tree column. This option is ignored unless the [option -detach] option is true. [para] For header styles, this option specifies whether the element should be positioned to the right of the -canvaspadx padding. This option is ignored unless the [option -detach] option is true or the [option -union] option is specified. [para] The default is true. [opt_def [option -ipadx] [arg amount]] [opt_def [option -ipady] [arg amount]] [arg Amount] specifies how much internal padding to leave on the left and right (for [option -ipadx]) or top and bottom (for [option -ipady]) sides of the element. [arg Amount] may be a list of two values to specify padding for the two sides separately. The default value is 0. This option is typically used with the [option -union] layout option, to create space around the enclosed elements. [opt_def [option -minheight] [arg pixels]] [opt_def [option -height] [arg pixels]] [opt_def [option -maxheight] [arg pixels]] Specifies the minimum, fixed, and maximum height of the display area of the element. The default is unspecified. [opt_def [option -minwidth] [arg pixels]] [opt_def [option -width] [arg pixels]] [opt_def [option -maxwidth] [arg pixels]] Specifies the minimum, fixed, and maximum width of the display area of the element. The default is unspecified. [opt_def [option -padx] [arg amount]] [opt_def [option -pady] [arg amount]] [arg Amount] specifies how much external padding to leave on the left and right (for [option -padx]) or top and bottom (for [option -pady]) sides of the element. [arg Amount] may be a list of two values to specify padding for the two sides separately. The default value is 0. [opt_def [option -squeeze] [arg flags]] This option allows the display area of an element to decrease when a style has less space than it needs. [arg Flags] is a string that contains zero or more of the characters [const x] or [const y]. [const x] allows display area to decrease horizontally, [const y] allows display area to decrease vertically. This option is typically used for [const text] elements and will cause the text element to display an ellipsis (...) and/or wrap lines. The default is an empty string. [opt_def [option -sticky] [arg flags]] This option controls how the actual display information (image, text, etc) of an element is positioned (or stretched) within its display area. [arg Flags] is a string that contains zero or more of the characters [const n], [const s], [const w] or [const e]. Each letter refers to the top, bottom, left or right side of the display area that the display information should "stick" to. The default is nswe. [opt_def [option -union] [arg elementList]] Specifies a list of other elements which this element will surround. The size of an element with [option -union] layout is determined by the size and position of the elements in [arg elementList]. The [option -ipadx] and [option -ipady] options in this case refer to the distance of the edges of the display area of this element from those elements it surrounds. This option is typically used to display a selection rectangle around a piece of text. If none of the elements in [arg elementList] are visible, then the element is not displayed. [opt_def [option -visible] [arg boolean]] This is a [sectref {PER-STATE OPTIONS} per-state] option that controls visibility of an element. If the value of the option evaluates to false for a given item state, then the element is not displayed and consumes no space in the layout. [list_end] [call [arg pathName] [cmd {style names}]] Returns a list containing the names of all existing styles. [list_end] [call [arg pathName] [cmd theme] [arg option] [opt [arg {arg ...}]]] This command is used to interact with the platform-specific theme. The exact behavior of the command depends on the [arg option] argument that follows the [cmd theme] argument. The following forms of the command are supported: [list_begin definitions] [call [arg pathName] [cmd {theme platform}]] Returns the API used to draw themed parts of the treectrl. On Mac OS X the result is always [const aqua]. On MS Windows the result is [const visualstyles] if the uxtheme.dll was loaded and visual themes are in use, otherwise [const X11] is returned to indicate the Tk Xlib calls are drawing the themed parts. On Unix systems the result is [const gtk] if the Gtk+ version of treectrl was built, otherwise [const X11] is returned. [call [arg pathName] [cmd {theme setwindowtheme}] [arg appname]] The command is available on MS Windows only. If [arg appname] is "Explorer" then the item buttons look like those in the Explorer file browser (disclosure triangles under Windows Vista/7). If [arg appname] is an empty string then the buttons revert to their default appearance according to the system's current visual style. [list_end] [call [arg pathName] [cmd toggle] [opt [option -recurse]] \ [opt [arg {itemDesc ...}]]] Use [cmd {item toggle}] instead. [call [arg pathName] [cmd xview] [opt [arg args]]] This command is used to query and change the horizontal position of the information displayed in the treectrl's window. It can take any of the following forms: [list_begin definitions] [call [arg pathName] [cmd xview]] 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 tree's area is off-screen to the left, the middle 40% is visible in the window, and 40% of the tree is off-screen to the right. These are the same values passed to scrollbars via the [option -xscrollcommand] option. [call [arg pathName] [cmd {xview moveto}] [arg fraction]] Adjusts the view in the window so that [arg fraction] of the total width of the tree is off-screen to the left. [arg Fraction] must be a fraction between 0 and 1. A [const ] event is generated. [call [arg pathName] [cmd {xview scroll}] [arg number] [arg what]] This command shifts the view in the window left or right according to [arg number] and [arg what]. [arg Number] must be an integer. [arg What] must be either [const units] or [const pages] or an abbreviation of one of these. If [arg what] is [const units], the view adjusts left or right in units determined by the [option -xscrollincrement] option (which may be zero, see the description of that option). If [arg what] is [const pages] then the view adjusts in units of nine-tenths the window's width. If [arg number] is negative then information farther to the left becomes visible; if it is positive then information farther to the right becomes visible. A [const ] event is generated. [list_end] [call [arg pathName] [cmd yview] [opt [arg args]]] This command is used to query and change the vertical position of the information displayed in the treectrl's window. It can take any of the following forms: [list_begin definitions] [call [arg pathName] [cmd yview]] Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the vertical span that is visible in the window. For example, if the first element is .6 and the second element is 1.0, the lowest 40% of the tree's area is visible in the window. These are the same values passed to scrollbars via the [option -yscrollcommand] option. [call [arg pathName] [cmd {yview moveto}] [arg fraction]] Adjusts the view in the window so that [arg fraction] of the tree's area is off-screen to the top. [arg Fraction] is a fraction between 0 and 1. A [const ] event is generated. [call [arg pathName] [cmd {yview scroll}] [arg number] [arg what]] This command adjusts the view in the window up or down according to [arg number] and [arg what]. [arg Number] must be an integer. [arg What] must be either [const units] or [const pages]. If [arg what] is [const units], the view adjusts up or down in units of the [option -yscrollincrement] option (which may be zero, see the description of that option). If [arg what] is [const pages] then the view adjusts in units of nine-tenths the window's height. If [arg number] is negative then higher information becomes visible; if it is positive then lower information becomes visible. A [const ] event is generated. [list_end] [list_end] [section HEADERS] A treectrl widget can display zero or more rows of column headers. When a treectrl widget is created, a single row of column headers (aka a header-row) is created as well; this top header-row cannot be deleted. Additional header-rows can be created with the [cmd {header create}] command and deleted with [cmd {header delete}]. [para] There are no commands for changing the order of header-rows; they are displayed from top to bottom in the order they were created. [para] Drag-and-drop reordering of column headers is supported within a widget. To control column header drag-and-drop, use the [cmd {header dragconfigure}] command. [para] Header-rows in a treectrl may be specified in a number of ways. See [sectref {HEADER DESCRIPTION}] below. [para] The appearance of individual column headers within a header-row may be customized in two different ways: [list_begin enum] [enum] By configuring various column header options with the [cmd {header configure}] command [enum] By assigning a style to a column header with the [cmd {header style}] command. [list_end] [para] When one of the options below is specified as [sectref {PER-STATE OPTIONS} per-state], the state names are those described in [sectref {STATES}] for headers only, i.e. do not use item state names. [para] The following options are supported for each individual column header: [list_begin options] [opt_def [option -arrow] [arg direction]] Indicates whether or not a sort arrow should be drawn in the column header. [arg Direction] must have one of the values [const none] (the default), [const up], or [const down]. [opt_def [option -arrowbitmap] [arg bitmap]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the name of a bitmap to use to draw the arrow if this column's -arrow option is not [const none]. [opt_def [option -arrowgravity] [arg direction]] Indicates onto which side the sort arrow should be packed, if there is more space available for drawing the arrow then needed. [arg direction] must be either [const left] (the default) or [const right]. [opt_def [option -arrowimage] [arg image]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the name of an image to use to draw the sort arrow if this column's -arrow option is not [const none]. If an image is specified for a certain state, it overrides the -arrowbitmap option. [opt_def [option -arrowpadx] [arg amount]] [arg Amount] specifies how much padding to leave on the left and right of the sort arrow. [arg Amount] may be a list of two values to specify padding for left and right separately; it defaults to 6. [opt_def [option -arrowpady] [arg amount]] [arg Amount] specifies how much padding to leave on the top and bottom of the sort arrow. [arg Amount] may be a list of two values to specify padding for top and bottom separately; it defaults to 0. [opt_def [option -arrowside] [arg side]] Indicates on which side of the bitmap/image/text the sort arrow should be drawn. [arg Side] must be either [const left] or [const right] (the default). [opt_def [option -bitmap] [arg bitmap]] Specifies the name of a bitmap to display to the left of the column title. [opt_def [option -background] [arg color]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the color to use for the background of the column header. [opt_def [option -borderwidth] [arg size]] Specifies a non-negative value indicating the width of the 3-D border to draw around the outside of the column header (if such a border is being drawn; the [option -relief] column option determines this). The value may have any of the forms acceptable to [fun Tk_GetPixels]. [opt_def [option -button] [arg boolean]] Indicates whether or not the column header should be treated like a pushbutton. When this option is true, the default bindings track events in the header and generate a event when a event occurs in the header. See [sectref {DYNAMIC EVENTS}]. [opt_def [option -font] [arg fontName]] Specifies the font to use for displaying the column title inside the column header. When the value of this option is unspecified, the font specified by the widget option [option -headerfont] is used. [opt_def [option -image] [arg image]] Specifies the name of an image to display to the left of the column title. This option overrides the [option -bitmap] column option. [opt_def [option -imagepadx] [arg amount]] [arg Amount] specifies how much padding to leave on the left and right of the image (or bitmap). [arg Amount] may be a list of two values to specify padding for left and right separately; it defaults to 6. [opt_def [option -imagepady] [arg amount]] [arg Amount] specifies how much padding to leave on the top and bottom of the image (or bitmap). [arg Amount] may be a list of two values to specify padding for top and bottom separately; it defaults to 0. [opt_def [option -justify] [arg justification]] This option determines how the image and text in the column header are positioned. Must be one of [const left] (the default), [const center], or [const right]. [opt_def [option -state] [arg state]] Specifies one of three states for the column header: [const normal], [const active], or [const pressed]. The active state is used when the mouse is over the header. The pressed state is used when the mouse button is pressed in the header. [para] Changing the value of this option also affects the current set of [sectref {STATES} {header states}] for the column header, which may affect both the [sectref {PER-STATE OPTIONS} {per-state}] options mentioned here (such as [option -arrowimage]) as well as the elements in any style that may be assigned to the column header. [opt_def [option -text] [arg text]] Specifies a text string to be displayed as the column title. [opt_def [option -textcolor] [arg color]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the color to display the column title with. When the value of this option is unspecified, the title will be drawn according to the system theme color, if any, otherwise the widget option [option -headerforeground] is used. The default is unspecified. [opt_def [option -textlines] [arg count]] Specifies the maximum number of lines of text to display in the column title. If this value is zero, the number of lines displayed is determined by any newline characters and the effects of wrapping when the column width is less than needed. The default is 1. Note: Under OSX/Aqua this value is always set to 1 when the treectrl's [option -usetheme] option is true, because the Appearance Manager uses a fixed height for the column header; there is only room for a single line of text. [opt_def [option -textpadx] [arg amount]] [arg Amount] specifies how much padding to leave on the left and right of the text. [arg Amount] may be a list of two values to specify padding for left and right separately; it defaults to 6. [opt_def [option -textpady] [arg amount]] [arg Amount] specifies how much padding to leave on the top and bottom of the text. [arg Amount] may be a list of two values to specify padding for top and bottom separately; it defaults to 0. [list_end] [section {HEADER DESCRIPTION}] Many of the commands for a treectrl take as an argument a description of which header-rows to operate on. A [emph {header description}] is a properly-formed tcl list of keywords and arguments. The first word of a header description must be one of the following: [list_begin definitions] [def [arg id]] Specifies a unique header-row identifier, where [arg id] should be the return value of a prior call of the [cmd {header create}] widget command, or [const 0] to specify the ever-present top header-row. [def [arg QUALIFIERS]] Specifies a list of qualifiers. This gives the same result as [const all] followed by [arg QUALIFIERS]; i.e., every header-row is tested for a match. [def "[arg tagExpr] [arg QUALIFIERS]"] [arg TagExpr] is a tag expression (see [sectref {ITEM AND COLUMN TAGS}]) against which every header-row's tags are tested for a match. You may run into trouble if [arg tagExpr] looks like a header-row id or other keyword; also, [arg tagExpr] must look like a single list element since header-row descriptions are properly-formed lists. To be safe you may want to use the [const tag] qualifier followed by [arg tagExpr]. [example_begin] .t header dragconfigure {tag -funky} -draw yes [example_end] [def "[const all] [arg QUALIFIERS]"] Matches every header-row which satisfies [arg QUALIFIERS]. [def "[const first] [arg QUALIFIERS]"] Indicates the top header-row of the treectrl, or the first header-row starting from the top that satisfies [arg QUALIFIERS]. [def "[const end] [arg QUALIFIERS]"] [def "[const last] [arg QUALIFIERS]"] Indicates the last header-row which satisfies [arg QUALIFIERS]. [list_end] The word [arg QUALIFIERS] above represents a series of zero or more of the following terms that changes which header-row is chosen: [list_begin definitions] [def "[const tag] [arg tagExpr]"] [arg TagExpr] is a tag expression (see [sectref {ITEM AND COLUMN TAGS}]) against which a header-row's tags are tested for a match. [def [const visible]] When this qualifier is given, only header-rows that are displayed are matched. A header-row is displayed only if both the [const -showheader] widget option and [const -visible] header-row option are true. Also, if only the tail column is visible, then header-rows are not displayed. [def [const !visible]] When this qualifier is given, only header-rows that are *not* displayed are matched. [list_end] [section COLUMNS] A treectrl widget is capable of displaying multiple columns next to each other. An item can be considered as a row, which reaches over all columns. [para] Columns in a treectrl may be specified in a number of ways. See [sectref {COLUMN DESCRIPTION}] below. [para] There is always one special column, the [const tail] column, which fills all space to the right of the last ordinary column. This column has no unique ID; it can only be specified by the keyword [const tail]. [para] For compatibility with older versions of treectrl (which did not support more than one row of column headers) any of the configuration options mentioned in the [sectref HEADERS] section, such as [option -arrow], [option -text], etc, may be passed to the top header-row through the [cmd {column configure}] command and queried with the [cmd {column cget}] command. [para] The following options are supported for columns: [list_begin options] [opt_def [option -expand] [arg boolean]] Indicates whether or not any extra horizontal space should be distributed to this column. This option has no effect if the [option -width] option is set. [opt_def [option -gridleftcolor] [arg color]] [opt_def [option -gridrightcolor] [arg color]] Specifies the color of the lines drawn down the left and right edges of the column. These so-called "grid lines" are drawn over the elements of each item style in the column and down into the whitespace region below any items. The default value for each option is an empty string meaning no lines are drawn. [opt_def [option -itembackground] [arg colorList]] Specifies a list of zero or more colors, which are used as alternating background colors for items in this column. See also the [option -backgroundmode] widget option for more on this. [opt_def [option -itemjustify] [arg justification]] This option determines how the item styles in this column are aligned horizontally. Must be one of [const left], [const center], or [const right]. The default value is an empty string (for compatibility with older versions), in which case the column option [option -justify] is used to align item styles in this column. [opt_def [option -itemstyle] [arg style]] [arg Style] is the name of a style that should be set in this column for newly-created items. [opt_def [option -justify] [arg justification]] This option determines how item styles in this column are aligned horizontally unless overriden by the [option -itemjustify] option for this column. Must be one of [const left] (the default), [const center], or [const right]. [para] For compatibility with older versions of treectrl (which did not allow multiple rows of column headers), changing the value of this option also changes the [option -justify] option of the column header in the top [sectref HEADERS header-row]. [opt_def [option -lock] [arg lock]] This option allows a column to stick to the left or right edge of the window. A locked column scrolls vertically but not horizontally. Must be one of [const none] (the default), [const left], or [const right]. [opt_def [option -maxwidth] [arg size]] Specifies the maximum size, in screen units, that will be permitted for this column. If [arg size] is an empty string, then there is no limit on the maximum size of the column. This option has no effect if the [option -width] option is set. [opt_def [option -minwidth] [arg size]] Specifies the minimum size, in screen units, that will be permitted for this column. If [arg size] is an empty string, then the minimum size of the column is zero. This option has no effect if the [option -width] option is set. [opt_def [option -resize] [arg boolean]] Specifies a boolean value that indicates whether the user should be allowed to resize the column by dragging the edge of the column's header. Default is true. [opt_def [option -squeeze] [arg boolean]] Specifies a boolean value that indicates whether or not the column should shrink when the content width of the treectrl is less than the total needed width of all visible columns. Defaults to false, which means the column will not get smaller than its needed width. The column will not get smaller than the value of its [option -minwidth] option, if specified. This option has no effect if the [option -width] option is set. [opt_def [option -stepwidth] [arg size]] Deprecated. Use the treectrl's [option -itemwidthmultiple] option instead. [opt_def [option -tags] [arg tagList]] [arg TagList] is a list of tag names that can be used to identify the column. See also the [cmd {column tag}] command. [opt_def [option -uniform] [arg group]] When a non-empty value is supplied, this option places the column in a [emph "uniform group"] with other columns that have the same value for [option -uniform]. The space for columns belonging to a uniform group is allocated so that their sizes are always in strict proportion to their [option -weight] values. This option is based on the grid geometry manager. [opt_def [option -visible] [arg boolean]] Indicates whether or not the column should be displayed. [opt_def [option -weight] [arg integer]] Sets the relative weight for apportioning any extra space among columns. A weight of zero (0) indicates the column will not deviate from its requested size. A column whose weight is two will grow at twice the rate as a column of weight one when extra space is allocated to columns. This option is based on the grid geometry manager. [opt_def [option -width] [arg size]] Specifies a fixed width for the column. If this value is an empty string, then the column width is calculated as the maximum of: a) the width requested by items; b) the width requested by the column's header; and c) the column's [option -minwidth] option. This calculated width is also affected by the [option -expand], [option -squeeze], [option -uniform] and [option -weight] options. In any case, the calculated width will not be greater than the [option -maxwidth] option, if specified. [opt_def [option -widthhack] [arg boolean]] Deprecated. Use the treectrl's [option -itemwidthequal] option instead. [list_end] [section {COLUMN DESCRIPTION}] Many of the commands and options for a treectrl take as an argument a description of which column to operate on. See the [sectref EXAMPLES] section for examples. The initial part of a column description must begin with one of the following terms: [list_begin definitions] [def [arg id]] Specifies the unique column identifier, where [arg id] should be the return value of a prior call of the [cmd {column create}] widget command. See also the [option -columnprefix] option. [def [arg QUALIFIERS]] Specifies a list of qualifiers. This gives the same result as [const all] followed by [arg QUALIFIERS]; i.e., every column is tested for a match. [def "[arg tagExpr] [arg QUALIFIERS]"] [arg TagExpr] is a tag expression (see [sectref {ITEM AND COLUMN TAGS}]) against which every column's tags are tested for a match. This keyword cannot be followed by any modifiers unless a single column is matched. You may run into trouble if [arg tagExpr] looks like a column id or other keyword; also, [arg tagExpr] must look like a single list element since column descriptions are properly-formed lists. To be safe you may want to use the [const tag] qualifier followed by [arg tagExpr]. [def "[const all] [arg QUALIFIERS]"] Indicates every column, including the tail column if the command allows it, which match [arg QUALIFIERS]. [def "[const first] [arg QUALIFIERS]"] Indicates the leftmost column of the treectrl which matches [arg QUALIFIERS]. [def "[const end] [arg QUALIFIERS]"] [def "[const last] [arg QUALIFIERS]"] Indicates the rightmost column of the treectrl (but not the tail column) which matches [arg QUALIFIERS]. [def "[const list] [arg columnDescs]"] [arg ColumnDescs] is a list (a single argument, i.e. "list {a b c}" not "list a b c") of other column descriptions. This keyword cannot be followed by any modifiers unless a single column is matched. [def "[const order] [arg n] [arg QUALIFIERS]"] Indicates the [arg n]th column in the list of columns as returned by the [cmd {column order}] command. [def "[const range] [arg {first last}] [arg QUALIFIERS]"] [arg First] and [arg last] specify a range of columns. This keyword cannot be followed by any modifiers unless a single column is specified. [def [const tail]] Indicates the ever-present tail column of the treectrl. [def [const tree]] Indicates the column specified by the -treecolumn option of the treectrl. [list_end] [para] The initial part of the column description (matching any of the values above) may be followed by one or more [arg modifier]s. A modifier changes the column used relative to the description up to this point. It may be specified in any of the following forms: [list_begin definitions] [def "[const next] [arg QUALIFIERS]"] Use the column to the right matching [arg QUALIFIERS]. [def "[const prev] [arg QUALIFIERS]"] Use the column to the left matching [arg QUALIFIERS]. [def "[const span] [arg N] [arg QUALIFIERS]"] Starting with (and counting) the single column specified by the column description so far, walk at most [arg N] columns rightwards, stopping if any of the following conditions is met: [list_begin enum] [enum] A column does not match [arg QUALIFIERS]. [enum] A column's -lock option does not match the first column's -lock option. [list_end] [list_end] The word [arg QUALIFIERS] above represents a sequence of zero or more of the following terms that changes which column is chosen: [list_begin definitions] [def "[const tag] [arg tagExpr]"] [arg TagExpr] is a tag expression (see [sectref {ITEM AND COLUMN TAGS}]) against which a column's tags are tested for a match. [def [const !tail]] When this qualifier is given, the tail column is not matched. [def [const visible]] When this qualifier is given, only columns whose [option -visible] option is TRUE are considered. [def [const !visible]] When this qualifier is given, only columns whose [option -visible] option is FALSE are considered. [list_end] [section STATES] For every column header and every item a set of boolean states is managed. These states play an integral role in the appearance of headers and items; that role is described in detail in [sectref {PER-STATE OPTIONS}]. The set of states available to headers is separate from the set of states available to items. [list_begin definitions] [def {HEADER STATES}] The following states are predefined for every column header: [list_begin definitions] [def [const active]] [def [const normal]] [def [const pressed]] These states mirror the value of a column header's configuration option [option -state]. Exactly one of these states is set at any time in each column header. [def [const down]] [def [const up]] These states mirror the value of a column header's configuration option [option -arrow]. If the [option -arrow] option is [const none], then neither of these states is set. [def [const background]] This state is set for every header-row if the toplevel window containing the treectrl is not the foreground active window. This state cannot be modified by means of a widget command, but is maintained in reaction to the and windowing system events. [def [const focus]] This state is set for every header-row if the treectrl widget currently has the focus. It cannot be modified by means of a widget command, but is maintained in reaction to the and windowing system events. [list_end] [def {ITEM STATES}] The following states are predefined for every item: [list_begin definitions] [def [const active]] At all times this state is set for exactly one item. The active item is used with keyboard navigation. When the treectrl widget is created or when the active item is deleted, the root item will become the active item. This state can be modified by means of the widget command [cmd activate]. [def [const enabled]] This state is set for every item when it is created. Disabled items cannot be selected and are ignored by the default bindings when navigating via the keyboard. This state can be modified by means of the widget command [cmd {item enabled}]. [def [const focus]] This state is set for every item if the treectrl widget currently has the focus. It cannot be modified by means of a widget command, but is maintained in reaction to the and events. [def [const open]] If this state is switched on, the descendants of the item are displayed - the item is expanded. If this state is switched off, the descendants of the item are not displayed - the item is collapsed. For a new item this state is switched on by default. This state can be modified by means of the widget commands [cmd {item expand}], [cmd {item collapse}], or [cmd {item toggle}]. [def [const selected]] This state is set for every item included in the selection. It can be modified by means of the widget command [cmd selection]. [list_end] [para] By means of the [cmd {state define}] widget command, up to 27 additional states can be defined. [list_end] [section {PER-STATE OPTIONS}] The visual appearance of an item can change depending on the state the item is in, such as being the active item, being included in the selection, being collapsed, or some combination of those or other states. When a configuration option is described as [emph per-state], it means the option describes a value which varies depending on the state of the item. If a per-state option is specified as a single value, the value is used for all states. Otherwise the per-state option must be specified as an even-numbered list. For example, to use the font "Times 12 bold" in a [const text] element regardless of the item state you can write: [example_begin] $T element configure MyTextElement -font {{Times 12 bold}} [example_end] However, to use a different font when the item is selected you could write: [example_begin] $T element configure MyTextElement -font {{Courier 10} selected {Times 12 bold} {}} [example_end] In the example above, the -font option reads "value stateList value stateList". If [arg stateList] is an empty list, the preceding [arg value] is used regardless of the item state. A non-empty stateList specifies a list of states which must be set for the item in order to use the preceding value. Each stateList can also include state names preceded by a ! sign, indicating the state must *not* be set for the item. For example: [example_begin] $T element configure MyRectElement -fill {blue {selected focus} gray {selected !focus}} [example_end] In the example above, the [const rect] element is filled with blue when the treectrl has the focus and the item is selected. If the treectrl does not have the focus, the example specifies that gray should be used for selected items. Also note that if the item is not selected, no color is specified for the -fill option. [para] Each value-stateList pair is checked in order from left to right. The value associated with the first stateList that matches the current item state is used. So stateLists should be listed from most-specific to least-specific. [example_begin] $T element configure MyRectElement -fill {gray {selected} blue {selected focus}} [example_end] Written this way, gray will always be used for selected items since it appears first, and blue will never be used for selected items regardless of the focus. [para] A value followed by an empty stateList should always be last since it will be chosen regardless of the item's state. [section {ELEMENTS AND STYLES}] [emph Elements] and [emph styles] are the core visual building blocks that determine the appearance of items (and optionally column headers). An element can be of type [const bitmap], [const border], [const header], [const image], [const rect], [const text] or [const window]. One or more elements can be assigned to a style which manages the layout of those elements. It may be helpful to think of an element as a Tk widget and a style as a Tk geometry manager such as [cmd grid], [cmd pack] or [cmd place]. [para] When an element is created by the [cmd {element create}] command, that element is referred to as a [emph master] element. Similarly, a style that is created by [cmd {style create}] is called a [emph master] style. When a master style is assigned to a column of an item by the [cmd {item style set}] command, a new instance style is allocated which refers back to the master style and its master elements. In this way, a single master style may be shared by multiple columns of multiple items. If a master element or master style is modified, those changes affect all the items whose instance styles and elements refer to those masters. [para] Although you probably want the font and selection-rectangle colors to be shared by all items, you most likely don't want the text to be the same for every column of every item. The [cmd {item element configure}] command can be used to override a master element's configuration options for a specific column of an item. When you call [cmd {item element configure}] (or [cmd {item text}] or [cmd {item image}]), a new instance element is allocated, if one wasn't already, and that instance element's options will override the master element's. [para] All of the element configuration options described below are unspecified by default, meaning that no value whatsoever has been given to the option. It may seem strange to you that a boolean option would be unspecified instead of simply "true" or "false". The reason for this is that when an instance element used by an item has no value specified for an option, that instance element refers to the master element for the value of that option. This allows items which are displaying a certain element to be redisplayed when the master element's options change. The benefits of this are that you don't need to configure the font or text color for every item in a treectrl individually, saving CPU cycles and memory. [para] You may be thinking that to change the color of a selection rectangle you would call [cmd {item element configure}] when an item was selected, but that is not usually the case. It would be wasteful to allocate a new instance element for a selection rectangle just because an item became selected. The solution is to allow the appearance of the selection rectangle master element to change based on the selected state of the item. This is described in [sectref {PER-STATE OPTIONS}]. [para] For each element type there is a section below describing the options which can modify an element of that type. [section {BITMAP ELEMENT}] An element of type [const bitmap] can be used to display a bitmap in an item. The following options are supported for bitmap elements: [list_begin options] [opt_def [option -background] [arg color]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the color to use for each of the bitmap's '0' valued pixels. If the value for a certain state is an empty string (the default), the bitmap is drawn transparent. [opt_def [option -bitmap] [arg bitmap]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the bitmap to display in the element. [opt_def [option -draw] [arg boolean]] Deprecated; use the style layout option [option -draw] instead. Specifies as a [sectref {PER-STATE OPTIONS} per-state] option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. [opt_def [option -foreground] [arg color]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the color to use for each of the bitmap's '1' valued pixels. If the value for a certain state is an empty string (the default), the bitmap's foreground color is black. [list_end] [section {BORDER ELEMENT}] An element of type [const border] can be used to display a 3D border in an item. The following options are supported for border elements: [list_begin options] [opt_def [option -background] [arg color]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the color to use for the background of the border. If the value for a certain state is an empty string (the default), the element will not be drawn. [opt_def [option -draw] [arg boolean]] Deprecated; use the style layout option [option -draw] instead. Specifies as a [sectref {PER-STATE OPTIONS} per-state] option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. [opt_def [option -filled] [arg boolean]] Specifies whether the interior of the border should be filled with the background color. If this option is unspecified (the default), it it treated as false which means that only the edges of the border will be drawn. [opt_def [option -height] [arg size]] Specifies the height of the border. If this value is unspecified (the default), the border will be exactly as tall as its display area as determined by the style layout options. [opt_def [option -relief] [arg relief]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the relief of the border. If the value for a certain state is an empty string (the default), it is treated as flat. For acceptable values see the description of the [option -relief] option in the [cmd options] manual page. [opt_def [option -thickness] [arg thickness]] Specifies the thickness of the edges of the border. [opt_def [option -width] [arg size]] Specifies the width of the border. If this value is unspecified (the default), the border will be exactly as wide as its display area as determined by the style layout options. [list_end] [section {HEADER ELEMENT}] An element of type [const header] can be used to display a themed (or non-themed) column header background and sort arrow. Header elements are best used surrounding other elements via the style layout option [option -union], so that the sort arrow can be displayed correctly. [para] Some of the options for this type of element get their default values from the [sectref STATES {header state}] flags that are set in the column header in which the element is displayed. In particular, the [option -arrow] option gets its default value by checking the [const up] and [const down] state flags, and the [option -state] option gets its default value by checking the [const active], [const normal], and [const pressed] state flags. If elements of this type are displayed in an item instead of a column header, then this behavior isn't used since those state flags aren't meaningful for items. [para] The following options are supported for header elements: [list_begin options] [opt_def [option -arrow] [arg direction]] Indicates whether or not a sort arrow should be drawn. [arg Direction] must have one of the values [const none], [const up], or [const down]. If unspecified, the value defaults to [const none] (but see the note above regarding header states). [opt_def [option -arrowbitmap] [arg bitmap]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the name of a bitmap to use to draw the sort arrow if this element's -arrow option is not [const none]. This option is ignored when drawing themed headers on Mac OS X. [opt_def [option -arrowgravity] [arg direction]] Indicates onto which side the sort arrow should be packed, if there is more space available for drawing the arrow than needed. [arg Direction] must be either [const left] or [const right]. If unspecified, the value defaults to [const left]. This option is ignored when drawing themed headers on Mac OS X. [opt_def [option -arrowimage] [arg image]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the name of an image to use to draw the sort arrow if this element's -arrow option is not [const none]. If an image is specified for a certain state, it overrides the -arrowbitmap option. This option is ignored when drawing themed headers on Mac OS X. [opt_def [option -arrowpadx] [arg amount]] [arg Amount] specifies how much padding to leave on the left and right of the sort arrow. [arg Amount] may be a list of two values to specify padding for the left and right separately. If unspecified, the value defaults to 6. Padding to the right of the sort arrow is ignored when drawing themed headers on Mac OS X. [opt_def [option -arrowpady] [arg amount]] [arg Amount] specifies how much padding to leave on the top and bottom of the sort arrow. [arg Amount] may be a list of two values to specify padding for the top and bottom separately. If unspecified, the value defaults to 0. This option is ignored when drawing themed headers on Mac OS X. [opt_def [option -arrowside] [arg side]] Indicates on which side of the element the sort arrow should be drawn. [arg Side] must be either [const left] or [const right]. If unspecified, the value defaults to [const right]. [opt_def [option -background] [arg color]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the color to use for the non-themed background and 3D border. If unspecified, the value defaults to either the Tk button widget's -background or -activebackground color. [opt_def [option -borderwidth] [arg size]] Specifies a non-negative value indicating the width of the non-themed 3D border to draw around the inner edges of the element (if such a border is being drawn; the [option -relief] option determines this). The value may have any of the forms acceptable to [fun Tk_GetPixels]. If unspecified, the value defaults to 2. [opt_def [option -state] [arg state]] Specifies one of three states for the element: [const normal], [const active], or [const pressed]. The active state is used when the mouse is over the header. The pressed state is used when the mouse button is pressed in the header. If unspecified, the value defaults to [const normal] (but see the note above regarding header states). [list_end] [section {IMAGE ELEMENT}] An element of type [const image] can be used to display an image in an item. The following options are supported for image elements: [list_begin options] [opt_def [option -draw] [arg boolean]] Deprecated; use the style layout option [option -draw] instead. Specifies as a [sectref {PER-STATE OPTIONS} per-state] option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. [opt_def [option -height] [arg size]] Specifies the requested height of the display area for this element. If unspecified (the default), the element requests a height equal to the height of the image, or zero if there is no image. [opt_def [option -image] [arg image]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the image to display in the element. [opt_def [option -tiled] [arg boolean]] Specifies a boolean indicating whether or not the image should be tiled horizontally and vertically within the display area for the element. The default is false. [opt_def [option -width] [arg size]] Specifies the requested width of the display area for this element. If unspecified (the default), the element requests a width equal to the width of the image, or zero if there is no image. [list_end] [section {RECTANGLE ELEMENT}] An element of type [const rect] can be used to display a rectangle in an item. The following options are supported for rectangle elements: [list_begin options] [opt_def [option -draw] [arg boolean]] Deprecated; use the style layout option [option -draw] instead. Specifies as a [sectref {PER-STATE OPTIONS} per-state] option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. [opt_def [option -fill] [arg color]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the color to be used to fill the rectangle's area. If the color for a certain state is an empty string (the default), then the rectangle will not be filled (but the outline may still be drawn). [opt_def [option -height] [arg size]] Specifies the height of the rectangle. If this value is unspecified (the default), the rectangle will be exactly as tall as its display area as determined by the style layout options. [opt_def [option -open] [arg open]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option which edges of the rectangle should be left open. This option may be used to get an incomplete drawing of the outline and rounded corners, often to give the appearance of the rectangle extending over adjacent columns or items. [arg Open] is a string that contains zero or more of the characters [const n], [const s], [const e] or [const w]. Each letter refers to an edge (north, south, east, or west) on which the outline and rounded corners will not be drawn. The default is the empty string, which causes all rounded corners and the outline to be drawn. [opt_def [option -outline] [arg color]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the color to be used to draw the outline of the rectangle. If the color for a certain state is an empty string (the default), then no outline is drawn for the rectangle. [opt_def [option -outlinewidth] [arg outlineWidth]] Specifies the width of the outline to be drawn around the rectangle's region. [arg outlineWidth] may be in any of the forms acceptable to [fun Tk_GetPixels]. If this option is specified as an empty string (the default), then no outline is drawn. [opt_def [option -rx] [arg radius]] [opt_def [option -ry] [arg radius]] Specifies the x and y radius of each corner of a rounded rectangle in any of the forms acceptable to [fun Tk_GetPixels]. [opt_def [option -showfocus] [arg boolean]] Specifies a boolean value indicating whether a "focus ring" should be drawn around the rectangle, if the item containing the rectangle is the active item and the treectrl widget currently has the focus. If this option is specified as an empty string (the default), then a focus rectangle is not drawn. [opt_def [option -width] [arg size]] Specifies the width of the rectangle. If this value is unspecified (the default), the rectangle will be exactly as wide as its display area as determined by the style layout options. [list_end] [section {TEXT ELEMENT}] An element of type [const text] can be used to display a text in an item. The following options are supported for text elements: [list_begin options] [opt_def [option -draw] [arg boolean]] Deprecated; use the style layout option [option -draw] instead. Specifies as a [sectref {PER-STATE OPTIONS} per-state] option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. [opt_def [option -data] [arg data]] Specifies a value that together with the [option -datatype] and [option -format] options will be displayed as text. [opt_def [option -datatype] [arg dataType]] Specifies the type of information in the [option -data] option. Acceptable values are [const double], [const integer], [const long], [const string], or [const time]. [opt_def [option -fill] [arg color]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the foreground color to use when displaying text. [para] In items, if the color for a certain state is an empty string (the default), then the text will be displayed using the color specified by the treectrl's [option -foreground] option. [para] In headers, if the color for a certain state is an empty string, then the text will be displayed using the system theme color on Gtk+; if that color is not specified then the [option -headerforeground] option is used. [opt_def [option -font] [arg font]] Specifies as a [sectref {PER-STATE OPTIONS} per-state] option the font to use when displaying the text. If the font for a certain state is an empty string, the text is displayed using the font specified by the treectrl's [option -font] option in items or the [option -headerfont] option in headers. [opt_def [option -format] [arg formatString]] This option specifies the format string used to display the value of the [option -data] option. If [option -datatype] is [const time], [arg formatString] should be a valid format string for the Tcl [cmd clock] command. For all other [option -datatype] values [arg formatString] should be a valid format string for the Tcl [cmd format] command. If this value is unspecified the following defaults are used: for -datatype double "%g", for -datatype integer "%d", for -datatype long "%ld", for -datatype string "%s", and for -datatype time the default format string of the Tcl [cmd clock] command. [opt_def [option -justify] [arg how]] Specifies how to justify the text when multiple lines are displayed. [arg How] must be one of the values [const left], [const right], or [const center]. If this option is specified as an empty string (the default), [const left] is used. [opt_def [option -lines] [arg lineCount]] Specifies the maximum number of lines to display. If more than [arg lineCount] lines would be displayed, the last line will be truncated with an ellipsis at the right. If this option is specified as zero or an empty string (the default), there is no limit to the number of lines displayed. [opt_def [option -lmargin1] [arg pixels]] [arg Pixels] is a screen distance that specifies how much a line of text should be indented. If a line of text wraps, this option only applies to the first line on the display; the [option -lmargin2] option controls the indentation for subsequent lines. If this option is specified as zero or an empty string (the default), then the line is not indented. This option was based on the Tk Text widget tag option of the same name. [opt_def [option -lmargin2] [arg pixels]] [arg Pixels] is a screen distance that specifies how much a line of text should be indented. If a line of text wraps, this option only applies to the second and later display lines for a line of text. If this option is specified as zero or an empty string (the default), then the line is not indented. This option was based on the Tk Text widget tag option of the same name. [opt_def [option -text] [arg string]] [arg String] specifies a string to be displayed by the element. [arg String] may contain newline characters in which case multiple lines of text will be displayed. If this option is specified, the [option -data], [option -datatype], [option -format], and [option -textvariable] options are ignored. [opt_def [option -textvariable] [arg varName]] Specifies the name of a variable. The value of the variable is a string to be displayed by the element; if the variable value changes then the element will automatically update itself to display the new value. If this option is specified, the [option -data], [option -datatype], and [option -format] options are ignored. [opt_def [option -underline] [arg charIndex]] Specifies the integer index of a character to underline. 0 corresponds to the first character. If [arg charIndex] is unspecified (the default), less than zero or greater than the index of the last displayed character, the underline is not drawn. [opt_def [option -width] [arg size]] Specifies the maximum line length in any of the forms acceptable to [fun Tk_GetPixels]. For text to wrap lines the value of the [option -width] option must be less than the needed width of the text, or the display area for this element must be less than the needed width of the text. For the display area to be less than the needed width of the text, one of the style layout options [option -maxwidth], [option -width] or [option -squeeze] must be used. [opt_def [option -wrap] [arg mode]] [arg Mode] specifies how to handle lines in the text that are longer than the maximum line length. Acceptable values are [const none], [const char] or [const word]. If this option is unspecified (the default), [const word] is used. See the [option -width] option for a description of how the maximum line length is determined. [list_end] [section {WINDOW ELEMENT}] An element of type [const window] can be used to display a Tk window in an item. The following options are supported for window elements: [list_begin options] [opt_def [option -clip] [arg boolean]] Specifies whether the associated Tk window is a borderless frame which should be used to clip its child window so it doesn't overlap the header, borders, or other items or columns. When this option is true, the treectrl manages the geometry of both the [option -window] widget and its first child widget; in this case the [option -window] widget (which should be a borderless frame) is kept sized and positioned so that it is never out-of-bounds. [opt_def [option -destroy] [arg boolean]] Specifies whether the associated Tk window should be destroyed when the element is deleted. The element is deleted when the item containing the element is deleted, when the column containing the element is deleted, or when the style assigned to the item's column is changed. If this option is unspecified (the default), it is treated as false and the Tk window will not be destroyed. [opt_def [option -draw] [arg boolean]] Deprecated; use the style layout option [option -draw] instead. Specifies as a [sectref {PER-STATE OPTIONS} per-state] option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. [opt_def [option -window] [arg pathName]] Specifies the window to associate with this element. The window specified by [arg pathName] must either be a child of the treectrl widget or a child of some ancestor of the treectrl widget. [arg PathName] may not refer to a top-level window. This option cannot be specified by the [cmd {element create}] or [cmd {element configure}] commands, only by the [cmd {item element configure}] command; i.e., the element must be associated with a particular item. [list_end] [section {ITEM DESCRIPTION}] Many of the commands for a treectrl take as an argument a description of which items to operate on. An item description is a properly-formed tcl list of keywords and arguments. The first word of an item description must be one of the following: [list_begin definitions] [def [arg id]] Specifies the unique item identifier, where [arg id] should be the return value of a prior call of the [cmd {item create}] widget command, or [const 0] to specify the ever-present root item. See also the [option -itemprefix] option. [def [arg QUALIFIERS]] Specifies a list of qualifiers. This gives the same result as [const all] followed by [arg QUALIFIERS]; i.e., every item is tested for a match. [def "[arg tagExpr] [arg QUALIFIERS]"] [arg TagExpr] is a tag expression (see [sectref {ITEM AND COLUMN TAGS}]) against which every item's tags are tested for a match. This keyword cannot be followed by any modifiers unless a single item is matched. You may run into trouble if [arg tagExpr] looks like an item id or other keyword; also, [arg tagExpr] must look like a single list element since item descriptions are properly-formed lists. To be safe you may want to use the [const tag] qualifier followed by [arg tagExpr]. [def [const active]] Indicates the item that is currently active, i.e. normally the item specified as argument of the last successful [cmd activate] widget command, or the root item if no such call happened yet. [def [const anchor]] Indicates the anchor item of the selection, i.e. normally the item specified as argument of the last successful [cmd {selection anchor}] widget command, or the root item if no such call happened yet. [def "[const all] [arg QUALIFIERS]"] Indicates every item including orphans which match [arg QUALIFIERS]. This keyword cannot be followed by any modifiers unless a single item is matched. [def "[const first] [arg QUALIFIERS]"] Indicates the first item of the treectrl (the root item), or the first item matching [arg QUALIFIERS]. [def "[const end] [arg QUALIFIERS]"] [def "[const last] [arg QUALIFIERS]"] Indicates the last item which matches [arg QUALIFIERS]. [def "[const list] [arg itemDescs]"] [arg ItemDescs] is a list (a single argument, i.e. "list {a b c}" not "list a b c") of other item descriptions. This keyword cannot be followed by any modifiers unless a single item is matched. [def "[const nearest] [arg {x y}]"] Indicates the item nearest to the point given by [arg x] and [arg y]. [def "[const rnc] [arg {row column}]"] Indicates the item in the given [arg row] and [arg column]. The row and column corresponds to the on-screen arrangement of items as determined by the -orient and -wrap options. You can memorize [const rnc] as an abbreviation of "row 'n' column". [def "[const range] [arg {first last}] [arg QUALIFIERS]"] [arg First] and [arg last] specify a range of items. This keyword cannot be followed by any modifiers unless a single item is matched. [def [const root]] Indicates the root item of the treectrl. [list_end] [para] The initial part of the item description (matching any of the values above) may be followed by one or more [arg modifier]s. A modifier changes the item used relative to the description up to this point. It may be specified in any of the following forms: [list_begin definitions] [def [const above]] Use the item one row above in this column. [def "[const ancestors] [arg QUALIFIERS]"] Use the ancestors of the item (like [cmd {item ancestors}] but QUALIFIERS may change which ancestors match). This keyword cannot be followed by any modifiers. [def [const below]] Use the item one row below in this column. [def [const bottom]] Use the item in the last row of this column. [def "[const child] [arg n] [arg QUALIFIERS]"] Use the [arg n]th child of the item. [def "[const children] [arg QUALIFIERS]"] Use the children of the item (like [cmd {item children}] but QUALIFIERS may change which children match). This keyword cannot be followed by any modifiers. [def "[const descendants] [arg QUALIFIERS]"] Use the descendants of the item (like [cmd {item descendants}] but QUALIFIERS may change which descendants match). This keyword cannot be followed by any modifiers. [def "[const firstchild] [arg QUALIFIERS]"] Use the first child of the item. [def "[const lastchild] [arg QUALIFIERS]"] Use the last child of the item. [def [const left]] Use the item one column to the left in the same row. [def [const leftmost]] Use the item of the first column in the same row. [def "[const next] [arg QUALIFIERS]"] Use the next item, which is the first item from the following list: the first child, the next sibling or the next sibling of the nearest ancestor which has one. [def "[const nextsibling] [arg QUALIFIERS]"] Use the next sibling of the item. [def [const parent]] Use the parent of the item. [def "[const prev] [arg QUALIFIERS]"] Use the last child of the previous sibling, or the parent if there is no previous sibling. [def "[const prevsibling] [arg QUALIFIERS]"] Use the previous sibling of the item. [def [const right]] Use the item one column to the right in the same row. [def [const rightmost]] Use the item of the last column in the same row. [def "[const sibling] [arg n] [arg QUALIFIERS]"] Use the [arg n]th child of the item's parent. [def [const top]] Use the item in the first row of this column. [list_end] The word [arg QUALIFIERS] above represents a series of zero or more of the following terms that changes which item is chosen: [list_begin definitions] [def "[const depth] [arg depth]"] Matches items whose depth (as returned by the [cmd depth] command) is equal to [arg depth]. [def "[const state] [arg stateList]"] [arg StateList] is a list of item state names (static and dynamic, see [sectref STATES]). Only items that have the given states set (or unset if the '!' prefix is used) are considered. [def "[const tag] [arg tagExpr]"] [arg TagExpr] is a tag expression (see [sectref {ITEM AND COLUMN TAGS}]) against which an item's tags are tested for a match. [def [const visible]] When this qualifier is given, only items that are displayed are considered. [def [const !visible]] When this qualifier is given, only items that are *not* displayed are considered. [list_end] To get the first item in the list that is enabled: [example_begin] $T item id "first state enabled" [example_end] To get the ancestors that are not open of the last item in the list: [example_begin] $T item id "last ancestors state !open" [example_end] To get the visible descendants of the root item: [example_begin] $T item id "root descendants visible" [example_end] To get the every hidden item with tag "a" or "b": [example_begin] $T item id "all !visible tag a||b" $T item id "!visible tag a||b" $T item id "tag a||b !visible" $T item id "a||b !visible" [example_end] [section {EVENTS AND SCRIPT SUBSTITUTIONS}] The [arg script] argument to [cmd {notify bind}] is a Tcl script, which will be evaluated whenever the given event is generated. [arg Script] will be executed in the same interpreter that the [cmd {notify bind}] command was executed in, and it will run at global level (only global variables will be accessible). If [arg script] contains any [const %] characters, then the script will not be evaluated directly. Instead, a new script will be generated by replacing each [const %], and the character following it, with information from the current event. Unlike the regular Tk [cmd bind] mechanism, each event generated by a treectrl widget has its own set of %-substitutions. [para] The following %-substitutions are valid for all static events: [list_begin options] [opt_def %%] Replaced with a single % [opt_def %d] The detail name [opt_def %e] The event name [opt_def %P] The pattern, either or [opt_def %W] The object argument to the [cmd "notify bind"] command [opt_def %T] The treectrl widget which generated the event [opt_def %?] A list of the format {char value char value ...} for each %-substitution character and the value it is replaced by [list_end] [para] The following events may be generated by a treectrl widget: [list_begin definitions] [def [const ]] Generated whenever the active item changes. [list_begin options] [opt_def %c] The current active item [opt_def %p] The previous active item [list_end] [def [const ]] Generated before an item is collapsed. [list_begin options] [opt_def %I] The item id [list_end] [def [const ]] Generated after an item is collapsed. [list_begin options] [opt_def %I] The item id [list_end] [def [const ]] Generated before an item is expanded. This event is useful if you want to add child items to the item just before the item is expanded. [list_begin options] [opt_def %I] The item id [list_end] [def [const ]] Generated after an item is expanded. [list_begin options] [opt_def %I] The item id [list_end] [def [const ]] Generated when items are about to be deleted by the [cmd {item delete}] command. [list_begin options] [opt_def %i] List of items ids being deleted. [list_end] [def [const ]] Generated when items become visible on screen and when items are no longer visible on screen. This event is useful if you have a very large number of items and want to assign styles only when items are actually going to be displayed. [list_begin options] [opt_def %h] List of items ids which are no longer visible. [opt_def %v] List of items ids which are now visible. [list_end] [def [const ]] Generated whenever the view in the treectrl changes in such a way that a horizontal scrollbar should be redisplayed. [list_begin options] [opt_def %l] Same as the first fraction appended to [const -xscrollcommand]. Think [emph lower]. [opt_def %u] Same as the second fraction appended to [const -xscrollcommand]. Think [emph upper]. [list_end] [def [const ]] Generated whenever the view in the treectrl changes in such a way that a vertical scrollbar should be redisplayed. [list_begin options] [opt_def %l] Same as the first fraction appended to [const -yscrollcommand]. Think [emph lower]. [opt_def %u] Same as the second fraction appended to [const -yscrollcommand]. Think [emph upper]. [list_end] [def [const ]] Generated whenever the selection changes. This event gives information about how the selection changed. [list_begin options] [opt_def %c] Same as the [cmd "selection count"] widget command [opt_def %D] List of newly-deselected item ids [opt_def %S] List of newly-selected item ids [list_end] [list_end] [section {DYNAMIC EVENTS}] In addition to the pre-defined static events such as and , new dynamic events can be created by using the [cmd {notify install}] command. [para] The library scripts provide an example of using a dynamic event called , which is generated when the mouse button is clicked and released over a column header. [example_begin] # Example application code treectrl .t .t notify install .t notify bind MyTag { puts "column header %C clicked in header-row %H in treectrl %T" } # Library code in treectrl.tcl proc ::TreeCtrl::Release1 {w x y} { ... $w notify generate [lb]list H $Priv(header) C $Priv(column)[rb] \ [lb]list ::TreeCtrl::PercentsCmd $w[rb] ... } [example_end] In the example above, a new treectrl widget is created and the event is installed. A script is bound to the event with [cmd {notify bind}] which will print out the column ID, header ID and widget name to the console. In a real application, any script bound to would be used to sort the list based on the column header that was clicked. [para] Note there is no [arg percentsCommand] argument to [cmd {notify install}]; instead, the call to [cmd {notify generate}] specifies the %-substitution command. The [arg charMap] argument to [cmd {notify generate}] provides a list of %-substitution characters and values which is used by ::TreeCtrl::PercentsCmd. In the example, any %C in any script bound to the event would be replaced by the value of $Priv(column), and %H would be replaced by $Priv(header). The library procedure ::TreeCtrl::PercentsCmd also supports the same common %-substitution characters as the built-in static events, such as %T, %P, %? etc. [para] The following dynamic events may be generated by the library scripts: [list_begin definitions] [def [const ]] This event is generated just after the user begins dragging a column header. At the time this event is generated, the [cmd {header dragconfigure}] option [option -imagecolumn] is set to the unique ID of the column being dragged, the [option -imageoffset] option is set to the horizontal distance the mouse pointer has moved, and the [option -imagespan] option is set to the span of the column header that was initially clicked. [def [const ]] This event is generated each time a new place to drop the dragged column header is found. At the time this event is generated, the [cmd {header dragconfigure}] option [option -indicatorcolumn] is set to the unique ID of the column before or after which the dragged column will be dropped, and the [option -indicatorspan] option is set to the span of the column header for this newly-chosen indicator column. [def [const ]] This event is generated when the user has successfully dragged and dropped a column header to a new position. The library scripts do not actually move the dragged column. You must bind a script to this event to move the column. See [sectref EXAMPLES]. [def [const ]] This event is generated after the user finally releases the left mouse button while dragging a column header. This event is generated after all the other events even when the column wasn't dragged to a new location (i.e., even when no [const ] event was generated). [list_begin options] [opt_def %H] The [sectref HEADERS header-row] that contains the column header. [opt_def %C] The column whose header is dragged within the header-row. [opt_def %b] The column to move the dragged column(s) before. Valid for [const ] only. [list_end] [def [const ]] [def [const ]] [def [const ]] Generated whenever the user drag-and-drops a file into a directory. This event is generated by the filelist-bindings.tcl library code, which is not used by default. See the "Explorer" demos. [list_begin options] [opt_def %I] The item that the user dropped the dragged items on. [opt_def %l] (lowercase L) The list of dragged items. [list_end] [def [const ]] [def [const ]] [def [const ]] The filelist-bindings.tcl code will display a text-editing window if the user clicks on a selected file/folder name. See the "Explorer" demos. [list_begin options] [opt_def %I] The item containing the edited text element. [opt_def %C] The column containing the edited text element. [opt_def %E] The name of the edited text element. [opt_def %t] The edited text. [list_end] [def [const ]] Generated whenever the user clicks and releases the left mouse button in a column header if the column header's -button option is true. You can bind a script to this event to sort the list. [list_begin options] [opt_def %H] The [sectref HEADERS header-row] that contains the column header. [opt_def %C] The column whose header was clicked. [list_end] [def [const ]] Generated when the column header option [option -state] is changed by the library scripts during Motion and Button events. [list_begin options] [opt_def %H] The [sectref HEADERS header-row] that displays the column header. [opt_def %C] The column within the header-row whose header option [option -state] changed. [opt_def %s] The new value of the column header option [option -state]. [list_end] [list_end] [section {DEFAULT BINDINGS}] Tk automatically creates class bindings for treectrl widgets that give them the following default behavior. [list_begin enum] [enum] Clicking mouse button 1 over an item positions the active cursor on the item, sets the input focus to this widget, and resets the selection of the widget to this item, if it is not already in the selection. [enum] Clicking mouse button 1 with the Control key down will reposition the active cursor and add the item to the selection without ever removing any items from the selection. [enum] If the mouse is dragged out of the widget while button 1 is pressed, the treectrl will automatically scroll to make more items visible (if there are more items off-screen on the side where the mouse left the window). [enum] The Left and Right keys move the active cursor one item to the left or right; for an hierarchical tree with vertical orientation nothing will happen, since it has no two items in the same row. The selection is set to include only the active item. If Left or Right is typed with the Shift key down, then the active cursor moves and the selection is extended to include the new item. [enum] The Up and Down keys move the active cursor one item up or down. The selection is set to include only the active item. If Up or Down is typed with the Shift key down, then the active cursor moves and the selection is extended to include the new item. [enum] The Next and Prior keys move the active cursor forward or backwards by one screenful, without affecting the selection. [enum] Control-Next and Control-Prior scroll the view right or left by one page without moving the active cursor or affecting the selection. Control-Left and Control-Right behave the same. [enum] The Home and End keys scroll to the left or right end of the widget without moving the active cursor or affecting the selection. [enum] The Control-Home and Control-End keys scroll to the top or bottom of the widget, they also activate and select the first or last item. If also the Shift key is down, then the active cursor moves and the selection is extended to include the new item. [enum] The Space and Select keys set the selection to the active item. [enum] Control-/ selects the entire contents of the widget. [enum] Control-\\ clears any selection in the widget. [enum] The + and - keys expand or collapse the active item, the Return key toggles the active item. [enum] The mousewheel scrolls the view of the widget four lines up or down depending on the direction, the wheel was turned. The active cursor or the selection is not affected. [list_end] [section GRADIENTS] Color gradients are an easy way to give your lists a more modern appearance. Since Tk provides no support for drawing gradients, the TkPath extension was used as a guide when implementing gradients in TkTreeCtrl. The current implementation has some limitations, however: [list_begin enum] [enum] Only linear gradients are supported. [enum] Gradients can only be painted left-to-right or top-to-bottom, not at arbitrary angles. [enum] Gradients look bad on low-color displays. Before using gradients, you should check that the display's color depth is at least 15 or 16 by calling the [cmd "winfo depth"] command. [enum] Gradients are fully opaque when XFillRectangle() is used to draw them (see below). This means the [option opacity] value of each color stop is ignored. Keep that in mind if your application is cross-platform. [enum] Rounded rectangles cannot be filled or outlined with a gradient when XFillRectangle() is used to draw gradients (see below). Instead, the rounded rectangle is painted with the gradient's first [option -stops] color. [list_end] Gradients may be used in the following places: [list_begin enum] [enum] The -gridleftcolor and -gridrightcolor options of columns. [enum] The -itembackground option of columns. [enum] The -fill and -outline options of rect elements. [enum] The -fill and -outline options of the [cmd "marquee configure"] command. [list_end] [para] On Microsoft Windows, GDI+ is used where it is available (gdiplus.dll is dynamically loaded at run-time). On Mac OS X, CoreGraphics is used to draw gradients. With the Gtk+ build of treectrl, libcairo is used to draw gradients. When native gradient support is available, all the talk below about [option -steps] can safely be ignored. [para] When no native support for gradients is available, gradients are drawn simply by filling sub-rectangles using XFillRectangle(). The number of sub-rectangles drawn and number of colors that make up the displayed gradient are controlled by the gradient's [option -steps] and [option -stops] options. The number of sub-rectangles is equal to the length of the [option -stops] option multiplied by the value of the [option -steps] option. For example: [example_begin] $T gradient create myGradient -stops {{0 white} {1 gray}} -steps 8 [example_end] This gradient will be drawn with 2x8=16 sub-rectangles of color. The higher the [option -steps] value, the smoother the color transitions will be, and the slower the gradient will be to draw. For the best appearance, make the number of sub-rectangles drawn less than or equal to the height or width of the gradient being drawn. So if you have a rect element 18 pixels tall, use a vertical gradient that has steps X stops=18. Avoid using gradients with steps X stops greater than the height or width of the rectangle being drawn, because then colors will overlap. [section {GRADIENT COORDINATES}] By default, a gradient brush is exactly the same size as whatever rectangle is being painted. For example, if a column's [option -itembackground] option specifies a gradient name, then the background of an item is painted with all the colors of the gradient. So a vertical gradient from blue to green will start blue at the top and end with green at the bottom of every item. [para] By specifying any of the [option -bottom], [option -left], [option -right] or [option -top] gradient options the size of the gradient brush does not need to match that of the rectangle being painted. These options can be used to make a gradient appear to span across the entire width or height of the treectrl window, or across the entire [sectref {THE CANVAS} {canvas}], for example. [para] There is no point specifying [option -left] or [option -right] if the gradient is vertical, since the gradient's colors are constant horizontally, so changing the horizontal size of the brush won't change the appearance of the gradient. The same reasoning applies for the [option -top] and [option -bottom] options for a horizontal gradient. [para] [example_begin] package require treectrl set T [lb]treectrl .t -itemheight 20 -showheader no[rb] $T gradient create G1 -orient vertical -top {0.0 canvas} -bottom {1.0 canvas} \ -stops {{0.0 blue} {0.5 green} {1.0 red}} -steps 25 $T column create -expand yes -itembackground G1 pack $T -expand yes -fill both [example_end] [section EXAMPLES] Get the unique identifier for the leftmost visible column: [example_begin] set id [lb]$T column index "first visible"[rb] [example_end] Delete the leftmost column: [example_begin] $T column delete "order 0" [example_end] Take the visible column that is to the left of the last column, and move that column in front of the tail column: [example_begin] $T column move "last prev visible" tail [example_end] Get the unique identifier for the first visible item: [example_begin] set id [lb]$T item index "first visible"[rb] [example_end] Delete the parent of the item that is under the point x,y: [example_begin] $T item delete "nearest $x $y parent" [example_end] Add the 10th child of the second child of the root item to the selection: [example_begin] $T selection add "root firstchild nextsibling child 10" [example_end] Move a column that the user drag-and-dropped: [example_begin] $T header dragconfigure -enable yes $T notify install $T notify bind MyTag { %T column move %C %b } [example_end] [see_also listbox(n) image(n) bitmap(n) bind(n) options(n)] [keywords tree widget] [manpage_end] tktreectrl-2.4.1/doc/treectrl.n0000644000076400010400000070066111646360507017005 0ustar TimAdministrators'\" '\" Generated from file 'doc/treectrl.man' by tcllib/doctools with format 'nroff' '\" '\" The definitions below are for supplemental macros used in Tcl/Tk '\" manual entries. '\" '\" .AP type name in/out ?indent? '\" Start paragraph describing an argument to a library procedure. '\" type is type of argument (int, etc.), in/out is either "in", "out", '\" or "in/out" to describe whether procedure reads or modifies arg, '\" and indent is equivalent to second arg of .IP (shouldn't ever be '\" needed; use .AS below instead) '\" '\" .AS ?type? ?name? '\" Give maximum sizes of arguments for setting tab stops. Type and '\" name are examples of largest possible arguments that will be passed '\" to .AP later. If args are omitted, default tab stops are used. '\" '\" .BS '\" Start box enclosure. From here until next .BE, everything will be '\" enclosed in one large box. '\" '\" .BE '\" End of box enclosure. '\" '\" .CS '\" Begin code excerpt. '\" '\" .CE '\" End code excerpt. '\" '\" .VS ?version? ?br? '\" Begin vertical sidebar, for use in marking newly-changed parts '\" of man pages. The first argument is ignored and used for recording '\" the version when the .VS was added, so that the sidebars can be '\" found and removed when they reach a certain age. If another argument '\" is present, then a line break is forced before starting the sidebar. '\" '\" .VE '\" End of vertical sidebar. '\" '\" .DS '\" Begin an indented unfilled display. '\" '\" .DE '\" End of indented unfilled display. '\" '\" .SO '\" Start of list of standard options for a Tk widget. The '\" options follow on successive lines, in four columns separated '\" by tabs. '\" '\" .SE '\" End of list of standard options for a Tk widget. '\" '\" .OP cmdName dbName dbClass '\" Start of description of a specific option. cmdName gives the '\" option's name as specified in the class command, dbName gives '\" the option's name in the option database, and dbClass gives '\" the option's class in the option database. '\" '\" .UL arg1 arg2 '\" Print arg1 underlined, then print arg2 normally. '\" '\" RCS: @(#) $Id: man.macros,v 1.1 2009/01/30 04:56:47 andreas_kupries Exp $ '\" '\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b '\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. '\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out '\" # BS - start boxed text '\" # ^y = starting y location '\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. '\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. '\" # VS - start vertical sidebar '\" # ^Y = starting y location '\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. '\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. '\" # Special macro to handle page bottom: finish off current '\" # box/sidebar if in box/sidebar mode, then invoked standard '\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. '\" # DS - begin display .de DS .RS .nf .sp .. '\" # DE - end display .de DE .fi .RE .sp .. '\" # SO - start of list of standard options .de SO .SH "STANDARD OPTIONS" .LP .nf .ta 4c 8c 12c .ft B .. '\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\fBoptions\\fR manual entry for details on the standard options. .. '\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. '\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. '\" # CE - end code excerpt .de CE .fi .RE .. .de UL \\$1\l'|0\(ul'\\$2 .. .TH "treectrl" n 2.4.1 treectrl "Tk Commands" .BS .SH NAME treectrl \- Create and manipulate hierarchical multicolumn widgets .SH SYNOPSIS package require \fBtreectrl 2.4.1\fR .sp \fBtreectrl\fR \fIpathName\fR ?\fIoptions\fR? .sp \fIpathName\fR \fBactivate\fR \fIitemDesc\fR .sp \fIpathName\fR \fBbbox\fR ?\fIarea\fR? .sp \fIpathName\fR \fBcanvasx\fR \fIwindowx\fR .sp \fIpathName\fR \fBcanvasy\fR \fIwindowy\fR .sp \fIpathName\fR \fBcget\fR \fIoption\fR .sp \fIpathName\fR \fBcollapse\fR ?\fB-recurse\fR? ?\fIitemDesc ...\fR? .sp \fIpathName\fR \fBcolumn\fR \fIoption\fR \fIcolumn\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBcolumn bbox\fR \fIcolumnDesc\fR .sp \fIpathName\fR \fBcolumn cget\fR \fIcolumnDesc\fR \fIoption\fR .sp \fIpathName\fR \fBcolumn configure\fR \fIcolumnDesc\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBcolumn compare\fR \fIcolumn1\fR \fIop\fR \fIcolumn2\fR .sp \fIpathName\fR \fBcolumn count\fR ?\fIcolumnDesc\fR? .sp \fIpathName\fR \fBcolumn create\fR ?\fIoption value ...\fR? .sp \fIpathName\fR \fBcolumn delete\fR \fIfirst\fR ?\fIlast\fR? .sp \fIpathName\fR \fBcolumn dragcget\fR \fIoption\fR .sp \fIpathName\fR \fBcolumn dragconfigure\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBcolumn index\fR \fIcolumnDesc\fR .sp \fIpathName\fR \fBcolumn id\fR \fIcolumnDesc\fR .sp \fIpathName\fR \fBcolumn list\fR ?\fI-visible\fR? .sp \fIpathName\fR \fBcolumn move\fR \fIcolumnDesc\fR \fIbeforeDesc\fR .sp \fIpathName\fR \fBcolumn neededwidth\fR \fIcolumnDesc\fR .sp \fIpathName\fR \fBcolumn order\fR \fIcolumnDesc\fR ?\fI-visible\fR? .sp \fIpathName\fR \fBcolumn tag\fR \fIoption\fR ?\fIarg arg ...\fR? .sp \fIpathName\fR \fBcolumn tag add\fR \fIcolumnDesc\fR \fItagList\fR .sp \fIpathName\fR \fBcolumn tag expr\fR \fIcolumnDesc\fR \fItagExpr\fR .sp \fIpathName\fR \fBcolumn tag names\fR \fIcolumnDesc\fR .sp \fIpathName\fR \fBcolumn tag remove\fR \fIcolumnDesc\fR \fItagList\fR .sp \fIpathName\fR \fBcolumn width\fR \fIcolumnDesc\fR .sp \fIpathName\fR \fBcompare\fR \fIitemDesc1\fR \fIop\fR \fIitemDesc2\fR .sp \fIpathName\fR \fBconfigure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? .sp \fIpathName\fR \fBcontentbox\fR .sp \fIpathName\fR \fBdebug\fR \fIoption\fR ?\fIarg arg ...\fR? .sp \fIpathName\fR \fBdebug alloc\fR .sp \fIpathName\fR \fBdebug cget\fR \fIoption\fR .sp \fIpathName\fR \fBdebug configure\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBdebug dinfo\fR \fIoption\fR .sp \fIpathName\fR \fBdebug expose\fR \fIx1\fR \fIy1\fR \fIx2\fR \fIy2\fR .sp \fIpathName\fR \fBdepth\fR ?\fIitemDesc\fR? .sp \fIpathName\fR \fBdragimage\fR \fIoption\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBdragimage add\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fIelement\fR? .sp \fIpathName\fR \fBdragimage cget\fR \fIoption\fR .sp \fIpathName\fR \fBdragimage clear\fR .sp \fIpathName\fR \fBdragimage configure\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBdragimage offset\fR ?\fIx y\fR? .sp \fIpathName\fR \fBelement\fR \fIoption\fR ?\fIelement\fR? ?\fIarg arg ...\fR? .sp \fIpathName\fR \fBelement cget\fR \fIelement\fR \fIoption\fR .sp \fIpathName\fR \fBelement configure\fR \fIelement\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBelement create\fR \fIname\fR \fItype\fR ?\fIoption value ...\fR? .sp \fIpathName\fR \fBelement delete\fR ?\fIelement ...\fR? .sp \fIpathName\fR \fBelement names\fR .sp \fIpathName\fR \fBelement perstate\fR \fIelement\fR \fIoption\fR \fIstateList\fR .sp \fIpathName\fR \fBelement type\fR \fIelement\fR .sp \fIpathName\fR \fBexpand\fR ?\fB-recurse\fR? ?\fIitemDesc ...\fR? .sp \fIpathName\fR \fBgradient\fR \fIoption\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBgradient cget\fR \fIgradient\fR \fIoption\fR .sp \fIpathName\fR \fBgradient configure\fR \fIgradient\fR ?\fIoption value ...\fR? .sp \fIpathName\fR \fBgradient create\fR \fIname\fR ?\fIoption value ...\fR? .sp \fIpathName\fR \fBgradient delete\fR ?\fIname ...\fR? .sp \fIpathName\fR \fBgradient names\fR .sp \fIpathName\fR \fBgradient native\fR ?\fIpreference\fR? .sp \fIpathName\fR \fBheader\fR \fIoption\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBheader bbox\fR \fIheaderDesc\fR ?\fIcolumn\fR? ?\fIelement\fR? .sp \fIpathName\fR \fBheader compare\fR \fIheaderDesc1\fR \fIop\fR \fIheaderDesc2\fR .sp \fIpathName\fR \fBheader configure\fR \fIheaderDesc\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBheader count\fR ?\fIheaderDesc\fR? .sp \fIpathName\fR \fBheader create\fR ?\fIoption value\fR? .sp \fIpathName\fR \fBheader delete\fR \fIheaderDesc\fR .sp \fIpathName\fR \fBheader dragcget\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBheader dragconfigure\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBheader element\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBheader id\fR \fIheaderDesc\fR .sp \fIpathName\fR \fBheader image\fR \fIheaderDesc\fR ?\fIcolumn\fR? ?\fIimage\fR? ?\fIcolumn image ...\fR? .sp \fIpathName\fR \fBheader span\fR \fIheaderDesc\fR ?\fIcolumn\fR? ?\fInumColumns\fR? ?\fIcolumn numColumns ...\fR? .sp \fIpathName\fR \fBheader state\fR \fIcommand\fR \fIheaderDesc\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBheader style\fR \fIcommand\fR \fIheaderDesc\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBheader text\fR \fIheaderDesc\fR ?\fIcolumn\fR? ?\fItext\fR? ?\fIcolumn text ...\fR? .sp \fIpathName\fR \fBheader tag\fR \fIcommand\fR \fIheaderDesc\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBidentify\fR ?\fI-array varName\fR? \fIx\fR \fIy\fR .sp \fIpathName\fR \fBindex\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem\fR \fIoption\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBitem ancestors\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem bbox\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fIelement\fR? .sp \fIpathName\fR \fBitem buttonstate\fR \fIitemDesc\fR ?\fIstate\fR? .sp \fIpathName\fR \fBitem cget\fR \fIitemDesc\fR \fIoption\fR .sp \fIpathName\fR \fBitem children\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem collapse\fR \fIitemDesc\fR ?\fB-animate\fR? ?\fB-recurse\fR? .sp \fIpathName\fR \fBitem compare\fR \fIitemDesc1\fR \fIop\fR \fIitemDesc2\fR .sp \fIpathName\fR \fBitem complex\fR \fIitemDesc\fR ?\fIlist...\fR? .sp \fIpathName\fR \fBitem configure\fR \fIitemDesc\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBitem count\fR ?\fIitemDesc\fR? .sp \fIpathName\fR \fBitem create\fR ?\fIoption value ...\fR? .sp \fIpathName\fR \fBitem delete\fR \fIfirst\fR ?\fIlast\fR? .sp \fIpathName\fR \fBitem descendants\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem dump\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem element\fR \fIcommand\fR \fIitemDesc\fR \fIcolumn\fR \fIelement\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBitem element actual\fR \fIitemDesc\fR \fIcolumn\fR \fIelement\fR \fIoption\fR .sp \fIpathName\fR \fBitem element cget\fR \fIitemDesc\fR \fIcolumn\fR \fIelement\fR \fIoption\fR .sp \fIpathName\fR \fBitem element configure\fR \fIitemDesc\fR \fIcolumn\fR \fIelement\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBitem element perstate\fR \fIitemDesc\fR \fIcolumn\fR \fIelement\fR \fIoption\fR ?\fIstateList\fR? .sp \fIpathName\fR \fBitem enabled\fR \fIitemDesc\fR ?\fIboolean\fR? .sp \fIpathName\fR \fBitem expand\fR \fIitemDesc\fR ?\fB-animate\fR? ?\fB-recurse\fR? .sp \fIpathName\fR \fBitem firstchild\fR \fIparent\fR ?\fIchild\fR? .sp \fIpathName\fR \fBitem id\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem image\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fIimage\fR? ?\fIcolumn image ...\fR? .sp \fIpathName\fR \fBitem isancestor\fR \fIitemDesc\fR \fIdescendant\fR .sp \fIpathName\fR \fBitem isopen\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem lastchild\fR \fIparent\fR ?\fIchild\fR? .sp \fIpathName\fR \fBitem nextsibling\fR \fIsibling\fR ?\fInext\fR? .sp \fIpathName\fR \fBitem numchildren\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem order\fR \fIitemDesc\fR ?\fI-visible\fR? .sp \fIpathName\fR \fBitem parent\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem prevsibling\fR \fIsibling\fR ?\fIprev\fR? .sp \fIpathName\fR \fBitem range\fR \fIfirst\fR \fIlast\fR .sp \fIpathName\fR \fBitem remove\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem rnc\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem sort\fR \fIitemDesc\fR ?\fIoption ...\fR? .sp \fIpathName\fR \fBitem span\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fInumColumns\fR? ?\fIcolumn numColumns ...\fR? .sp \fIpathName\fR \fBitem state\fR \fIcommand\fR \fIitemDesc\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBitem state define\fR \fIstateName\fR .sp \fIpathName\fR \fBitem state forcolumn\fR \fIitemDesc\fR \fIcolumn\fR ?\fIstateDescList\fR? .sp \fIpathName\fR \fBitem state get\fR \fIitemDesc\fR ?\fIstateName\fR? .sp \fIpathName\fR \fBitem state linkage\fR \fIstateName\fR .sp \fIpathName\fR \fBitem state names\fR .sp \fIpathName\fR \fBitem state set\fR \fIitemDesc\fR ?\fIlastItem\fR? \fIstateDescList\fR .sp \fIpathName\fR \fBitem state undefine\fR ?\fIstateName ...\fR? .sp \fIpathName\fR \fBitem style\fR \fIcommand\fR \fIitemDesc\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBitem style elements\fR \fIitemDesc\fR \fIcolumn\fR .sp \fIpathName\fR \fBitem style map\fR \fIitemDesc\fR \fIcolumn\fR \fIstyle\fR \fImap\fR .sp \fIpathName\fR \fBitem style set\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fIstyle\fR? ?\fIcolumn style ...\fR? .sp \fIpathName\fR \fBitem tag\fR \fIoption\fR ?\fIarg arg ...\fR? .sp \fIpathName\fR \fBitem tag add\fR \fIitemDesc\fR \fItagList\fR .sp \fIpathName\fR \fBitem tag expr\fR \fIitemDesc\fR \fItagExpr\fR .sp \fIpathName\fR \fBitem tag names\fR \fIitemDesc\fR .sp \fIpathName\fR \fBitem tag remove\fR \fIitemDesc\fR \fItagList\fR .sp \fIpathName\fR \fBitem text\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fItext\fR? ?\fIcolumn text ...\fR? .sp \fIpathName\fR \fBitem toggle\fR \fIitemDesc\fR ?\fB-animate\fR? ?\fB-recurse\fR? .sp \fIpathName\fR \fBmarquee\fR \fIoption\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBmarquee anchor\fR ?\fIx y\fR? .sp \fIpathName\fR \fBmarquee cget\fR \fIoption\fR .sp \fIpathName\fR \fBmarquee configure\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBmarquee coords\fR ?\fIx1 y1 x2 y2\fR? .sp \fIpathName\fR \fBmarquee corner\fR ?\fIx y\fR? .sp \fIpathName\fR \fBmarquee identify\fR .sp \fIpathName\fR \fBnotify\fR \fIoption\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBnotify bind\fR ?\fIobject\fR? ?\fIpattern\fR? ?+??\fIscript\fR? .sp \fIpathName\fR \fBnotify configure\fR \fIobject\fR \fIpattern\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBnotify detailnames\fR \fIeventName\fR .sp \fIpathName\fR \fBnotify eventnames\fR .sp \fIpathName\fR \fBnotify generate\fR \fIpattern\fR ?\fIcharMap\fR? ?\fIpercentsCommand\fR? .sp \fIpathName\fR \fBnotify install\fR \fIpattern\fR ?\fIpercentsCommand\fR? .sp \fIpathName\fR \fBnotify install detail\fR \fIeventName\fR \fIdetail\fR ?\fIpercentsCommand\fR? .sp \fIpathName\fR \fBnotify install event\fR \fIeventName\fR ?\fIpercentsCommand\fR? .sp \fIpathName\fR \fBnotify linkage\fR \fIpattern\fR .sp \fIpathName\fR \fBnotify linkage\fR \fIeventName\fR ?\fIdetail\fR? .sp \fIpathName\fR \fBnotify unbind\fR \fIobject\fR ?\fIpattern\fR? .sp \fIpathName\fR \fBnotify uninstall\fR \fIpattern\fR .sp \fIpathName\fR \fBnotify uninstall detail\fR \fIeventName\fR \fIdetail\fR .sp \fIpathName\fR \fBnotify uninstall event\fR \fIeventName\fR .sp \fIpathName\fR \fBnumcolumns\fR .sp \fIpathName\fR \fBnumitems\fR .sp \fIpathName\fR \fBorphans\fR .sp \fIpathName\fR \fBrange\fR \fIfirst\fR \fIlast\fR .sp \fIpathName\fR \fBscan\fR \fIoption\fR \fIargs\fR .sp \fIpathName\fR \fBscan mark\fR \fIx\fR \fIy\fR .sp \fIpathName\fR \fBscan dragto\fR \fIx\fR \fIy\fR ?\fIgain\fR? .sp \fIpathName\fR \fBsee\fR \fIitemDesc\fR ?\fIcolumnDesc\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBselection\fR \fIoption\fR \fIargs\fR .sp \fIpathName\fR \fBselection add\fR \fIfirst\fR ?\fIlast\fR? .sp \fIpathName\fR \fBselection anchor\fR ?\fIitemDesc\fR? .sp \fIpathName\fR \fBselection clear\fR ?\fIfirst\fR? ?\fIlast\fR? .sp \fIpathName\fR \fBselection count\fR .sp \fIpathName\fR \fBselection get\fR ?\fIfirst\fR? ?\fIlast\fR? .sp \fIpathName\fR \fBselection includes\fR \fIitemDesc\fR .sp \fIpathName\fR \fBselection modify\fR \fIselect\fR \fIdeselect\fR .sp \fIpathName\fR \fBstate\fR \fIoption\fR \fIargs\fR .sp \fIpathName\fR \fBstate define\fR \fIstateName\fR .sp \fIpathName\fR \fBstate linkage\fR \fIstateName\fR .sp \fIpathName\fR \fBstate names\fR .sp \fIpathName\fR \fBstate undefine\fR ?\fIstateName ...\fR? .sp \fIpathName\fR \fBstyle\fR \fIoption\fR ?\fIelement\fR? ?\fIarg arg ...\fR? .sp \fIpathName\fR \fBstyle cget\fR \fIstyle\fR \fIoption\fR .sp \fIpathName\fR \fBstyle configure\fR \fIstyle\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBstyle create\fR \fIname\fR ?\fIoption value ...\fR? .sp \fIpathName\fR \fBstyle delete\fR ?\fIstyle ...\fR? .sp \fIpathName\fR \fBstyle elements\fR \fIstyle\fR ?\fIelementList\fR? .sp \fIpathName\fR \fBstyle layout\fR \fIstyle\fR \fIelement\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? .sp \fIpathName\fR \fBstyle names\fR .sp \fIpathName\fR \fBtheme\fR \fIoption\fR ?\fIarg ...\fR? .sp \fIpathName\fR \fBtheme platform\fR .sp \fIpathName\fR \fBtheme setwindowtheme\fR \fIappname\fR .sp \fIpathName\fR \fBtoggle\fR ?\fB-recurse\fR? ?\fIitemDesc ...\fR? .sp \fIpathName\fR \fBxview\fR ?\fIargs\fR? .sp \fIpathName\fR \fBxview\fR .sp \fIpathName\fR \fBxview moveto\fR \fIfraction\fR .sp \fIpathName\fR \fBxview scroll\fR \fInumber\fR \fIwhat\fR .sp \fIpathName\fR \fByview\fR ?\fIargs\fR? .sp \fIpathName\fR \fByview\fR .sp \fIpathName\fR \fByview moveto\fR \fIfraction\fR .sp \fIpathName\fR \fByview scroll\fR \fInumber\fR \fIwhat\fR .sp .BE .SH DESCRIPTION .TP \fBtreectrl\fR \fIpathName\fR ?\fIoptions\fR? .PP .PP The \fBtreectrl\fR command creates a new window (given by the \fIpathName\fR argument) and makes it into a treectrl widget. Additional options, described above, may be specified on the command line or in the option database to configure aspects of the treectrl such as its background color and relief. The \fBtreectrl\fR command returns the path name of the new window. At the time this command is invoked, there must not exist a window named \fIpathName\fR, but \fIpathName\fR's parent must exist. .PP A treectrl is a listbox widget which displays items in a one- or two-dimensional arrangement. Items have a parent-child relationship with other items. Items may be arranged from top-to-bottom or from left-to-right. Items may be spread about one or more columns. Each item-column may be configured to span one or more adjacent item-columns. The visibility of items can be set individually. .PP Items have a set of states, which are boolean properties. For each column of an item there is a style associated, which determines how to display the item's column taking into account the item's current state set. New states may be defined to further control the appearance of items; these custom states may be turned on or off in individual columns of items. .PP Multiple rows of column headers are supported. Column headers have platform-native appearance on Windows, Mac OS X, and Gtk+. The appearance of column headers may be customized using styles. .PP Columns may be rearranged by the user using drag-and-drop. One column can be specified to display the data in a hierarchical structure. The visibility of columns can be set individually. .PP A treectrl can display a user-resizable selection rectangle called the marquee. Another feature, the drag image, may be used to provide feedback during drag-and-drop operations. Both of these are features commonly found in file browsers. .PP A treectrl can generate events when various things happen, such as changes to the selection, or a parent item being toggled open or closed. Scripts may be bound to these events. New events can be defined. .PP A treectrl can display a background image. The background image can be configured to be scrolled and tiled on each axis individually. .SH "STANDARD OPTIONS" .TP \fB\fB-background\fR\fR .TP \fB\fB-borderwidth\fR\fR .TP \fB\fB-cursor\fR\fR .TP \fB\fB-font\fR\fR .TP \fB\fB-highlightbackground\fR\fR .TP \fB\fB-highlightcolor\fR\fR .TP \fB\fB-highlightthickness\fR\fR .TP \fB\fB-orient\fR\fR .TP \fB\fB-relief\fR\fR .TP \fB\fB-takefocus\fR\fR .TP \fB\fB-xscrollcommand\fR\fR .TP \fB\fB-yscrollcommand\fR\fR .TP \fB\fB-foreground\fR\fR .PP See the \fBoption\fR manual entry for details on the standard options. .SH "WIDGET SPECIFIC OPTIONS" .LP .nf .ta 6c Command-Line Switch: \fB-backgroundimage\fR Database Name: \fBbackgroundImage\fR Database Class: \fBBackgroundImage\fR .fi .IP Specifies the name of an image to draw as the list background. Other options control whether the image is tiled and whether the image scrolls. If the image is transparent it is drawn on top of any column \fB-itembackground\fR colors. .LP .nf .ta 6c Command-Line Switch: \fB-backgroundmode\fR Database Name: \fBbackgroundMode\fR Database Class: \fBBackgroundMode\fR .fi .IP Specifies how the background color of items is chosen in each column. The value should be one of \fBrow\fR, \fBcolumn\fR, \fBorder\fR, or \fBordervisible\fR. The default is \fBrow\fR. This option has only an effect for columns which have \fB-itembackground\fR defined as list of two or more colors (see section \fBCOLUMNS\fR below for more on this). If \fBrow\fR or \fBcolumn\fR is specified, the background color is chosen based on the location of the item in the 1- or 2-dimensional grid of items as layed out on the screen; this layout of items is affected by the \fB-orient\fR and \fB-wrap\fR options as well as item visibility. When \fBorder\fR or \fBordervisible\fR is specified, the background color is chosen based on the result of the \fBitem order\fR command, regardless of the layout of items. .LP .nf .ta 6c Command-Line Switch: \fB-bgimage\fR Database Name: \fBbgImage\fR Database Class: \fBBgImage\fR .fi .IP Synonym for -backgroundimage. .LP .nf .ta 6c Command-Line Switch: \fB-bgimageanchor\fR Database Name: \fBbgImageAnchor\fR Database Class: \fBBgImageAnchor\fR .fi .IP Specifies how the background image should be aligned in any of the forms acceptable to \fBTk_GetAnchor\fR. Must be one of the values \fBn\fR, \fBne\fR, \fBe\fR, \fBse\fR, \fBs\fR, \fBsw\fR, \fBw\fR, \fBnw\fR, or \fBcenter\fR. The default is \fBnw\fR. When the background image scrolls, the anchor position is relative to the \fBcanvas\fR, otherwise it is relative to the contentbox. .LP .nf .ta 6c Command-Line Switch: \fB-bgimageopaque\fR Database Name: \fBbgImageOpaque\fR Database Class: \fBBgImageOpaque\fR .fi .IP Specifies a boolean indicating whether or not the background image is fully opaque. This is needed because there is no way in Tk to determine whether an image contains transparency or not. The default value is true, so if you use a transparent -backgroundimage you must set this to false. .LP .nf .ta 6c Command-Line Switch: \fB-bgimagescroll\fR Database Name: \fBbgImageScroll\fR Database Class: \fBBgImageScroll\fR .fi .IP Specifies whether the background image scrolls along with the items or whether it remains locked in place relative to the edges of the window. The value must be a string that contains zero or more of the characters \fBx\fR or \fBy\fR. The default is \fBxy\fR. .LP .nf .ta 6c Command-Line Switch: \fB-bgimagetile\fR Database Name: \fBbgImageTile\fR Database Class: \fBBgImageTile\fR .fi .IP Specifies whether the background image is tiled along the x and/or y axes. The value must be a string that contains zero or more of the characters \fBx\fR or \fBy\fR. The default is \fBxy\fR. .LP .nf .ta 6c Command-Line Switch: \fB-buttonbitmap\fR Database Name: \fBbuttonBitmap\fR Database Class: \fBButtonBitmap\fR .fi .IP Specifies the name of a bitmap be used to display the expand/collapse button of an item. This is a \fBper-state\fR option. If a bitmap is specified for a certain item state, it overrides the effects of -usetheme. .LP .nf .ta 6c Command-Line Switch: \fB-buttoncolor\fR Database Name: \fBbuttonColor\fR Database Class: \fBButtonColor\fR .fi .IP Specifies the foreground color which should be used for drawing the outline and the plus or minus sign of an item's expand/collapse button. .LP .nf .ta 6c Command-Line Switch: \fB-buttonimage\fR Database Name: \fBbuttonImage\fR Database Class: \fBButtonImage\fR .fi .IP Specifies the name of an image to be used to display the expand/collapse button of an item. This is a \fBper-state\fR option. If an image is specified for a certain item state, it overrides the effects of -buttonbitmap and -usetheme. .LP .nf .ta 6c Command-Line Switch: \fB-buttonsize\fR Database Name: \fBbuttonSize\fR Database Class: \fBButtonSize\fR .fi .IP Specifies the width and height of the expand/collapse button of an item in any of the forms acceptable to \fBTk_GetPixels\fR. .LP .nf .ta 6c Command-Line Switch: \fB-buttonthickness\fR Database Name: \fBbuttonThickness\fR Database Class: \fBButtonThickness\fR .fi .IP Specifies the width of the outline and the plus or minus sign of the expand/collapse button of an item in any of the forms acceptable to \fBTk_GetPixels\fR. .LP .nf .ta 6c Command-Line Switch: \fB-buttonttracking\fR Database Name: \fBbuttonTracking\fR Database Class: \fBButtonTracking\fR .fi .IP Specifies a boolean that determines if the expand/collapse buttons are tracked like pushbuttons when clicking them. When true, buttons are not toggled until the event occurs over them. When false, buttons are toggled as soon as the event occurs over them. This option defaults to true on Mac OS X and Gtk+, false on Win32 and X11. .LP .nf .ta 6c Command-Line Switch: \fB-canvaspadx\fR Database Name: \fBcanvasPadX\fR Database Class: \fBCanvasPadX\fR .fi .IP Specifies the width of extra whitespace on the left and right edges of the \fBcanvas\fR in any of the forms acceptable to \fBTk_GetPixels\fR. The option value may be a list of one or two screen distances to specify padding for the two edges separately. The default is 0. .LP .nf .ta 6c Command-Line Switch: \fB-canvaspady\fR Database Name: \fBcanvasPadY\fR Database Class: \fBCanvasPadY\fR .fi .IP Specifies the height of extra whitespace on the top and bottom edges of the \fBcanvas\fR in any of the forms acceptable to \fBTk_GetPixels\fR. The option value may be a list of one or two screen distances to specify padding for the two edges separately. The default is 0. .LP .nf .ta 6c Command-Line Switch: \fB-columnprefix\fR Database Name: \fBcolumnPrefix\fR Database Class: \fBColumnPrefix\fR .fi .IP Specifies an ascii string that changes the way column ids are reported and processed. If this option is a non-empty string, the usual integer value of a column id is prefixed with the given string. This can aid debugging but it is important your code doesn't assume column ids are integers if you use it. .LP .nf .ta 6c Command-Line Switch: \fB-columnproxy\fR Database Name: \fBcolumnProxy\fR Database Class: \fBColumnProxy\fR .fi .IP If this option specifies a non empty value, it should be a screen distance in any of the forms acceptable to \fBTk_GetPixels\fR. Then a 1 pixel thick vertical line will be drawn at the specified screen distance from the left edge of the treectrl widget, which reaches from top to bottom of the treectrl widget and uses an inverting color (i.e black on lighter background, white on darker background). This line can be used to give the user a visual feedback during column resizing. .LP .nf .ta 6c Command-Line Switch: \fB-columnresizemode\fR Database Name: \fBcolumnResizeMode\fR Database Class: \fBColumnResizeMode\fR .fi .IP Specifies the visual feedback used when resizing columns. The value should be one of \fBproxy\fR or \fBrealtime\fR. For \fBproxy\fR, a 1-pixel thick vertical line is drawn representing where the right edge of the column will be after resizing. For \fBrealtime\fR, the column's size is changed while the user is dragging the right edge of the column. The default is \fBrealtime\fR. .LP .nf .ta 6c Command-Line Switch: \fB-columntagexpr\fR Database Name: \fBcolumnTagExpr\fR Database Class: \fBColumnTagExpr\fR .fi .IP Specifies a boolean that enables or disables tag expressions in column descriptions. See \fBITEM AND COLUMN TAGS\fR. .LP .nf .ta 6c Command-Line Switch: \fB-defaultstyle\fR Database Name: \fBdefaultStyle\fR Database Class: \fBDefaultStyle\fR .fi .IP This option is deprecated; use the column option \fB-itemstyle\fR instead. Specifies a list of styles, one per column, to apply to each item created by the \fBitem create\fR command. The number of styles in the list can be different from the number of tree columns. Each list element should be a valid style name or an empty string to indicate no style should be applied to a specific column. The list of styles is updated if a style is deleted or if a column is moved. .LP .nf .ta 6c Command-Line Switch: \fB-doublebuffer\fR Database Name: \fBdoubleBuffer\fR Database Class: \fBDoubleBuffer\fR .fi .IP This option no longer has any effect, but was left in for compatibility. It used to control the amount of double-buffering that was used when displaying a treectrl. .LP .nf .ta 6c Command-Line Switch: \fB-headerfont\fR Database Name: \fBheaderFont\fR Database Class: \fBFont\fR .fi .IP Specifies the font to draw text in column headers with. The default value is TkHeadingFont where available (on Tk 8.5+). This option can be overridden by setting the \fB-font\fR option for individual column headers. .LP .nf .ta 6c Command-Line Switch: \fB-headerfg\fR Database Name: \fBheaderForeground\fR Database Class: \fBForeground\fR .fi .IP Synonym for -headerforeground. .LP .nf .ta 6c Command-Line Switch: \fB-headerforeground\fR Database Name: \fBheaderForeground\fR Database Class: \fBForeground\fR .fi .IP Specifies the color to draw text in column headers with. The default value is the Tk button foreground color (usually black). On Gtk+, the system theme may override this color. This option (and the Gtk+ system theme color) can be overridden by setting the \fB-textcolor\fR option for individual column headers. .LP .nf .ta 6c Command-Line Switch: \fB-height\fR Database Name: \fBheight\fR Database Class: \fBHeight\fR .fi .IP Specifies the desired height for the window in any of the forms acceptable to \fBTk_GetPixels\fR. The default is 200 pixels. If this option is less than or equal to zero then the window will not request any size at all. .LP .nf .ta 6c Command-Line Switch: \fB-indent\fR Database Name: \fBindent\fR Database Class: \fBIndent\fR .fi .IP Specifies the screen distance an item is indented relative to its parent item in any of the forms acceptable to \fBTk_GetPixels\fR. The default is 19 pixels. .LP .nf .ta 6c Command-Line Switch: \fB-itemgapx\fR Database Name: \fBitemGapX\fR Database Class: \fBItemGapX\fR .fi .IP Specifies the horizontal spacing between adjacent items in any of the forms acceptable to \fBTk_GetPixels\fR. The default is 0. .LP .nf .ta 6c Command-Line Switch: \fB-itemgapy\fR Database Name: \fBitemGapY\fR Database Class: \fBItemGapY\fR .fi .IP Specifies the vertical spacing between adjacent items in any of the forms acceptable to \fBTk_GetPixels\fR. The default is 0. .LP .nf .ta 6c Command-Line Switch: \fB-itemheight\fR Database Name: \fBitemHeight\fR Database Class: \fBItemHeight\fR .fi .IP Specifies a fixed height for every item in any of the forms acceptable to \fBTk_GetPixels\fR. If non-zero, this option overrides the requested height of an item and the -minitemheight option. If an item's own -height option is specified then that is the height used for the item. In any case, items are never shorter than the maximum height of a button if they display one. The default is 0. .LP .nf .ta 6c Command-Line Switch: \fB-itemprefix\fR Database Name: \fBitemPrefix\fR Database Class: \fBItemPrefix\fR .fi .IP Specifies an ascii string that changes the way item ids are reported and processed. If this option is a non-empty string, the usual integer value of an item id is prefixed with the given string. This can aid debugging but it is important your code doesn't assume item ids are integers if you use it. .LP .nf .ta 6c Command-Line Switch: \fB-itemtagexpr\fR Database Name: \fBitemTagExpr\fR Database Class: \fBItemTagExpr\fR .fi .IP Specifies a boolean that enables or disables tag expressions in item descriptions. See \fBITEM AND COLUMN TAGS\fR. .LP .nf .ta 6c Command-Line Switch: \fB-itemwidth\fR Database Name: \fBitemWidth\fR Database Class: \fBItemWidth\fR .fi .IP Specifies a fixed width for every item in any of the forms acceptable to \fBTk_GetPixels\fR. If more than one column is visible, then this option has no effect. If the -orient option is vertical, and the -wrap option is unspecified, then this option has no effect (in that case all items are as wide as the column). .LP .nf .ta 6c Command-Line Switch: \fB-itemwidthequal\fR Database Name: \fBitemWidthEqual\fR Database Class: \fBItemWidthEqual\fR .fi .IP Specifies a boolean that says whether all items should have the same width. If more than one column is visible, then this option has no effect. If the -orient option is vertical, and the -wrap option is unspecified, then this option has no effect (in that case all items are as wide as the column). If the -itemwidth option is specified, then this option has no effect. .LP .nf .ta 6c Command-Line Switch: \fB-itemwidthmultiple\fR Database Name: \fBitemWidthMultiple\fR Database Class: \fBItemWidthMultiple\fR .fi .IP Specifies a screen distance that every item's width will be evenly divisible by in any of the forms acceptable to \fBTk_GetPixels\fR. If more than one column is visible, then this option has no effect. If the -orient option is vertical, and the -wrap option is unspecified, then this option has no effect (in that case all items are as wide as the column). If the -itemwidth option is specified, then this option has no effect. .LP .nf .ta 6c Command-Line Switch: \fB-linecolor\fR Database Name: \fBlineColor\fR Database Class: \fBLineColor\fR .fi .IP Specifies the color which should be used for drawing the connecting lines between related items. .LP .nf .ta 6c Command-Line Switch: \fB-linestyle\fR Database Name: \fBlineStyle\fR Database Class: \fBLineStyle\fR .fi .IP Specifies the appearance of the connecting lines between related items. The value should be \fBdot\fR, which is the default, or \fBsolid\fR. .LP .nf .ta 6c Command-Line Switch: \fB-linethickness\fR Database Name: \fBlineThickness\fR Database Class: \fBLineThickness\fR .fi .IP Specifies the thickness of the connecting lines between related items in any of the forms acceptable to \fBTk_GetPixels\fR. .LP .nf .ta 6c Command-Line Switch: \fB-minitemheight\fR Database Name: \fBminItemHeight\fR Database Class: \fBMinItemHeight\fR .fi .IP Specifies a minimum height for every item in any of the forms acceptable to \fBTk_GetPixels\fR. The default is 0, which means that every item has the height requested by the arrangement of elements in each column. This option has no effect if either the -itemheight widget option or -height item option is specified. In any case, items are never shorter than the maximum height of an expand/collapse button. .LP .nf .ta 6c Command-Line Switch: \fB-rowproxy\fR Database Name: \fBrowProxy\fR Database Class: \fBRowProxy\fR .fi .IP If this option specifies a non empty value, it should be a screen distance in any of the forms acceptable to \fBTk_GetPixels\fR. Then a 1 pixel thick horizontal line will be drawn at the specified screen distance from the top edge of the treectrl widget, which reaches from left to right of the treectrl widget and uses an inverting color (i.e black on lighter background, white on darker background). This line can be used to give the user a visual feedback during row resizing. .LP .nf .ta 6c Command-Line Switch: \fB-scrollmargin\fR Database Name: \fBscrollMargin\fR Database Class: \fBScrollMargin\fR .fi .IP Specifies a positive screen distance in any of the forms acceptable to \fBTk_GetPixels\fR. This option is used by the default bindings to determine how close to the edges of the contentbox the mouse pointer must be before scrolling occurs. Specifying a positive value is useful when items may be drag-and-dropped. Defaults to 0. .LP .nf .ta 6c Command-Line Switch: \fB-selectmode\fR Database Name: \fBselectMode\fR Database Class: \fBSelectMode\fR .fi .IP 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 \fBsingle\fR, \fBbrowse\fR, \fBmultiple\fR, or \fBextended\fR; the default value is \fBbrowse\fR. .LP .nf .ta 6c Command-Line Switch: \fB-showbuttons\fR Database Name: \fBshowButtons\fR Database Class: \fBShowButtons\fR .fi .IP Specifies a boolean value that determines whether this widget leaves indentation space to display the expand/collapse buttons next to items. The default value is true. The item option \fB-button\fR determines whether an item has a button. See also the widget options \fB-showrootbutton\fR and \fB-showrootchildbuttons\fR. .LP .nf .ta 6c Command-Line Switch: \fB-showheader\fR Database Name: \fBshowHeader\fR Database Class: \fBShowHeader\fR .fi .IP Specifies a boolean value that determines whether this widget should display the header line with the column names at the top of the widget. The default value is true. .LP .nf .ta 6c Command-Line Switch: \fB-showlines\fR Database Name: \fBshowLines\fR Database Class: \fBShowLines\fR .fi .IP Specifies a boolean value that determines whether this widget should draw the connecting lines between related items. The default value is true on Win32 and X11, false on Mac OS X and Gtk+. .LP .nf .ta 6c Command-Line Switch: \fB-showroot\fR Database Name: \fBshowRoot\fR Database Class: \fBShowRoot\fR .fi .IP Specifies a boolean value that determines whether this widget should draw the root item. By suppressing the drawing of the root item the widget can have multiple items that appear as toplevel items. The default value is true. .LP .nf .ta 6c Command-Line Switch: \fB-showrootbutton\fR Database Name: \fBshowRootButton\fR Database Class: \fBShowRootButton\fR .fi .IP Specifies a boolean value that determines whether this widget leaves indentation space to display the expand/collapse button next to the root item. The default value is false. The item option \fB-button\fR determines whether the root item has a button. .LP .nf .ta 6c Command-Line Switch: \fB-showrootchildbuttons\fR Database Name: \fBshowRootChildButtons\fR Database Class: \fBShowRootChildButtons\fR .fi .IP Specifies a boolean value that determines whether this widget should draw the expand/collapse buttons next to children of the root item. The default value is true. .LP .nf .ta 6c Command-Line Switch: \fB-showrootlines\fR Database Name: \fBshowRootLines\fR Database Class: \fBShowRootLines\fR .fi .IP Specifies a boolean value that determines whether this widget should draw the connecting lines between children of the root item. The default value is true. .LP .nf .ta 6c Command-Line Switch: \fB-treecolumn\fR Database Name: \fBtreeColumn\fR Database Class: \fBTreeColumn\fR .fi .IP Specifies a \fBcolumn description\fR that determines which column displays the expand/collapse buttons and connecting lines between items. The default is unspecified. .LP .nf .ta 6c Command-Line Switch: \fB-usetheme\fR Database Name: \fBuseTheme\fR Database Class: \fBUseTheme\fR .fi .IP Specifies a boolean value that determines whether this widget should draw parts of itself using a platform-specific theme manager. The default is true. .LP .nf .ta 6c Command-Line Switch: \fB-width\fR Database Name: \fBwidth\fR Database Class: \fBWidth\fR .fi .IP Specifies the desired width for the window in any of the forms acceptable to \fBTk_GetPixels\fR. The default is 200 pixel. If this option is less than or equal to zero then the window will not request any size at all. .LP .nf .ta 6c Command-Line Switch: \fB-wrap\fR Database Name: \fBwrap\fR Database Class: \fBWrap\fR .fi .IP Specifies whether items are arranged in a 1- or 2-dimensional layout. .sp If the value is an empty string (the default), then items are arranged from top to bottom (-orient=vertical) or from left to right (-orient=horizontal) in a 1-dimensional layout. .sp If the value is "\fIN\fR \fBitems\fR", then no more than \fIN\fR items will appear in a vertical group (-orient=vertical) or horizontal group (-orient=horizontal). .sp If the value is "\fIN\fR \fBpixels\fR", then no vertical group of items will be taller than \fIN\fR pixels (-orient=vertical) or no horizontal group of items will be wider than \fIN\fR pixels (-orient=horizontal). .sp If the value is \fBwindow\fR, then a no vertical group of items will be taller than the window (-orient=vertical) or no horizontal group of items will be wider than the window (-orient=horizontal). .sp It is also possible to cause wrapping to occur on a per-item basis by using the item option -wrap. See the \fBitem create\fR command for that option. .LP .nf .ta 6c Command-Line Switch: \fB-xscrolldelay\fR Database Name: \fBxScrollDelay\fR Database Class: \fBScrollDelay\fR .fi .IP This option controls how quickly horizontal scrolling occurs while dragging the mouse with button 1 pressed. The value should be a list of 1 or 2 integers interpreted as milliseconds. If 2 values are specified, then the first value determines the intial delay after the first scroll, and the second value determines the delay for all scrolling after the first. If only 1 value is specified, each scroll takes place after that delay. .LP .nf .ta 6c Command-Line Switch: \fB-xscrollincrement\fR Database Name: \fBxScrollIncrement\fR Database Class: \fBScrollIncrement\fR .fi .IP Specifies an increment for horizontal scrolling, in any of the usual forms permitted for screen distances. If the value of this option is greater than zero, the horizontal view in the window will be constrained so that the \fBcanvas\fR x coordinate at the left edge of the window is always an even multiple of \fB-xscrollincrement\fR; furthermore, the units for scrolling (e.g., the change in view when the left and right arrows of a scrollbar are selected) will also be \fB-xscrollincrement\fR. If the value of this option is less than or equal to zero, then horizontal scrolling snaps to the left of an item, or part of an item if items are wider than the contentbox. .LP .nf .ta 6c Command-Line Switch: \fB-xscrollsmoothing\fR Database Name: \fBxScrollSmoothing\fR Database Class: \fBScrollSmoothing\fR .fi .IP Specifies whether scrolling should be done as if -xscrollincrement=1 whenever scrolling is performed by non-unit amounts. When the value of this option is true and the xview command is called to scroll by "units", scrolling occurs according to the -xscrollincrement option, and all other scrolling is done as if the -xscrollincrement option was set to 1. The effect is that when dragging the scrollbar thumb scrolling is very smooth, but when clicking the scrollbar buttons scrolling is done in coarser increments. The default value is false. .LP .nf .ta 6c Command-Line Switch: \fB-yscrolldelay\fR Database Name: \fByScrollDelay\fR Database Class: \fBScrollDelay\fR .fi .IP This option controls how quickly vertical scrolling occurs while dragging the mouse with button 1 pressed. The value should be a list of 1 or 2 integers interpreted as milliseconds. If 2 values are specified, then the first value determines the intial delay after the first scroll, and the second value determines the delay for all scrolling after the first. If only 1 value is specified, each scroll takes place after that delay. .LP .nf .ta 6c Command-Line Switch: \fB-yscrollincrement\fR Database Name: \fByScrollIncrement\fR Database Class: \fBScrollIncrement\fR .fi .IP Specifies an increment for vertical scrolling, in any of the usual forms permitted for screen distances. If the value of this option is greater than zero, the vertical view in the window will be constrained so that the \fBcanvas\fR y coordinate at the top edge of the window is always an even multiple of \fB-yscrollincrement\fR; furthermore, the units for scrolling (e.g., the change in view when the top and bottom arrows of a scrollbar are selected) will also be \fB-yscrollincrement\fR. If the value of this option is less than or equal to zero, then vertical scrolling snaps to the top of an item, or part of an item if items are taller than the contentbox. .LP .nf .ta 6c Command-Line Switch: \fB-yscrollsmoothing\fR Database Name: \fByScrollSmoothing\fR Database Class: \fBScrollSmoothing\fR .fi .IP Specifies whether scrolling should be done as if -yscrollincrement=1 whenever scrolling is performed by non-unit amounts. When the value of this option is true and the yview command is called to scroll by "units", scrolling occurs according to the -yscrollincrement option, and all other scrolling is done as if the -yscrollincrement option was set to 1. The effect is that when dragging the scrollbar thumb scrolling is very smooth, but when clicking the scrollbar buttons scrolling is done in coarser increments. The default value is false. .PP .SH "THE CANVAS" Throughout this manual page the term \fIcanvas\fR is sometimes used. The canvas can be thought of as the virtual sheet of paper upon which all visible items are drawn. The treectrl window displays different areas of the canvas within its borders as the list is scrolled. .SH "ITEM AND COLUMN TAGS" Columns and items may have any number of tags associated with them. A tag is just a string of characters, and it may take any form, including that of an integer, although the characters '(', ')', '&', '|', '^' and '!' should be avoided. .PP The same tag may be associated with many columns or items. This is commonly done to group items in various interesting ways; for example, in a file browser all directories might be given the tag "directory". .PP Tag expressions are used in \fBcolumn descriptions\fR and \fBitem descriptions\fR to specify which columns and items to operate on. A tag expression can be a single tag name or a logical expression of tags using operators '&&', '||', '^' and '!', and parenthesized subexpressions. For example: .nf .t item id "tag {(a && !b) || (!a && b)}" .fi or equivalently: .nf .t item id "tag {a ^ b}" .fi will return the unique ids of any items with either "a" or "b" tags, but not both. .PP Within a tag expression a tag name may be enclosed in double quotes to avoid special processing of the operator characters. For example: .nf .t item id {tag {"a&&b"||c}} .fi will return the unique ids of any items with either "a&&b" or "c" tags; in this example the && is not treated as an operator. A double-quote may be escaped within a quoted tag name using a backslash '\\'. .PP Tag operators may be bypassed completely by setting the \fB-columntagexpr\fR and \fB-itemtagexpr\fR options. This can be useful if your application has column or item tags containing arbitrary text. .nf .t configure -itemtagexpr false .t item delete "tag a&&b" .fi .SH "WIDGET COMMAND" The \fBtreectrl\fR command creates a new Tcl command whose name is the same as the path name of the treectrl's window. This command may be used to invoke various operations on the widget. It has the following general form: .PP \fIpathName\fR \fIoption\fR ?\fIarg arg ...\fR? .PP \fIPathName\fR is the name of the command, which is the same as the treectrl widget's path name. \fIOption\fR and the \fIarg\fRs determine the exact behavior of the command. The following commands are possible for treectrl widgets: .TP \fIpathName\fR \fBactivate\fR \fIitemDesc\fR Sets the active item to the one described by \fIitemDesc\fR, and switches on the state \fBactive\fR for that item. The active item can be referred to by the item description \fBactive\fR. If this command changes which item is active an \fB\fR event is generated. If the active item is deleted the root item becomes the new active item. .TP \fIpathName\fR \fBbbox\fR ?\fIarea\fR? Returns a list with four elements giving the bounding box (left, top, right and bottom) of an area of the window. If \fIarea\fR is not specified, then the result is the bounding box of the entire window. If \fIarea\fR is \fBcontent\fR, then the result is the part of the window not including borders, headers, or locked columns. If \fIarea\fR is \fBheader\fR, then the result is the part of the window not including borders where column titles are displayed. If \fIarea\fR is \fBleft\fR, then the result is the part of the window not including borders or headers where left-locked columns are displayed. If \fIarea\fR is \fBright\fR, then the result is the part of the window not including borders or headers where right-locked columns are displayed. .sp If \fIarea\fR is one of \fBheader.left\fR, \fBheader.none\fR or \fBheader.right\fR then the area of the column headers occupied by columns with -lock=left, -lock=none or -lock=right is returned. .sp An empty string is returned if the display area has no height or width, which can be true for various reasons such as the window is too small, or the header is not displayed, or there aren't any locked columns. .TP \fIpathName\fR \fBcanvasx\fR \fIwindowx\fR Translates the given window x-coordinate \fIwindowx\fR in the treectrl to \fBcanvas\fR coordinate space. The \fBmarquee\fR command expects canvas coordinates. .TP \fIpathName\fR \fBcanvasy\fR \fIwindowy\fR Translates the given window y-coordinate \fIwindowy\fR in the treectrl to \fBcanvas\fR coordinate space. The \fBmarquee\fR command expects canvas coordinates. .TP \fIpathName\fR \fBcget\fR \fIoption\fR Returns the current value of the configuration option given by \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBtree\fR command. .TP \fIpathName\fR \fBcollapse\fR ?\fB-recurse\fR? ?\fIitemDesc ...\fR? Deprecated. Use \fBitem collapse\fR instead. .TP \fIpathName\fR \fBcolumn\fR \fIoption\fR \fIcolumn\fR ?\fIarg ...\fR? This command is used to manipulate the columns of the treectrl widget (see section \fBCOLUMNS\fR below). The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBcolumn\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBcolumn bbox\fR \fIcolumnDesc\fR Returns a list with four elements giving the bounding box of the header of the column specified by the \fBcolumn description\fR \fIcolumnDesc\fR. The returned coordinates are relative to the top-left corner of the widget. If the column option \fB-visible\fR=false or if the widget option \fB-showheader\fR=false, then an empty list is returned. .TP \fIpathName\fR \fBcolumn cget\fR \fIcolumnDesc\fR \fIoption\fR This command returns the current value of the option named \fIoption\fR for the column specified by the \fBcolumn description\fR \fIcolumnDesc\fR, \fIColumnDesc\fR may also be the string \fBtail\fR to specify the tail column. \fIOption\fR may have any of the values accepted by the \fBcolumn configure\fR widget command. .TP \fIpathName\fR \fBcolumn configure\fR \fIcolumnDesc\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command is similar to the \fBconfigure\fR widget command except that it modifies options associated with the columns specified by the \fBcolumn description\fR \fIcolumnDesc\fR instead of modifying options for the overall treectrl widget. \fIColumnDesc\fR may be the string \fBtail\fR to specify the tail column. If \fIcolumnDesc\fR refers to more than one column, then at least one option-value pair must be given. If no \fIoption\fR is specified, the command returns a list describing all of the available options for \fIcolumnDesc\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, 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 \fIoption\fR is specified). If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given option(s) to have the given value(s) for \fIcolumnDesc\fR; in this case the command returns an empty string. .sp See \fBCOLUMNS\fR below for details on the options available for columns. .sp For compatibility with older versions of treectrl (which did not support more than one row of column headers) any of the configuration options mentioned in the \fBHEADERS\fR section, such as \fB-arrow\fR, \fB-text\fR, etc, may be passed to the top header-row through this command. .TP \fIpathName\fR \fBcolumn compare\fR \fIcolumn1\fR \fIop\fR \fIcolumn2\fR For both \fBcolumn descriptions\fR \fIcolumn1\fR and \fIcolumn2\fR the index is retrieved (as returned from the \fBcolumn order\fR widget command). Then these indexes are compared using the operator \fIop\fR, which must be either \fB<\fR, \fB<=\fR, \fB==\fR, \fB>=\fR, \fB>\fR, or \fB!=\fR. The return value of this command is 1 if the comparison evaluated to true, 0 otherwise. .TP \fIpathName\fR \fBcolumn count\fR ?\fIcolumnDesc\fR? If no additional arguments are given, the result is a decimal string giving the number of columns created by the \fBcolumn create\fR widget command which haven't been deleted by the \fBcolumn delete\fR widget command; in this case the \fBtail\fR column is not counted. If \fIcolumnDesc\fR is given, then the result is the number of columns that match that \fBcolumn description\fR. .TP \fIpathName\fR \fBcolumn create\fR ?\fIoption value ...\fR? This command creates a new column in the treectrl widget. The new column is placed to the right of all other columns (except the \fBtail\fR column). Any \fIoption\fR-\fIvalue\fR arguments configure the new column according to the \fBcolumn configure\fR command. The return value is the unique identifier of the new column. .TP \fIpathName\fR \fBcolumn delete\fR \fIfirst\fR ?\fIlast\fR? Deletes the specified column(s). \fIFirst\fR and \fIlast\fR must be valid \fBcolumn descriptions\fR. If both \fIfirst\fR and \fIlast\fR are specified, then they may refer to a single column only. The \fBtail\fR column cannot be deleted and it is an error to specify it. The order of \fIfirst\fR and \fIlast\fR doesn't matter, and \fIfirst\fR may be equal to \fIlast\fR. .TP \fIpathName\fR \fBcolumn dragcget\fR \fIoption\fR Deprecated. Use \fBheader dragcget\fR instead. .TP \fIpathName\fR \fBcolumn dragconfigure\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? Deprecated. Use \fBheader dragconfigure\fR instead. .TP \fIpathName\fR \fBcolumn index\fR \fIcolumnDesc\fR Deprecated. Use \fBcolumn id\fR instead. .TP \fIpathName\fR \fBcolumn id\fR \fIcolumnDesc\fR This command resolves the \fBcolumn description\fR \fIcolumnDesc\fR into a list of unique column identifiers. If the column(s) described by \fIcolumnDesc\fR don't exist, this command returns an empty list. .TP \fIpathName\fR \fBcolumn list\fR ?\fI-visible\fR? This command returns a list of identifiers for every column (except the tail) from left to right. If \fI-visible\fR is given, only columns whose -visible option is true are returned. .TP \fIpathName\fR \fBcolumn move\fR \fIcolumnDesc\fR \fIbeforeDesc\fR Moves the column specified by \fIcolumnDesc\fR to the left of the column specified by \fIbeforeDesc\fR. Both \fIcolumnDesc\fR and \fIbeforeDesc\fR must be valid \fBcolumn descriptions\fR. If \fIbeforeDesc\fR is the string \fBtail\fR, the column \fIcolumnDesc\fR will become the last column. .TP \fIpathName\fR \fBcolumn neededwidth\fR \fIcolumnDesc\fR This command returns a decimal string giving the needed width of the column specified by the \fBcolumn description\fR \fIcolumnDesc\fR. The needed width is the maximum of the width of the column header and the width of the widest style in any visible item. .sp When an item style or column header spans multiple columns, the needed width of a column is affected by the widths of other columns in the span, in which case the result of this command isn't particularly useful. .TP \fIpathName\fR \fBcolumn order\fR \fIcolumnDesc\fR ?\fI-visible\fR? This command returns a decimal string giving the position of the column specified by the \fBcolumn description\fR \fIcolumnDesc\fR in the list of columns starting from zero for the leftmost column. If \fI-visible\fR is given, only columns whose -visible option is true are considered, and -1 is returned if \fIcolumnDesc\fR's -visible option is false. .TP \fIpathName\fR \fBcolumn tag\fR \fIoption\fR ?\fIarg arg ...\fR? This command is used to manipulate tags on columns. The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBcolumn tag\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBcolumn tag add\fR \fIcolumnDesc\fR \fItagList\fR Adds each tag in \fItagList\fR to the columns specified by the \fBcolumn description\fR \fIcolumnDesc\fR. Duplicate tags are ignored. The list of tags for a column can also be changed via a column's \fB-tags\fR option. .TP \fIpathName\fR \fBcolumn tag expr\fR \fIcolumnDesc\fR \fItagExpr\fR Evaluates the tag expression \fItagExpr\fR against every column specified by the \fBcolumn description\fR \fIcolumnDesc\fR. The result is 1 if the tag expression evaluates to true for every column, 0 otherwise. .TP \fIpathName\fR \fBcolumn tag names\fR \fIcolumnDesc\fR Returns a list of tag names assigned to the columns specified by the \fBcolumn description\fR \fIcolumnDesc\fR. The result is the union of any tags assigned to the columns. .TP \fIpathName\fR \fBcolumn tag remove\fR \fIcolumnDesc\fR \fItagList\fR Removes each tag in \fItagList\fR from the columns specified by the \fBcolumn description\fR \fIcolumnDesc\fR. It is not an error if any of the columns do not use any of the tags. The list of tags for a column can also be changed via a column's \fB-tags\fR option. .RE .TP \fIpathName\fR \fBcolumn width\fR \fIcolumnDesc\fR This command returns a decimal string giving the width in pixels of the column specified by the \fBcolumn description\fR \fIcolumnDesc\fR, even if the treectrl is configured to not display the column headers by means of the \fB-showheader\fR option. .RE .TP \fIpathName\fR \fBcompare\fR \fIitemDesc1\fR \fIop\fR \fIitemDesc2\fR Deprecated. Use the \fBitem compare\fR command instead. .TP \fIpathName\fR \fBconfigure\fR ?\fIoption\fR? ?\fIvalue option value ...\fR? Query or modify the configuration options of the widget. If no \fIoption\fR is specified, returns a list describing all of the available options for \fIpathName\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, 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 \fIoption\fR is specified). If one or more \fIoption\fR-\fIvalue\fR 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. \fIOption\fR may have any of the values accepted by the \fBtreectrl\fR command. .TP \fIpathName\fR \fBcontentbox\fR Returns a list with four elements giving the bounding box of the screen area used to display items. This is the area of the window not including borders, column headers, or locked columns. An empty string is returned if the display area has no height or width, which can happen if the window is too small. The result of this command is the same as that of \fBbbox content\fR. .TP \fIpathName\fR \fBdebug\fR \fIoption\fR ?\fIarg arg ...\fR? This command is used to facilitate debugging of the treectrl widget. The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBdebug\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBdebug alloc\fR Returns a string giving partial statistics on memory allocations, if the package was built with TREECTRL_DEBUG defined. .TP \fIpathName\fR \fBdebug cget\fR \fIoption\fR This command returns the current value of the debugging option named \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBdebug configure\fR widget command. .TP \fIpathName\fR \fBdebug configure\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command is similar to the \fBconfigure\fR widget command except that it modifies debugging options instead of modifying options for the overall treectrl widget. If no \fIoption\fR is specified, the command returns a list describing all of the available debugging options (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, 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 \fIoption\fR is specified). If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given debugging option(s) to have the given value(s); in this case the command returns an empty string. .sp The following debugging options are supported: .RS .TP \fB\fB-displaydelay\fR\fR \fImillis\fR Specifies a time duration in milliseconds, which should be waited after something has been drawn to the screen. Setting this option has only an effect, if the debugging options \fB-enable\fR and \fB-display\fR are switched on. .TP \fB\fB-data\fR\fR \fIboolean\fR If this option is switched on (together with the debugging option \fB-enable\fR), at various places a consistence check on the internal data structure is made (e.g. for every item is checked, if the registered number of children is equal to the number of child items). If an inconsistency was found, a Tcl background error is raised. .TP \fB\fB-display\fR\fR \fIboolean\fR If this option is switched on (together with the debugging option \fB-enable\fR), at varios places additional debugging output is printed to stdout. .TP \fB\fB-drawcolor\fR\fR \fIcolor\fR When specified, areas of the window are painted with this color when drawing in those areas is about to occur. Setting this option has only an effect if the debugging options \fB-enable\fR and \fB-display\fR are switched on. .TP \fB\fB-enable\fR\fR \fIboolean\fR All other debugging options only take effect if this option is also switched on. .TP \fB\fB-erasecolor\fR\fR \fIcolor\fR When specified, areas of the window which have been marked as "invalid" (for example, when part of the window is exposed) are painted with this color. If you use an unusual color for this option (like \fBpink\fR), superflous screen redraws can be spotted more easily. Setting this option has only an effect if the debugging options \fB-enable\fR and \fB-display\fR are switched on. .TP \fB\fB-span\fR\fR \fIboolean\fR Debugging related to column spanning. .TP \fB\fB-textlayout\fR\fR \fIboolean\fR Debugging related to text-element layout. .RE .TP \fIpathName\fR \fBdebug dinfo\fR \fIoption\fR Returns a string describing display-related stuff. \fIOption\fR must be one of \fBalloc\fR, \fBditem\fR, \fBonscreen\fR or \fBrange\fR. .TP \fIpathName\fR \fBdebug expose\fR \fIx1\fR \fIy1\fR \fIx2\fR \fIy2\fR Causes the area of the window bounded by the given window-coords to be marked as invalid. This simulates uncovering part of the window. .RE .TP \fIpathName\fR \fBdepth\fR ?\fIitemDesc\fR? If the additional argument \fIitemDesc\fR is given, then the result is a decimal string giving the depth of the item described by \fIitemDesc\fR. If no \fIitemDesc\fR is specified, then the maximum depth of all items in the treectrl widget is returned instead. Depth is defined as the number of ancestors an item has. .TP \fIpathName\fR \fBdragimage\fR \fIoption\fR ?\fIarg ...\fR? This command is used to manipulate the drag image, which is used to provide feedback when items are drag-and-dropped within the window. The drag image is displayed as the dotted outlines of one or more items, columns and/or elements. The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBdragimage\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBdragimage add\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fIelement\fR? Adds the shapes of the item described by \fIitemDesc\fR to the shapes of the dragimage. Specifying additional arguments reduces the number of rectangles that are added to the dragimage. If no additional arguments is specified, for every element of the item in every column a dotted rectangles is added. If \fIcolumn\fR is specified, all elements in other columns are ignored. If also \fIelement\fR is specified, only a rectangle for this one element of the specified item in the given column is added. .TP \fIpathName\fR \fBdragimage cget\fR \fIoption\fR This command returns the current value of the dragimage option named \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBdragimage configure\fR widget command. .TP \fIpathName\fR \fBdragimage clear\fR Removes all shapes (if there are any) from the dragimage. This command does not modify the dragimage offset. .TP \fIpathName\fR \fBdragimage configure\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command is similar to the \fBconfigure\fR widget command except that it modifies the dragimage options instead of modifying options for the overall treectrl widget. If no \fIoption\fR is specified, the command returns a list describing all of the available dragimage options (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named dragimage option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given dragimage option(s) to have the given value(s); in this case the command returns an empty string. .sp The following dragimage options are supported: .RS .TP \fB\fB-visible\fR\fR \fIboolean\fR Specifies a boolean value which determines whether the dragimage should currently be visible. .RE .TP \fIpathName\fR \fBdragimage offset\fR ?\fIx y\fR? Returns a list containing the x and y offsets of the dragimage, if no additional arguments are specified. The dragimage offset is the screen distance the image is displayed at relative to the item(s) its shape is derived from. If two coordinates are specified, sets the dragimage offset to the given coordinates \fIx\fR and \fIy\fR. .RE .TP \fIpathName\fR \fBelement\fR \fIoption\fR ?\fIelement\fR? ?\fIarg arg ...\fR? This command is used to manipulate elements (see \fBELEMENTS AND STYLES\fR below). The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBelement\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBelement cget\fR \fIelement\fR \fIoption\fR This command returns the current value of the option named \fIoption\fR associated with the element given by \fIelement\fR. \fIOption\fR may have any of the values accepted by the \fBelement configure\fR widget command. .sp This command also accepts the \fB-statedomain\fR option. .TP \fIpathName\fR \fBelement configure\fR \fIelement\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command is similar to the \fBconfigure\fR widget command except that it modifies options associated with the element given by \fIelement\fR instead of modifying options for the overall treectrl widget. If no \fIoption\fR is specified, the command returns a list describing all of the available options for \fIelement\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, 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 \fIoption\fR is specified). If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given option(s) to have the given value(s) in \fIelement\fR; in this case the command returns an empty string. See \fBELEMENTS AND STYLES\fR below for details on the options available for elements. .TP \fIpathName\fR \fBelement create\fR \fIname\fR \fItype\fR ?\fIoption value ...\fR? Creates a new master element of type \fItype\fR with the unique user-defined name \fIname\fR and configures it with zero or more option/value pairs. See the subsections on individual element types in \fBELEMENTS AND STYLES\fR for the options that are valid for each type of element. This command returns the name of the new element (the same as the \fIname\fR argument). .sp This command also accepts the \fB-statedomain\fR option with a value of either \fBheader\fR or \fBitem\fR to specify where this element will be displayed. .TP \fIpathName\fR \fBelement delete\fR ?\fIelement ...\fR? Deletes each of the named elements and returns an empty string. If an element is deleted while it is still configured as an element of one or more styles by means of the \fBstyle elements\fR widget command, it is also removed from the element lists of these styles. .TP \fIpathName\fR \fBelement names\fR Returns a list containing the names of all existing elements. .TP \fIpathName\fR \fBelement perstate\fR \fIelement\fR \fIoption\fR \fIstateList\fR This command returns the value of the \fBper-state\fR option named \fIoption\fR for \fIelement\fR for a certain state. \fIStateList\fR is a list of state names (static and dynamic, see \fBSTATES\fR) which specifies the state to use. .TP \fIpathName\fR \fBelement type\fR \fIelement\fR Returns the type of the element given by \fIelement\fR, such as \fBrect\fR or \fBtext\fR. .RE .TP \fIpathName\fR \fBexpand\fR ?\fB-recurse\fR? ?\fIitemDesc ...\fR? Deprecated. Use \fBitem expand\fR instead. .TP \fIpathName\fR \fBgradient\fR \fIoption\fR ?\fIarg ...\fR? This command is used to manipulate color gradients. See \fBGRADIENTS\fR for more information about using gradients. The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBgradient\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBgradient cget\fR \fIgradient\fR \fIoption\fR Returns the current value of the configuration option for the gradient specified by \fIgradient\fR whose name is \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBgradient configure\fR command. .TP \fIpathName\fR \fBgradient configure\fR \fIgradient\fR ?\fIoption value ...\fR? If no \fIoption\fR is specified, the command returns a list describing all of the available gradient options (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named gradient option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given gradient option(s) to have the given value(s); in this case the command returns an empty string. .sp The following options are supported (see \fBgradient create\fR for the meaning of each option): .RS .TP \fB\fB-bottom\fR\fR \fIcoordSpec\fR .TP \fB\fB-left\fR\fR \fIcoordSpec\fR .TP \fB\fB-orient\fR\fR \fIdirection\fR .TP \fB\fB-right\fR\fR \fIcoordSpec\fR .TP \fB\fB-steps\fR\fR \fIstepCount\fR .TP \fB\fB-stops\fR\fR \fIstopsList\fR .TP \fB\fB-top\fR\fR \fIcoordSpec\fR .RE .TP \fIpathName\fR \fBgradient create\fR \fIname\fR ?\fIoption value ...\fR? Creates a new gradient with the name \fIname\fR, which must be a unique name not used by another gradient created by this treectrl widget. .sp The following options are supported: .RS .TP \fB\fB-bottom\fR\fR \fIcoordSpec\fR .TP \fB\fB-left\fR\fR \fIcoordSpec\fR .TP \fB\fB-right\fR\fR \fIcoordSpec\fR .TP \fB\fB-top\fR\fR \fIcoordSpec\fR Each of these options specifies one edge of the gradient brush. If the option is specified as an empty string (the default), the gradient brush's edge is the same as that of whatever rectangle is being painted using the gradient. See \fBGRADIENT COORDINATES\fR for details on gradient brush coordinates. .sp The format of each of these options is a list of 2 or more values {value coordType ?arg ...?}, where \fIvalue\fR is a floating point number (usually from 0.0 to 1.0) and \fIcoordType\fR is one of \fBarea\fR, \fBcanvas\fR, \fBcolumn\fR or \fBitem\fR. The \fBarea\fR keyword must be followed by one of the same area names that the \fBbbox\fR command accepts. The \fBcolumn\fR keyword may be followed by a column description specifying exactly one column. The \fBitem\fR keyword may be followed by an item description specifying exactly one item. .TP \fB\fB-orient\fR\fR \fIdirection\fR This option specifies the direction a linear gradient changes color in. Must be either \fBhorizontal\fR (the default) or \fBvertical\fR or an abbreviation of one of these. .TP \fB\fB-steps\fR\fR \fIstepCount\fR Specifies the number of bands of color drawn for each color stop described by the \fB-stops\fR option. The default value is 1, the maximum is 25. This option has no effect if gradients are drawn using something better than Tk API calls. See \fBGRADIENTS\fR for more on this. .TP \fB\fB-stops\fR\fR \fIstopsList\fR Specifies the color stops along this gradient. The argument \fIstopsList\fR has the following form: .nf {{offset color ?opacity?} {offset color ?opacity?} ...} .fi Each \fIoffset\fR is a floating point number from 0.0 to 1.0 specifying the distance from the start of the gradient where the \fIcolor\fR begins. Each \fIcolor\fR is a Tk color name or description. Each optional \fIopacity\fR is a floating point number from 0.0 to 1.0 specifying how transparent the gradient is. .sp If \fIstopsList\fR is non-empty there must be at least two stops specified, and the first offset must be 0.0 and the last offset must be 1.0. Any other stop offsets must be listed in increasing order. Specifying opacity has no effect if gradients are drawn using Tk API calls. See \fBGRADIENTS\fR for more on this. .RE .TP \fIpathName\fR \fBgradient delete\fR ?\fIname ...\fR? Deletes each gradient specified by \fIname\fR. If the gradient is still being used then it is not actually deleted until all elements etc using the gradient have stopped using it. A deleted-but-in-use gradient is not recognized by the various gradient commands. Creating a new gradient with the same name as a deleted-but-in-use gradient resurrects the deleted gradient. .TP \fIpathName\fR \fBgradient names\fR Returns a list of names of all the gradients that have been created by this treectrl widget. .TP \fIpathName\fR \fBgradient native\fR ?\fIpreference\fR? Without any arguments, this command returns a boolean indicating whether or not the platform supports native transparent gradients. The \fIpreference\fR argument is a boolean that indicates whether native gradients should be used; this can be used to test the appearance of the application. .RE .TP \fIpathName\fR \fBheader\fR \fIoption\fR ?\fIarg ...\fR? This command is used to manipulate column headers. The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBheader\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBheader bbox\fR \fIheaderDesc\fR ?\fIcolumn\fR? ?\fIelement\fR? See the \fBitem bbox\fR command. .TP \fIpathName\fR \fBheader compare\fR \fIheaderDesc1\fR \fIop\fR \fIheaderDesc2\fR See the \fBitem compare\fR command. .TP \fIpathName\fR \fBheader configure\fR \fIheaderDesc\fR ?\fIarg ...\fR? There are two forms of this command distinguished by whether or not a \fBcolumn description\fR appears after the \fIheaderDesc\fR argument. If the first argument after \fIheaderDesc\fR begins with a '-' character it is assumed to be an option name, not a column description, in which case the command applies to the header-row. If the first argument after \fIheaderDesc\fR does not being with a '-' it is assumed to be a column description, in which case the command applies to a header-column. .RS .TP \fIpathName\fR \fBheader configure\fR \fIheaderDesc\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? If no \fIoption\fR is specified, returns a list describing all of the available options for the header given by \fIheaderDesc\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no value, 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 \fIoption\fR is specified). .sp If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given option(s) to have the given value(s); in this case the command returns an empty string. This is the only case where \fIheaderDesc\fR may refer to multiple header-rows. .sp The following options are supported by this command (see \fBheader create\fR for the meaning of each option): .RS .TP \fB\fB-height\fR\fR \fIheight\fR .TP \fB\fB-tags\fR\fR \fItagList\fR .TP \fB\fB-visible\fR\fR \fIboolean\fR .RE .TP \fIpathName\fR \fBheader configure\fR \fIheaderDesc\fR \fIcolumn\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? If no \fIoption\fR is specified, returns a list describing all of the available options for the single column \fIcolumn\fR of the header-row given by \fIheaderDesc\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no value, 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 \fIoption\fR is specified). .sp If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given option(s) to have the given value(s); in this case the command returns an empty string. This is the only case where both \fIheaderDesc\fR may refer to multiple header-rows and \fIcolumn\fR may refer to multiple header-columns. .sp The following options are supported by this command (see \fBHEADERS\fR) for the meaning of each option): .RS .TP \fB\fB-arrow\fR\fR \fIdirection\fR .TP \fB\fB-arrowbitmap\fR\fR \fIbitmap\fR .TP \fB\fB-arrowgravity\fR\fR \fIdirection\fR .TP \fB\fB-arrowimage\fR\fR \fIimage\fR .TP \fB\fB-arrowpadx\fR\fR \fIamount\fR .TP \fB\fB-arrowpady\fR\fR \fIamount\fR .TP \fB\fB-arrowside\fR\fR \fIside\fR .TP \fB\fB-background\fR\fR \fIcolor\fR .TP \fB\fB-bitmap\fR\fR \fIbitmap\fR .TP \fB\fB-borderwidth\fR\fR \fIsize\fR .TP \fB\fB-button\fR\fR \fIboolean\fR .TP \fB\fB-font\fR\fR \fIfontName\fR .TP \fB\fB-image\fR\fR \fIimage\fR .TP \fB\fB-imagepadx\fR\fR \fIamount\fR .TP \fB\fB-imagepady\fR\fR \fIamount\fR .TP \fB\fB-justify\fR\fR \fIjustification\fR .TP \fB\fB-state\fR\fR \fIstate\fR .TP \fB\fB-text\fR\fR \fItext\fR .TP \fB\fB-textcolor\fR\fR \fIcolor\fR .TP \fB\fB-textlines\fR\fR \fIcount\fR .TP \fB\fB-textpadx\fR\fR \fIamount\fR .TP \fB\fB-textpady\fR\fR \fIamount\fR .RE .RE .TP \fIpathName\fR \fBheader count\fR ?\fIheaderDesc\fR? If no additional arguments are given, the result is a decimal string giving the number of header-rows created by the \fBheader create\fR widget command which haven't been deleted by the \fBheader delete\fR widget command, plus 1 for the ever-present top header-row created along with the widget. If the optional argument \fIheaderDesc\fR is given, then the result is the number of header-rows that match that \fBheader description\fR. .TP \fIpathName\fR \fBheader create\fR ?\fIoption value\fR? Creates a new header-row and returns its unique identifier. The following configuration options are supported: .RS .TP \fB\fB-height\fR\fR \fIheight\fR Specifies a fixed height for the header-row in any of the forms acceptable to \fBTk_GetPixels\fR. Must be >= 0. If \fIheight\fR is zero then the header-row's height is the maximum height of all of its column headers. Defaults to 0. .TP \fB\fB-tags\fR\fR \fItagList\fR \fITagList\fR is a list of tag names to be added to the new header-row. The \fBheader tag\fR command can also be used to manipulate this list of tags. .TP \fB\fB-visible\fR\fR \fIboolean\fR \fIBoolean\fR must have one of the forms accepted by \fBTcl_GetBoolean\fR. It indicates whether or not the header-row should be displayed. If the widget option \fB-showheader\fR is false then the header-row will not be displayed regardless of the value of this option. .RE .TP \fIpathName\fR \fBheader delete\fR \fIheaderDesc\fR Deletes the header-rows given by the \fBheader description\fR \fIheaderDesc\fR. Attempts to delete the ever-present top header-row are ignored without raising an error. .TP \fIpathName\fR \fBheader dragcget\fR ?\fIarg ...\fR? There are two forms of this command distinguished by whether or not a \fBheader description\fR appears as the first argument. If the first argument begins with a '-' character it is assumed to be an option name, not a header description, in which case the command applies to the header-drag-and-drop options for the widget. If the first argument does not being with a '-' it is assumed to be a header description, in which case the command applies to a header-row. .RS .TP \fIpathName\fR \fBheader dragcget\fR \fIoption\fR This command returns the current value of the header-drag-and-drop option named \fIoption\fR for the widget. The following configuration options are supported (see \fBheader dragconfigure\fR for the meaning of each option): .RS .TP \fB\fB-enable\fR\fR \fIboolean\fR .TP \fB\fB-imagealpha\fR\fR \fIalpha\fR .TP \fB\fB-imagecolor\fR\fR \fIbackground\fR .TP \fB\fB-imagecolumn\fR\fR \fIcolumn\fR .TP \fB\fB-imageoffset\fR\fR \fIoffset\fR .TP \fB\fB-imagespan\fR\fR \fIcount\fR .TP \fB\fB-indicatorcolor\fR\fR \fIcolor\fR .TP \fB\fB-indicatorcolumn\fR\fR \fIcolumn\fR .TP \fB\fB-indicatorside\fR\fR \fIside\fR .TP \fB\fB-indicatorspan\fR\fR \fIcount\fR .RE .TP \fIpathName\fR \fBheader dragcget\fR \fIheaderDesc\fR \fIoption\fR This command returns the current value of the header-drag-and-drop option named \fIoption\fR for a header-row. The following configuration options are supported (see \fBheader dragconfigure\fR for the meaning of each option): .RS .TP \fB\fB-draw\fR\fR \fIboolean\fR .TP \fB\fB-enable\fR\fR \fIboolean\fR .RE .RE .TP \fIpathName\fR \fBheader dragconfigure\fR ?\fIarg ...\fR? There are two forms of this command distinguished by whether or not a \fBheader description\fR appears as the first argument. If the first argument begins with a '-' character it is assumed to be an option name, not a header description, in which case the command applies to the header-drag-and-drop options for the widget. If the first argument does not being with a '-' it is assumed to be a header description, in which case the command applies to a header-row. .RS .TP \fIpathName\fR \fBheader dragconfigure\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command queries and sets header-drag-and-drop options for the widget, not for individual header-rows. The following configuration options are supported: .RS .TP \fB\fB-enable\fR\fR \fIboolean\fR Controls whether the user is allowed to rearrange columns by drag-and-drop. The default is false. Each header-row also has an \fB-enable\fR dragconfigure option. .TP \fB\fB-imagealpha\fR\fR \fIalpha\fR \fIAlpha\fR is an integer from 0 (invisible) to 255 (opaque) controlling the transparency of the drag image. Any value outside this range is clipped. The default is 200. .TP \fB\fB-imagecolor\fR\fR \fIbackground\fR Unused. .TP \fB\fB-imagecolumn\fR\fR \fIcolumn\fR \fIColumn\fR specifies the column to create the drag image from. .TP \fB\fB-imageoffset\fR\fR \fIoffset\fR \fIOffset\fR is the horizontal screen distance the drag image is offset from its starting position. .TP \fB\fB-imagespan\fR\fR \fIcount\fR \fICount\fR is the number of columns, starting with -imagecolumn, that will be dragged as a group. .TP \fB\fB-indicatorcolor\fR\fR \fIcolor\fR Unused. .TP \fB\fB-indicatorcolumn\fR\fR \fIcolumn\fR The 2-pixel-thick line will be drawn over the left or right edge of \fIcolumn\fR. .TP \fB\fB-indicatorside\fR\fR \fIside\fR Unused. .TP \fB\fB-indicatorspan\fR\fR \fIcount\fR \fICount\fR is the number of columns, starting with -indicatorcolumn, that will be displaced as a group by the dragged column(s) .RE .TP \fIpathName\fR \fBheader dragconfigure\fR \fIheader\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command queries and sets header-drag-and-drop options for header-rows, not for the widget as a whole. The following configuration options are supported: .RS .TP \fB\fB-draw\fR\fR \fIboolean\fR Controls whether a header-row displays any feedback during header drag-and-drop. The default is true. .TP \fB\fB-enable\fR\fR \fIboolean\fR Controls whether clicking and dragging in this header-row initiates drag-and-drop. The default is true. If the \fB-enable\fR option for the \fIwidget\fR is false (see above) then this option has no effect. .RE .RE .TP \fIpathName\fR \fBheader element\fR ?\fIarg ...\fR? See the \fBitem element\fR command. .TP \fIpathName\fR \fBheader id\fR \fIheaderDesc\fR This command resolves the \fBheader description\fR \fIheaderDesc\fR into a list of unique header-row identifiers. If \fIheaderDesc\fR doesn't refer to any existing header-rows, then this command returns an empty list. .TP \fIpathName\fR \fBheader image\fR \fIheaderDesc\fR ?\fIcolumn\fR? ?\fIimage\fR? ?\fIcolumn image ...\fR? The behavior of this command depends on whether or not a column header was assigned a style containing an image element. If a column header has no style or no style with an image element then this command operates on the same -image option as \fBheader configure\fR. Otherwise this command operates on the -image option of the first image element in a column header's style. See the \fBitem image\fR command. .TP \fIpathName\fR \fBheader span\fR \fIheaderDesc\fR ?\fIcolumn\fR? ?\fInumColumns\fR? ?\fIcolumn numColumns ...\fR? See the \fBitem span\fR command. .TP \fIpathName\fR \fBheader state\fR \fIcommand\fR \fIheaderDesc\fR ?\fIarg ...\fR? See the \fBitem state\fR command. .TP \fIpathName\fR \fBheader style\fR \fIcommand\fR \fIheaderDesc\fR ?\fIarg ...\fR? See the \fBitem style\fR command. .TP \fIpathName\fR \fBheader text\fR \fIheaderDesc\fR ?\fIcolumn\fR? ?\fItext\fR? ?\fIcolumn text ...\fR? The behavior of this command depends on whether or not a column header was assigned a style containing a text element. If a column header has no style or no style with a text element then this command operates on the same -text option as \fBheader configure\fR. Otherwise this command operates on the -text option of the first text element in a column header's style. See \fBitem text\fR. .TP \fIpathName\fR \fBheader tag\fR \fIcommand\fR \fIheaderDesc\fR ?\fIarg ...\fR? See the \fBitem tag\fR command. .RE .TP \fIpathName\fR \fBidentify\fR ?\fI-array varName\fR? \fIx\fR \fIy\fR This command returns information about the what is displayed at the given window coordinates \fIx\fR and \fIy\fR. When the \fI-array\fR option is used to specify the name of an array variable, elements of the array variable are set as follows: .RS .IP [1] If the coordinates are outside the window, over the borders, or over any whitespace in the window, then: .sp $varName(where) is "" .IP [2] If the coordinates are over a column header, then: .sp $varName(where) is \fBheader\fR .sp $varName(header) is the unique id of the \fBheader-row\fR .sp $varName(column) is the unique id of the column .sp $varName(element) is the name of an \fBelement\fR, or "" .sp $varName(side) is \fBleft\fR or \fBright\fR if the coordinates are close to the edge of the column header, otherwise "" .IP [3] If the coordinates are over an item, then: .sp $varName(where) is \fBitem\fR .sp $varName(item) is the unique id of the item .sp $varName(column) is the unique id of the column .sp $varName(element) is the name of an \fBelement\fR, or "" .sp $varName(button) is a boolean indicating whether or not the coordinates are over the item's expand/collapse button .sp $varName(line) is the unique id of an ancestor of the item (but not the parent of the item) if the coordinates are over a line descending from that ancestor. If the coordinates are not over such a line then $varName(line) is "". This is used to collapse the ancestor when the line is clicked on. .RE When the \fI-array\fR option is not used, this command returns a list describing what is displayed at the given window coordinates. The format of this list can be like one of the following: .RS .IP [1] {} .sp An empty list is returned if the coordinates are outside the window, over the borders, or over any whitespace in the window. .IP [2] \fBheader\fR C ?\fBleft\fR|\fBright\fR? .sp \fBheader\fR C \fBelem\fR E ?\fBleft\fR|\fBright\fR? .sp \fBheader\fR H \fBcolumn\fR C ?\fBleft\fR|\fBright\fR? .sp \fBheader\fR H \fBcolumn\fR C \fBelem\fR E ?\fBleft\fR|\fBright\fR? .sp Only when there is more than one \fBheader-row\fR is there a unique id of a header-row \fIH\fR followed by the keyword \fBcolumn\fR. This is for compatibility with older versions when there was only one row of column headers allowed. .IP [3] \fBitem\fR I \fBcolumn\fR C .IP [4] \fBitem\fR I \fBcolumn\fR C \fBelem\fR E .IP [5] \fBitem\fR I \fBbutton\fR .sp This is the result when the coordinates are over the expand/collapse button next to an item. .IP [6] \fBitem\fR I \fBline\fR I2 .sp This is the result when the coordinates are over a line descending from an ancestor \fII2\fR of the item \fII\fR (but not the parent of that item). This is used to collapse the ancestor when the line is clicked on. .RE .TP \fIpathName\fR \fBindex\fR \fIitemDesc\fR Deprecated. Use \fBitem id\fR instead. .TP \fIpathName\fR \fBitem\fR \fIoption\fR ?\fIarg ...\fR? This command is used to manipulate items. The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBitem\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBitem ancestors\fR \fIitemDesc\fR Returns a list containing the item ids of the ancestors of the item specified by \fIitemDesc\fR. The first list value is the parent, the second is the parent's parent, an so on. The last list value will be the root item if \fIitemDesc\fR is a descendant of the root item. .TP \fIpathName\fR \fBitem bbox\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fIelement\fR? Returns a list with four elements giving the bounding box of the item described by \fIitemDesc\fR. If no further argument is specified, the bbox spans the area of the item over all non-locked columns. If a \fIcolumn\fR is specified, only the area of the item in this column is considered. If an additional \fIelement\fR is specified, the area of this \fIelement\fR in \fIcolumn\fR of the specified item is returned. The returned coordinates are relative to the top-left corner of the widget. If the item is not visible for any reason, the result in an empty string. .TP \fIpathName\fR \fBitem buttonstate\fR \fIitemDesc\fR ?\fIstate\fR? If \fIstate\fR is specified, this command sets the state of the expand/collapse button for the single item specified by \fIitemDesc\fR. The \fIstate\fR argument may be one of \fBactive\fR, \fBnormal\fR or \fBpressed\fR. The current (or newly-set) state of the button is returned. The button state is used by the system theme, if any, to change the appearance of the button. .TP \fIpathName\fR \fBitem cget\fR \fIitemDesc\fR \fIoption\fR Returns the current value of the configuration option for the item specified by \fIitemDesc\fR whose name is \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBitem configure\fR command. .TP \fIpathName\fR \fBitem children\fR \fIitemDesc\fR Returns a list containing the item ids of all children of the item specified by \fIitemDesc\fR in the correct order from the first child to the last child. .TP \fIpathName\fR \fBitem collapse\fR \fIitemDesc\fR ?\fB-animate\fR? ?\fB-recurse\fR? Switches off the \fBopen\fR state of the item(s) described by \fIitemDesc\fR. If an item has descendants, then they are no longer displayed. If an item is already closed, then this command has no effect on that item. If \fB-animate\fR is specified, then the item's button will animate as it transitions between states if the theme supports it; in this case only one item may be specified. If \fB-recurse\fR is specified, then all descendants of the items described by \fIitemDesc\fR will also be collapsed. For every item that actually will be collapsed, two events are generated: a \fB\fR event before the item state is changed, and a \fB\fR event after the item state was changed. .TP \fIpathName\fR \fBitem compare\fR \fIitemDesc1\fR \fIop\fR \fIitemDesc2\fR From both items described by the \fIitemDesc\fRs the index is retrieved (as returned from the \fBitem order\fR widget command). Then these indexes are compared using the operator \fIop\fR, which must be either \fB<\fR, \fB<=\fR, \fB==\fR, \fB>=\fR, \fB>\fR, or \fB!=\fR. The return value of this command is 1 if the comparison evaluated to true, 0 otherwise. .TP \fIpathName\fR \fBitem complex\fR \fIitemDesc\fR ?\fIlist...\fR? This horrible command is now deprecated. Use \fBitem element configure\fR instead. For every column of the treectrl there may be specified one \fIlist\fR. Each \fIlist\fR should look like this: .nf { {element option value ...} {element option value ...} ...} .fi Every \fIoption\fR must be known by the element's type (see \fBELEMENTS AND STYLES\fR below). Each \fIoption\fR will be set to \fIvalue\fR for the element in this one column in this item. .TP \fIpathName\fR \fBitem configure\fR \fIitemDesc\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? If no \fIoption\fR is specified, returns a list describing all of the available options for the item given by \fIitemDesc\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no value, 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 \fIoption\fR is specified). .sp If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given item option(s) to have the given value(s); in this case the command returns an empty string. This is the only case where \fIitemDesc\fR may refer to multiple items. .sp The following options are supported by this command (see \fBitem create\fR for the meaning of each option): .RS .TP \fB\fB-button\fR\fR \fIboolean|auto\fR .TP \fB\fB-height\fR\fR \fIheight\fR .TP \fB\fB-tags\fR\fR \fItagList\fR .TP \fB\fB-visible\fR\fR \fIboolean\fR .TP \fB\fB-wrap\fR\fR \fIboolean\fR .RE .TP \fIpathName\fR \fBitem count\fR ?\fIitemDesc\fR? If no additional arguments are given, the result is a decimal string giving the number of items created by the \fBitem create\fR widget command which haven't been deleted by the \fBitem delete\fR widget command, plus 1 for the ever-present root item. If the optional argument \fIitemDesc\fR is given, then the result is the number of items that match that \fBitem description\fR. .TP \fIpathName\fR \fBitem create\fR ?\fIoption value ...\fR? Creates some new items and optionally returns a list of unique identifiers for those items. The new items have the states \fBopen\fR and \fBenabled\fR set by default. If the treectrl widget currently has the focus, the state \fBfocus\fR is also set. .sp The following options are supported by this command: .RS .TP \fB\fB-button\fR\fR \fIboolean|auto\fR The value of this option must have one of the forms accepted by \fBTcl_GetBoolean\fR or be the word \fBauto\fR (or any abbreviation of it). It indicates whether or not an expand/collapse button should be drawn next to the item, typically to indicate that the item has children. If the value of this option is \fBauto\fR, then a button is displayed next to the item whenever the item has any children whose item option \fB-visible\fR is true. The button will only be displayed if: .RS .IP [1] the column specified by the treectrl option \fB-treecolumn\fR is visible, and .IP [2] the treectrl option \fB-showbuttons\fR is true, and .IP [3] for the root item, the treectrl option \fB-showrootbutton\fR is true, and .IP [4] for immediate children of the root item, the treectrl option \fB-showrootchildbuttons\fR is true. .RE .TP \fB\fB-count\fR\fR \fInumItems\fR Specifies the number of items to create. Must be >= 0. Defaults to 1. .TP \fB\fB-enabled\fR\fR \fIboolean\fR Specifies whether the items should be enabled. Default is true. .TP \fB\fB-height\fR\fR \fIheight\fR Specifies a fixed height in any of the forms acceptable to \fBTk_GetPixels\fR. Must be >= 0. If \fIheight\fR is zero then the item's height is unspecified. Defaults to 0. See also the widget options \fB-itemheight\fR and \fB-minitemheight\fR. .TP \fB\fB-nextsibling\fR\fR \fIitemDesc\fR Specifies the item before which the new items will be inserted. The new items will have the same parent as \fIitemDesc\fR. .TP \fB\fB-open\fR\fR \fIboolean\fR Specifies whether the items should be open or closed. Default is true. .TP \fB\fB-parent\fR\fR \fIitemDesc\fR Specifies the item which the new items will be the children of. The new items will be appended to the list of children of \fIitemDesc\fR. When no parent is specified, the new items are \fIorphan\fR items (see the widget command \fBorphans\fR) and will not be displayed in the list. .TP \fB\fB-prevsibling\fR\fR \fIitemDesc\fR Specifies the item after which the new items will be inserted. The new items will have the same parent as \fIitemDesc\fR. .TP \fB\fB-returnid\fR\fR \fIboolean\fR Specifies whether or not to return a list of item identifiers for the newly created items. Specifying false is useful when creating a large number of items in the console or to improve performance. Default is true. .TP \fB\fB-tags\fR\fR \fItagList\fR \fITagList\fR is a list of tag names to be added to the new items. The \fBitem tag\fR command can also be used to manipulate this list of tags. .TP \fB\fB-visible\fR\fR \fIboolean\fR \fIBoolean\fR must have one of the forms accepted by \fBTcl_GetBoolean\fR. It indicates that the item should be displayed in the list. The item will only be displayed if: .RS .IP [1] each ancestor is a descendant of the root item (not an orphan), and .IP [2] each ancestor's \fB-visible\fR option is true .RE .TP \fB\fB-wrap\fR\fR \fIboolean\fR \fIBoolean\fR must have one of the forms accepted by \fBTcl_GetBoolean\fR. It indicates that this item should be the first one in a horizontal range or vertical range of items. See also the widget option \fB-wrap\fR. .RE .TP \fIpathName\fR \fBitem delete\fR \fIfirst\fR ?\fIlast\fR? Deletes the specified item(s). \fIFirst\fR and \fIlast\fR must be valid \fBitem descriptions\fR. If \fIlast\fR isn't specified, then \fIfirst\fR may specify multiple items. If both \fIfirst\fR and \fIlast\fR are specified, they must each decribe a single item with a common ancestor; then the range of items between \fIfirst\fR and \fIlast\fR is deleted. The order of \fIfirst\fR and \fIlast\fR doesn't matter. .sp Deleting an item deletes any child items of the deleted item recursively. If the current \fBactive\fR item is deleted, the root item becomes the new active item. If the current selection \fBanchor\fR item is deleted, the root item becomes the new anchor item. There is no way to delete the root item of the treectrl widget; in all cases the specification of the root item is ignored. .sp For each call to this command, two events may be generated. If any of the deleted items are selected, then they are removed from the selection and a \fB\fR event is generated just before the items are deleted. If any items are going to be deleted, then an \fB\fR event is generated just before the items are deleted. .TP \fIpathName\fR \fBitem descendants\fR \fIitemDesc\fR Returns a list containing the item ids of the descendants of the item specified by \fIitemDesc\fR, i.e. the children, grandchildren, great-grandchildren etc, of the item. .TP \fIpathName\fR \fBitem dump\fR \fIitemDesc\fR Debug command. Returns a list with 4 words in the form \fBindex\fR \fIindex\fR \fBindexVis\fR \fIindexVis\fR. .TP \fIpathName\fR \fBitem element\fR \fIcommand\fR \fIitemDesc\fR \fIcolumn\fR \fIelement\fR ?\fIarg ...\fR? This command is used to manipulate elements of the item. The exact behavior of the command depends on the \fIcommand\fR argument that follows the \fBelement\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBitem element actual\fR \fIitemDesc\fR \fIcolumn\fR \fIelement\fR \fIoption\fR Deprecated. Use \fBitem element perstate\fR instead. .TP \fIpathName\fR \fBitem element cget\fR \fIitemDesc\fR \fIcolumn\fR \fIelement\fR \fIoption\fR This command returns the value of the option named \fIoption\fR associated with \fIelement\fR inside \fIcolumn\fR of the item described by \fIitemDesc\fR, if it was already configured for the actual item. \fIOption\fR may have any of the values accepted by the type of the specified element (see \fBELEMENTS AND STYLES\fR below) .TP \fIpathName\fR \fBitem element configure\fR \fIitemDesc\fR \fIcolumn\fR \fIelement\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command modifies configuration options for an element in a column of an item. If no \fIoption\fR is specified, the command returns a list describing all of the available options for the element (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, 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 \fIoption\fR is specified). .sp If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given option(s) to have the given value(s) in the \fIelement\fR inside \fIcolumn\fR of the item(s) described by \fIitemDesc\fR; in this case the command returns an empty string. This is the only case where \fIitemDesc\fR may refer to multiple items. .sp It is possible to configure multiple elements in multiple columns with a single call. To configure another element in the same column, append a \'\fB+\fR' argument followed by the element name. To configure elements in another column, append a '\fB,\fR' argument followed by the column. For example: .nf .t item element configure $I \\ $C1 $E1 -text "hello" + $E2 -text "world" , \\ $C2 $E3 -fill Blue , \\ $C3 $E1 -text "apples and oranges" .fi Each of the \fBcolumn description\fR arguments to this command may refer to multiple columns if at least one \fIoption\fR-\fIvalue\fR pair is given. .TP \fIpathName\fR \fBitem element perstate\fR \fIitemDesc\fR \fIcolumn\fR \fIelement\fR \fIoption\fR ?\fIstateList\fR? This command returns the current value of the \fBper-state\fR option named \fIoption\fR for \fIelement\fR inside \fIcolumn\fR of the item described by \fIitemDesc\fR. If \fIstateList\fR is specified, the list of state names (static and dynamic, see \fBSTATES\fR) is used in place of the current state for \fIitem\fR and \fIcolumn.\fR .RE .TP \fIpathName\fR \fBitem enabled\fR \fIitemDesc\fR ?\fIboolean\fR? Returns 1 if the item described by \fIitemDesc\fR has the state \fBenabled\fR switched on, 0 otherwise. If \fIboolean\fR is specified, then the \fBenabled\fR state of every item described by the \fBitem description\fR \fIitemDesc\fR is set accordingly. New items are enabled by default when created. Disabled items cannot be selected, and are ignored by the default key-navigation and mouse bindings. .TP \fIpathName\fR \fBitem expand\fR \fIitemDesc\fR ?\fB-animate\fR? ?\fB-recurse\fR? Switches on the \fBopen\fR state of the item(s) described by \fIitemDesc\fR. If an item has descendants, then they are now displayed. If an item is already open, then this command has no effect on that item. If \fB-animate\fR is specified, then the item's button will animate as it transitions between states if the theme supports it; in this case only one item may be specified. If \fB-recurse\fR is specified, then all descendants of the items described by \fIitemDesc\fR will also be expanded. For every item that actually will be expanded, two events are generated: an \fB\fR event before the item state is changed, and an \fB\fR event after the item state was changed. .TP \fIpathName\fR \fBitem firstchild\fR \fIparent\fR ?\fIchild\fR? If \fIchild\fR is not specified, returns the item id of the first child of the item described by \fIparent\fR. If \fIchild\fR is specified, it must describe an item that is neither the root item nor an ancestor of \fIparent\fR. Then it will become the new first child of \fIparent\fR. .TP \fIpathName\fR \fBitem id\fR \fIitemDesc\fR This command resolves the \fBitem description\fR \fIitemDesc\fR into a list of unique item identifiers. If \fIitemDesc\fR doesn't refer to any existing items, then this command returns an empty list. .TP \fIpathName\fR \fBitem image\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fIimage\fR? ?\fIcolumn image ...\fR? This command sets or retrieves the value of the \fBper-state\fR -image option for the first image element in one or more columns. If no \fIcolumn\fR is specified, this command returns a list of values, one per column. If no \fIimage\fR is specified, this command returns the value for \fIcolumn\fR. .sp If one or more \fIcolumn\fR-\fIimage\fR pairs is specified, then the value of the -image option in each \fIcolumn\fR is set to \fIimage\fR. In this case \fIitemDesc\fR may refer to multiple items and each \fIcolumn\fR may refer to multiple columns. .sp Note that this command is provided as a convenience. Use the \fBitem element configure\fR or \fBitem element cget\fR commands if you want to set or retrieve the value of the -image option for a specific image element. .TP \fIpathName\fR \fBitem isancestor\fR \fIitemDesc\fR \fIdescendant\fR Returns 1 if the item described by \fIitemDesc\fR is a direct or indirect parent of the item decribed by \fIdescendant\fR, 0 otherwise. .TP \fIpathName\fR \fBitem isopen\fR \fIitemDesc\fR Returns 1 if the item described by \fIitemDesc\fR has the state \fBopen\fR switched on, 0 otherwise. .TP \fIpathName\fR \fBitem lastchild\fR \fIparent\fR ?\fIchild\fR? If \fIchild\fR is not specified, returns the item id of the last child of the item described by \fIparent\fR. If \fIchild\fR is specified, it must describe an item that is not an ancestor of \fIparent\fR. Then it will become the new last child of \fIparent\fR. .TP \fIpathName\fR \fBitem nextsibling\fR \fIsibling\fR ?\fInext\fR? If \fInext\fR is not specified, returns the item id of the next sibling of the item described by \fIsibling\fR. If \fInext\fR is specified, it must describe an item that is not an ancestor of \fIsibling\fR. Then it will become the new next sibling of \fIsibling\fR. .TP \fIpathName\fR \fBitem numchildren\fR \fIitemDesc\fR Returns the number of children of the item described by \fIitemDesc\fR. .TP \fIpathName\fR \fBitem order\fR \fIitemDesc\fR ?\fI-visible\fR? This command returns the position of the item \fIitemDesc\fR relative to its toplevel ancestor (usually the root item, unless the ancestor is an orphan). If you imagine all the items flattened into a vertical list, the result of this command is the row the item falls in. If the optional argument \fI-visible\fR is given, only the items whose ancestors are expanded, and whose -visible option is true, get counted; in this case -1 is returned if the item is not visible. .TP \fIpathName\fR \fBitem parent\fR \fIitemDesc\fR Returns the item id of the parent of the item described by \fIitemDesc\fR. .TP \fIpathName\fR \fBitem prevsibling\fR \fIsibling\fR ?\fIprev\fR? If \fIprev\fR is not specified, returns the item id of the previous sibling of the item described by \fIsibling\fR. If \fIprev\fR is specified, it must describe an item that is not an ancestor of \fIsibling\fR. Then it will become the new previous sibling of \fIsibling\fR. .TP \fIpathName\fR \fBitem range\fR \fIfirst\fR \fIlast\fR Returns a list containing the item ids of all items in the range between \fIfirst\fR and \fIlast\fR, inclusive. The order between \fIfirst\fR and \fIlast\fR doesn't matter, and the result is always sorted by the increasing order of the items (as returned by the \fBitem order\fR command). The items specified by \fIfirst\fR and \fIlast\fR must share a common ancestor. .TP \fIpathName\fR \fBitem remove\fR \fIitemDesc\fR Removes the item described by \fIitemDesc\fR from the list of children of its parent, so that it will become an orphan. .TP \fIpathName\fR \fBitem rnc\fR \fIitemDesc\fR Returns a list of two integers, which corresponds to the row and column of the item described by \fIitemDesc\fR. The row and column corresponds to the on-screen arrangement of items as determined by the -orient and -wrap options. If the item is not displayed, this command returns an empty string. .TP \fIpathName\fR \fBitem sort\fR \fIitemDesc\fR ?\fIoption ...\fR? Sorts the children of the item described by \fIitemDesc\fR, and redisplays the tree with the items in the new order. .sp The range of items which should be sorted can be restricted by means of the \fB-first\fR and/or \fB-last\fR options, which should be children of the item described by \fIitemDesc\fR; the order between these two limiting items doesn't matter. .sp The sort column can be specified by means of the \fB-column\fR option; this option can be used repeatedly to define a multicolumn sort. The sorting is done by looking at the \fItext\fR of the element specified by the \fB-element\fR option, which must be a text element defined in the style of the sorting column, by default the first text element is used. .sp If the \fB-notreally\fR option is specified, no rearranging of the items is done; instead the sorted items are returned as result of the command. .sp By default ASCII sorting is used with the result returned in increasing order. Any of the following options may be specified to control the sorting process of the previously specified column (unique abbreviations are accepted): .RS .TP \fB\fB-ascii\fR\fR Use string comparison with ASCII collation order. This is the default. .TP \fB\fB-command\fR\fR \fIcommand\fR Use \fIcommand\fR as a comparison command. To compare two items, evaluate a Tcl script consisting of \fIcommand\fR with the numerical ids of the two items appended as additional arguments. The script should return an integer less than, equal to, or greater than zero if the first item is to be considered less than, equal to, or greater than the second, respectively. .TP \fB\fB-decreasing\fR\fR Sort the items in decreasing order ("largest" items first). .TP \fB\fB-dictionary\fR\fR Use dictionary-style comparison. This is the same as \fB-ascii\fR except (a) case is ignored except as a tie-breaker and (b) if two strings contain embedded numbers, the numbers compare as integers, not characters. For example, in \fB-dictionary\fR mode, \fIbigBoy\fR sorts between \fIbigbang\fR and \fIbigboy\fR, and \fIx10y\fR sorts between \fIx9y\fR and \fIx11y\fR. .TP \fB\fB-increasing\fR\fR Sort the items in increasing order ("smallest" items first). This is the default. .TP \fB\fB-integer\fR\fR Convert to integers and use integer comparison. .TP \fB\fB-real\fR\fR Convert to floating-point values and use floating comparison. .RE .TP \fIpathName\fR \fBitem span\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fInumColumns\fR? ?\fIcolumn numColumns ...\fR? This command sets or retrieves the number of columns that a style covers. If no \fIcolumn\fR is specified, the return value is a list of spans, one per column. If no \fInumColumns\fR is specified, the return value is the span for \fIcolumn\fR. .sp If one or more \fIcolumn\fR-\fInumColumns\fR pairs is specified, the span for each \fIcolumn\fR is set to \fInumColumns\fR. In this case \fIitemDesc\fR may refer to multiple items and each \fIcolumn\fR may refer to multiple columns. .TP \fIpathName\fR \fBitem state\fR \fIcommand\fR \fIitemDesc\fR ?\fIarg ...\fR? This command is used to manipulate the states of an item. The exact behavior of the command depends on the \fIcommand\fR argument that follows the \fBstyle\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBitem state define\fR \fIstateName\fR Defines a new state with the name \fIstateName\fR, which must not be the name of an existing state. .TP \fIpathName\fR \fBitem state forcolumn\fR \fIitemDesc\fR \fIcolumn\fR ?\fIstateDescList\fR? Just like \fBitem state set\fR but manipulates dynamic states for a single item column, not the item as a whole. If \fIstateDescList\fR is unspecified, this command returns a list containing the names of all the dynamic states which are switched on in \fIcolumn\fR. .sp If \fIstateDescList\fR is specified, then \fIitemDesc\fR may refer to multiple items and \fIcolumn\fR may refer to multiple columns. .TP \fIpathName\fR \fBitem state get\fR \fIitemDesc\fR ?\fIstateName\fR? If no \fIstateName\fR is specified, returns a list containing the names of all (static and dynamic) states which are currently switched on for the item described by \fIitemDesc\fR. If a \fIstateName\fR is specified, 1 is returned if the specified state is currently switched on for the item, 0 otherwise. .TP \fIpathName\fR \fBitem state linkage\fR \fIstateName\fR Returns a string indicating whether the specified state is user-defined by means of the \fBitem state define\fR widget command (\fBdynamic\fR) or predefined by the treectrl widget itself (\fBstatic\fR). .TP \fIpathName\fR \fBitem state names\fR Returns a list containing the names of all user-defined states. .TP \fIpathName\fR \fBitem state set\fR \fIitemDesc\fR ?\fIlastItem\fR? \fIstateDescList\fR Every element of \fIstateDescList\fR must be the name of a dynamic state (see \fBSTATES\fR below), optionally preceded by a \fB~\fR or \fB!\fR character. Every state with a leading \fB!\fR will be switched off for the item described by \fIitemDesc\fR, every state with a leading \fB~\fR will be toggled, and every state without leading \fB!\fR or \fB~\fR will be switched on. If \fIlastItem\fR is specified, the state changes will be made for all items in the range between \fIitemDesc\fR and \fIlastItem\fR. If \fIlastItem\fR unspecified, then the state changes are made for all items described by \fIitemDesc\fR. .TP \fIpathName\fR \fBitem state undefine\fR ?\fIstateName ...\fR? Every \fIstateName\fR must be the name of a user-defined state. Removes this state from the list of user-defined states. .RE .TP \fIpathName\fR \fBitem style\fR \fIcommand\fR \fIitemDesc\fR ?\fIarg ...\fR? This command is used to manipulate the styles of an item. The exact behavior of the command depends on the \fIcommand\fR argument that follows the \fBstyle\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBitem style elements\fR \fIitemDesc\fR \fIcolumn\fR This command returns a list containing the names of elements which were configured by the \fBitem element configure\fR command for the item described by \fIitemDesc\fR in \fIcolumn\fR. If there is no style assigned to \fIcolumn\fR an error is returned. .TP \fIpathName\fR \fBitem style map\fR \fIitemDesc\fR \fIcolumn\fR \fIstyle\fR \fImap\fR Like the \fBitem style set\fR command, this command may be used to assign a style to a specific column of an item. Unlike \fBitem style set\fR, this command can transfer configuration values of elements in the current style to elements in the new style specified by \fIstyle\fR. \fIMap\fR must be a list of \fIelementOld\fR-\fIelementNew\fR pairs, where \fIelementOld\fR is an element in the current style, and \fIelementNew\fR is an element in the style specified by \fIstyle\fR. Both \fIelementOld\fR and \fIelementNew\fR must be of the same type (\fBbitmap\fR, \fBtext\fR etc). \fIItemDesc\fR may refer to multiple items and \fIcolumn\fR may refer to multiple columns. .TP \fIpathName\fR \fBitem style set\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fIstyle\fR? ?\fIcolumn style ...\fR? This command sets or retrieves the style assigned to one or more columns. If no \fIcolumn\fR is specified, this command returns a list containing the names of the styles set for all columns of the item described by \fIitemDesc\fR. If no \fIstyle\fR is specified, this command returns the name of the style set for the item described by \fIitemDesc\fR in \fIcolumn\fR. .sp If one or more \fIcolumn\fR-\fIstyle\fR pairs is specified, then the style in each \fIcolumn\fR is set to \fIstyle\fR. In this case \fIitemDesc\fR may refer to multiple items and each \fIcolumn\fR may refer to multiple columns. .RE .TP \fIpathName\fR \fBitem tag\fR \fIoption\fR ?\fIarg arg ...\fR? This command is used to manipulate tags on items. The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBitem tag\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBitem tag add\fR \fIitemDesc\fR \fItagList\fR Adds each tag in \fItagList\fR to the items specified by the \fBitem description\fR \fIitemDesc\fR. Duplicate tags are ignored. The list of tags for an item can also be changed via an item's \fB-tags\fR option. .TP \fIpathName\fR \fBitem tag expr\fR \fIitemDesc\fR \fItagExpr\fR Evaluates the tag expression \fItagExpr\fR against every item specified by the \fBitem description\fR \fIitemDesc\fR. The result is 1 if the tag expression evaluates to true for every item, 0 otherwise. .TP \fIpathName\fR \fBitem tag names\fR \fIitemDesc\fR Returns a list of tag names assigned to the items specified by the \fBitem description\fR \fIitemDesc\fR. The result is the union of any tags assigned to the items. .TP \fIpathName\fR \fBitem tag remove\fR \fIitemDesc\fR \fItagList\fR Removes each tag in \fItagList\fR from the items specified by the \fBitem description\fR \fIitemDesc\fR. It is not an error if any of the items do not use any of the tags. The list of tags for an item can also be changed via an item's \fB-tags\fR option. .RE .TP \fIpathName\fR \fBitem text\fR \fIitemDesc\fR ?\fIcolumn\fR? ?\fItext\fR? ?\fIcolumn text ...\fR? This command sets or retrieves the value of the -text option for the first text element in one or more columns. If no \fIcolumn\fR is specified, this command returns a list of values, one per column. If no \fItext\fR is specified, this command returns the value for \fIcolumn\fR. .sp If one or more \fIcolumn\fR-\fItext\fR pairs is specified, then the value of the -text option in each \fIcolumn\fR is set to \fItext\fR. In this case \fIitemDesc\fR may refer to multiple items and each \fIcolumn\fR may refer to multiple columns. .sp Note that this command is provided as a convenience. Use the \fBitem element configure\fR or \fBitem element cget\fR commands if you want to set or retrieve the value of the -text option for a specific text element. .TP \fIpathName\fR \fBitem toggle\fR \fIitemDesc\fR ?\fB-animate\fR? ?\fB-recurse\fR? Changes the \fBopen\fR state of the item(s) described by \fIitemDesc\fR. If the \fBopen\fR state is currently switched off, then this command does the same as the \fBitem expand\fR widget command; otherwise the same as the \fBitem collapse\fR widget command. If \fB-animate\fR is specified, then the item's button will animate as it transitions between states if the theme supports it; in this case only one item may be specified. If \fB-recurse\fR is specified, then the \fBopen\fR state of all descendants of the items described by \fIitemDesc\fR will also be toggled. .RE .TP \fIpathName\fR \fBmarquee\fR \fIoption\fR ?\fIarg ...\fR? This command is used to manipulate the marquee, which can be used to implement a resizable selection rectangle, in a file browser for example. One corner point of the marquee is fixed as long as the marquee is visible and called the anchor; the diagonally opposite corner is dragged with the mouse while resizing the marquee and simply called the corner. .sp All coordinates handled by this widget command are \fBcanvas\fR coordinates, i.e. the \fBcanvasx\fR or \fBcanvasy\fR widget command should be used to translate window coordinates to canvas coordinates. .sp By default, the marquee is displayed as a 1-pixel thick dotted rectangle. If either of the \fB-fill\fR or \fB-outline\fR options is specified, then the marquee is drawn as a filled and/or outlined rectangle of the specified color(s). The \fB-fill\fR option should specify a transparent gradient to avoid hiding what is inside the marquee. See \fBGRADIENTS\fR for more info. .sp The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBmarquee\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBmarquee anchor\fR ?\fIx y\fR? Returns a list containing the x and y coordinates of the anchor, if no additional arguments are specified. If two coordinates are specified, sets the anchor to the given coordinates \fIx\fR and \fIy\fR. .TP \fIpathName\fR \fBmarquee cget\fR \fIoption\fR This command returns the current value of the marquee option named \fIoption\fR. \fIOption\fR may have any of the values accepted by the \fBmarquee configure\fR widget command. .TP \fIpathName\fR \fBmarquee configure\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command is similar to the \fBconfigure\fR widget command except that it modifies the marquee options instead of modifying options for the overall treectrl widget. If no \fIoption\fR is specified, the command returns a list describing all of the available marquee options (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, then the command returns a list describing the one named marquee option (this list will be identical to the corresponding sublist of the value returned if no \fIoption\fR is specified). If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given marquee option(s) to have the given value(s); in this case the command returns an empty string. .sp The following marquee options are supported: .RS .TP \fB\fB-fill\fR\fR \fIcolor\fR Specifies the color to fill the marquee rectangle with. See the comments above about using a transparent gradient here. .TP \fB\fB-outline\fR\fR \fIcolor\fR Specifies the color to outline the marquee rectangle with. .TP \fB\fB-outlinewidth\fR\fR \fIcolor\fR Specifies the width of the outline drawn inside the marquee's rectangle. The outline is not drawn if this value is less than 1. This option has no effect if the \fB-outline\fR option is unspecified, i.e., the default dotted rectangle is unaffected by this option. \fIoutlineWidth\fR may be in any of the forms acceptable to \fBTk_GetPixels\fR. Defaults to 1. .TP \fB\fB-visible\fR\fR \fIboolean\fR Specifies a boolean value which determines whether the marquee is displayed. .RE .TP \fIpathName\fR \fBmarquee coords\fR ?\fIx1 y1 x2 y2\fR? Returns a list containing the x and y coordinates of the anchor followed by the x and y coordinates of the corner, if no additional arguments are specified. If four coordinates are specified, sets the anchor to the given coordinates \fIx1\fR and \fIy1\fR and the corner to the coordinates \fIx2\fR and \fIy2\fR. .TP \fIpathName\fR \fBmarquee corner\fR ?\fIx y\fR? Returns a list containing the x and y coordinates of the corner, if no additional arguments are specified. If two coordinates are specified, sets the corner to the given coordinates \fIx\fR and \fIy\fR. .TP \fIpathName\fR \fBmarquee identify\fR Returns a list with information about any items intersecting the marquee. The format of the returned list is: .nf { {item {column element element ...} {column element element ...} ...} {item {column element element ...} {column element element ...} ...} ... } .fi There may be zero sublists following an item id if the marquee is in the button/line area of an item. There may be zero element names following a column id if the item-column has no style or if the marquee does not intersect any elements in that column. .RE .TP \fIpathName\fR \fBnotify\fR \fIoption\fR ?\fIarg ...\fR? Many Tk widgets communicate with the outside world via \fB-command\fR callbacks and/or virtual events. For example, the Text widget evaluates its \fB-yscrollcommand\fR when the view in the widget changes, and generates a <> virtual event when text is inserted or deleted. A treectrl widget replaces both methods of communication with its own event mechanism accessed through the \fBnotify\fR subcommands. .sp The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBnotify\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBnotify bind\fR ?\fIobject\fR? ?\fIpattern\fR? ?+??\fIscript\fR? This command associates Tcl scripts with events generated by a treectrl widget. If all three arguments are specified, \fBnotify bind\fR will arrange for \fIscript\fR (a Tcl script) to be evaluated whenever the event(s) specified by \fIpattern\fR are generated by this treectrl widget. If \fIscript\fR is prefixed with a "+", then it is appended to any existing binding for \fIpattern\fR; otherwise \fIscript\fR replaces any existing binding. If \fIscript\fR is an empty string then the current binding for \fIpattern\fR is destroyed, leaving \fIpattern\fR unbound. In all of the cases where a script argument is provided, \fBnotify bind\fR returns an empty string. .sp If \fIpattern\fR is specified without a \fIscript\fR, then the script currently bound to \fIpattern\fR is returned, or an empty string is returned if there is no binding for \fIpattern\fR. If neither \fIpattern\fR nor \fIscript\fR is specified, then the return value is a list whose elements are all the patterns for which there exist bindings for \fIobject\fR. .sp The \fIobject\fR argument determines which window(s) the binding applies to. If \fIobject\fR begins with a dot, as in .a.b.c, then it must be the path name for a window; otherwise it may be an arbitrary string. Like the regular \fBbind\fR command, bindings on window names are automatically removed if that window is destroyed. .TP \fIpathName\fR \fBnotify configure\fR \fIobject\fR \fIpattern\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command sets and retrieves options for bindings created by the \fBnotify bind\fR command. .sp If no \fIoption\fR is specified, the command returns a list with \fIoption\fR-\fIvalue\fR pairs describing all the available binding options for \fIpattern\fR on \fIobject\fR. If \fIoption\fR is specified with no \fIvalue\fR, then the command returns the current value of that option. If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given option(s) to have the given value(s) for the binding; in this case the command returns an empty string. .sp The following binding options are supported: .RS .TP \fB\fB-active\fR\fR \fIboolean\fR Specifies if the binding should be active. As long as this option is specified as false, a binding script will not be evaluated when the corresponding event is generated. .RE .TP \fIpathName\fR \fBnotify detailnames\fR \fIeventName\fR Returns a list containing the names of all details, which are installed for the event with the name \fIeventName\fR by means of the \fBnotify install\fR widget command or by the treectrl widget itself. .TP \fIpathName\fR \fBnotify eventnames\fR Returns a list containing the names of all events, which are installed by means of the \fBnotify install\fR widget command or by the treectrl widget itself. .TP \fIpathName\fR \fBnotify generate\fR \fIpattern\fR ?\fIcharMap\fR? ?\fIpercentsCommand\fR? This command causes the treectrl widget to generate an event. This command is typically used to generate dynamic events created by the \fBnotify install\fR command, but may be used to generate static events also. The event specified by \fIpattern\fR is generated, and any active binding scripts on the event are evaluated after undergoing %-substitution. If there are details defined for the event, \fIpattern\fR must describe an <\fIeventName\fR-\fIdetail\fR> pair, otherwise \fIpattern\fR should be <\fIeventName\fR>. .sp The optional \fIcharMap\fR is a list of \fIchar\fR-\fIvalue\fR pairs as in the form returned by \fBarray get\fR. Each \fIchar\fR has to be exactly one character. The \fIcharMap\fR is used in %-substitution. .sp If \fIpercentsCommand\fR is specified, then it will be used to perform %-substitution on any scripts bound to the event. If \fIpercentsCommand\fR is not specified and the event is dynamic, then the %-subtitution command passed to \fBnotify install\fR will be used if it was provided. If the event is static or no %-substitution command is available, then all %-substitution is done using \fIcharMap\fR only . See \fBnotify install\fR for a description of \fIpercentsCommand\fR. .TP \fIpathName\fR \fBnotify install\fR \fIpattern\fR ?\fIpercentsCommand\fR? This command installs a new event or detail specified by \fIpattern\fR. Events created by this command are called dynamic, whereas events created by the treectrl widget itself are called static. This command may be called to set or retrieve the \fIpercentsCommand\fR for an existing dynamic event. .sp The optional \fIpercentsCommand\fR is a list containing the name of a Tcl command, plus any optional arguments, to which five additional arguments will be appended. The command will be called to perform %-substitution on any scripts bound to the event specified by \fIpattern\fR (see \fBEVENTS AND SCRIPT SUBSTITUTIONS\fR). \fIPercentsCommand\fR should be defined as follows: .nf proc percentsCommand {?arg arg ...? char object event detail charMap} { switch -- $char { ... } return $value } .fi The optional \fIarg\fR arguments are part of the \fIpercentsCommand\fR list. \fIChar\fR is the %-character to be substituted. \fIObject\fR is the same as the argument to \fBnotify bind\fR. \fIEvent\fR and \fIdetail\fR specify the event. \fICharMap\fR is the same as the argument to \fBnotify generate\fR. \fIPercentsCommand\fR should return the value to replace the %-character by. If an error occurs evaluating \fIpercentsCommand\fR, the %-character is replaced by itself. .sp \fBnotify install\fR returns the current \fIpercentsCommand\fR for the event, or an error if the event is not dynamic. .TP \fIpathName\fR \fBnotify install detail\fR \fIeventName\fR \fIdetail\fR ?\fIpercentsCommand\fR? Deprecated. Use \fBnotify install\fR with a \fIpattern\fR of <\fIeventName\fR-\fIdetail\fR> instead. .TP \fIpathName\fR \fBnotify install event\fR \fIeventName\fR ?\fIpercentsCommand\fR? Deprecated. Use \fBnotify install\fR with a \fIpattern\fR of <\fIeventName\fR> instead. .TP \fIpathName\fR \fBnotify linkage\fR \fIpattern\fR Returns a string indicating whether the specified event or detail is created by means of the \fBnotify install\fR widget command (\fBdynamic\fR) or by the treectrl widget itself (\fBstatic\fR). .TP \fIpathName\fR \fBnotify linkage\fR \fIeventName\fR ?\fIdetail\fR? Deprecated. Use \fBnotify linkage\fR with a \fIpattern\fR of <\fIeventName\fR> or <\fIeventName\fR-\fIdetail\fR> instead. .TP \fIpathName\fR \fBnotify unbind\fR \fIobject\fR ?\fIpattern\fR? If no \fIpattern\fR is specified, all bindings on \fIobject\fR are removed. If \fIpattern\fR is specified, then the current binding for \fIpattern\fR is destroyed, leaving \fIpattern\fR unbound. .TP \fIpathName\fR \fBnotify uninstall\fR \fIpattern\fR If the event or detail specified by \fIpattern\fR is static (i.e. created by the treectrl widget itself), an error is generated. Otherwise the dynamic event or detail is removed. If an event name is specified without a detail, all details for that event are also removed. .TP \fIpathName\fR \fBnotify uninstall detail\fR \fIeventName\fR \fIdetail\fR Deprecated. Use \fBnotify uninstall\fR with a \fIpattern\fR of <\fIeventName\fR-\fIdetail\fR> instead. .TP \fIpathName\fR \fBnotify uninstall event\fR \fIeventName\fR Deprecated. Use \fBnotify uninstall\fR with a \fIpattern\fR of <\fIeventName\fR> instead. .RE .TP \fIpathName\fR \fBnumcolumns\fR Deprecated. Use the \fBcolumn count\fR command instead. .TP \fIpathName\fR \fBnumitems\fR Deprecated. Use the \fBitem count\fR command instead. .TP \fIpathName\fR \fBorphans\fR Returns a list containing the item ids of all items which have no parent. When an item is created, it has no parent by default, and can later become an orphan by means of the \fBitem remove\fR widget command. The root item is not returned. .TP \fIpathName\fR \fBrange\fR \fIfirst\fR \fIlast\fR Deprecated. Use the \fBitem range\fR command instead. .TP \fIpathName\fR \fBscan\fR \fIoption\fR \fIargs\fR This command is used to implement scanning on treectrls. It has two forms, depending on \fIoption\fR: .RS .TP \fIpathName\fR \fBscan mark\fR \fIx\fR \fIy\fR Records \fIx\fR and \fIy\fR and the treectrl's current view; used in conjunction with later \fBscan dragto\fR commands. Typically this command is associated with a mouse button press in the widget and \fIx\fR and \fIy\fR are the coordinates of the mouse. It returns an empty string. .TP \fIpathName\fR \fBscan dragto\fR \fIx\fR \fIy\fR ?\fIgain\fR? This command computes the difference between its \fIx\fR and \fIy\fR arguments (which are typically mouse coordinates) and the \fIx\fR and \fIy\fR arguments to the last \fBscan mark\fR command for the widget. It then adjusts the view by \fIgain\fR times the difference in coordinates, where \fIgain\fR defaults to 10. This command is typically associated with mouse motion events in the widget, to produce the effect of dragging the treectrl at high speed through its window. The return value is an empty string. .RE .TP \fIpathName\fR \fBsee\fR \fIitemDesc\fR ?\fIcolumnDesc\fR? ?\fIoption value ...\fR? Adjust the view in the treectrl so that the item described by \fIitemDesc\fR is visible. If the item is already visible then the command has no effect; otherwise the treectrl scrolls to bring the item into view, and the corresponding \fB\fR and/or \fB\fR events are generated. If \fIcolumnDesc\fR is specified then a specific column of the item is scrolled into view instead of the entire item. .sp The following options are supported: .RS .TP \fB\fB-center\fR\fR \fIflags\fR \fIFlags\fR is a string that contains zero or more of the characters \fBx\fR or \fBy\fR. This option is used to center the item horizontally and/or vertically in the window. The item will be centered regardless of whether it is already visible. .RE .TP \fIpathName\fR \fBselection\fR \fIoption\fR \fIargs\fR This command is used to adjust the selection within a treectrl. It has several forms, depending on \fIoption\fR: .RS .TP \fIpathName\fR \fBselection add\fR \fIfirst\fR ?\fIlast\fR? \fIFirst\fR and \fIlast\fR (if specified) must be valid \fBitem descriptions\fR. If both \fIfirst\fR and \fIlast\fR are specified, then they may refer to a single item only; in this case the command adds every unselected item in the range between \fIfirst\fR and \fIlast\fR, inclusive, to the selection without affecting the selected state of items outside that range. If only \fIfirst\fR is specified, then every unselected item specified by \fIfirst\fR is added to the selection. A \fB\fR event is generated if any items were added to the selection. .TP \fIpathName\fR \fBselection anchor\fR ?\fIitemDesc\fR? If \fIitemDesc\fR is specified, the selection anchor is set to the described item. The selection anchor is the end of the selection that is fixed while dragging out a selection with the mouse. The item description \fBanchor\fR may be used to refer to the anchor item. This command doesn't modify the selection state of any item. Returns the unique id of the selection anchor item. .TP \fIpathName\fR \fBselection clear\fR ?\fIfirst\fR? ?\fIlast\fR? \fIFirst\fR and \fIlast\fR (if specified) must be valid \fBitem descriptions\fR. If both \fIfirst\fR and \fIlast\fR are specified, then they may refer to a single item only; in this case any selected items between \fIfirst\fR and \fIlast\fR (inclusive) are removed from the selection without affecting the selected state of items outside that range. If only \fIfirst\fR is specified, then every selected item specified by \fIfirst\fR is removed from the selection. If neither \fIfirst\fR nor \fIlast\fR are specified, then all selected items are removed from the selection. A \fB\fR event is generated if any items were removed from the selection. .TP \fIpathName\fR \fBselection count\fR Returns an integer indicating the number of items in the treectrl that are currently selected. .TP \fIpathName\fR \fBselection get\fR ?\fIfirst\fR? ?\fIlast\fR? When no additional arguments are given, the result is an unsorted list containing the item ids of all of the items in the treectrl that are currently selected. If there are no items selected in the treectrl, then an empty string is returned. The optional arguments \fIfirst\fR and \fIlast\fR are treated as indices into the sorted list of selected items; these arguments allow in-place \fBlindex\fR and \fBlrange\fR operations on the selection. For example: .nf .t selection get 0 ; # return the first selected item .t selection get end ; # return the last selected item .t selection get 1 end-1 ; # return every selected item except the first and last .fi .TP \fIpathName\fR \fBselection includes\fR \fIitemDesc\fR Returns 1 if the item described by \fIitemDesc\fR is currently selected, 0 if it isn't. .TP \fIpathName\fR \fBselection modify\fR \fIselect\fR \fIdeselect\fR Both arguments \fIselect\fR and \fIdeselect\fR are a possibly-empty list of \fBitem descriptions\fR. Any unselected items in \fIselect\fR are added to the selection, and any selected items in \fIdeselect\fR are removed from the selection (except for those items which are also in \fIselect\fR). A \fB\fR event is generated if any items were selected or deselected. .RE .TP \fIpathName\fR \fBstate\fR \fIoption\fR \fIargs\fR This command is used to manipulate the list of user-defined item states, see section \fBSTATES\fR below. Item states can also be managed using the \fBitem state\fR command. To manage states for \fBheader-rows\fR, use the \fBheader state\fR widget command. The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBstate\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBstate define\fR \fIstateName\fR Defines a new state with the name \fIstateName\fR, which must not be the name of an existing state. .TP \fIpathName\fR \fBstate linkage\fR \fIstateName\fR Returns a string indicating whether the specified state is user-defined by means of the \fBstate define\fR widget command (\fBdynamic\fR) or predefined by the treectrl widget itself (\fBstatic\fR). .TP \fIpathName\fR \fBstate names\fR Returns a list containing the names of all user-defined states. .TP \fIpathName\fR \fBstate undefine\fR ?\fIstateName ...\fR? Every \fIstateName\fR must be the name of a user-defined state. Removes this state from the list of user-defined states. .RE .TP \fIpathName\fR \fBstyle\fR \fIoption\fR ?\fIelement\fR? ?\fIarg arg ...\fR? This command is used to manipulate styles, which can be thought of as a geometry manager for elements. The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBstyle\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBstyle cget\fR \fIstyle\fR \fIoption\fR This command returns the current value of the option named \fIoption\fR associated with the style given by \fIstyle\fR. \fIOption\fR may have any of the values accepted by the \fBstyle configure\fR widget command. .sp This command also accepts the \fB-statedomain\fR option. .TP \fIpathName\fR \fBstyle configure\fR \fIstyle\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command is similar to the \fBconfigure\fR widget command except that it modifies options associated with the style given by \fIstyle\fR instead of modifying options for the overall treectrl widget. If no \fIoption\fR is specified, the command returns a list describing all of the available options for \fIstyle\fR (see \fBTk_ConfigureInfo\fR for information on the format of this list). If \fIoption\fR is specified with no \fIvalue\fR, 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 \fIoption\fR is specified). If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given option(s) to have the given value(s) in \fIstyle\fR; in this case the command returns an empty string. .sp The following options are supported: .RS .TP \fB\fB-buttony\fR\fR \fIoffset\fR Specifies the distance from the top of the item that the expand/collapse button should be drawn. If \fIoffset\fR is an empty string (the default) then the button is centered vertically in the item. The value may have any of the forms acceptable to \fBTk_GetPixels\fR. This option only has effect when the style is set in an item in the tree column. .TP \fB\fB-orient\fR\fR \fIvarName\fR This option specifies which orientation should be used when laying out the elements associated with this style. Must be either \fBhorizontal\fR (the default) or \fBvertical\fR or an abbreviation of one of these. .RE .TP \fIpathName\fR \fBstyle create\fR \fIname\fR ?\fIoption value ...\fR? Creates a new style with the unique user-defined name \fIname\fR. After \fIname\fR there may be any number of \fIoption\fR-\fIvalue\fR pairs, each of which sets one of the configuration options for the style. See the \fBstyle configure\fR command for the possible options. The result of this command is the name of the new style (the same as the \fIname\fR option). .sp This command also accepts the \fB-statedomain\fR option with a value of either \fBheader\fR or \fBitem\fR to specify where this style will be displayed. .TP \fIpathName\fR \fBstyle delete\fR ?\fIstyle ...\fR? Deletes each of the named styles and returns an empty string. If a style is deleted while it is still used to display one or more items, it is also removed from the style list of these items. .TP \fIpathName\fR \fBstyle elements\fR \fIstyle\fR ?\fIelementList\fR? Specifies the elements which should be layed out by this style. Each element of \fIelementList\fR must be the name of an element created by the widget command \fBelement create\fR. Duplicate names in \fIelementList\fR are ignored. An element which was specified in a former call of this command for \fIstyle\fR but is not included in \fIelementList\fR, will be deleted from the elements layed out by \fIstyle\fR. .sp Every element used by a style must have been created with the same value for the \fB-statedomain\fR option. .sp If the \fIelementList\fR argument is not specified, a list is returned containing the currently defined elements of \fIstyle\fR. .TP \fIpathName\fR \fBstyle layout\fR \fIstyle\fR \fIelement\fR ?\fIoption\fR? ?\fIvalue\fR? ?\fIoption value ...\fR? This command is similar to the \fBconfigure\fR widget command except that it modifies options used by \fIstyle\fR for laying out \fIelement\fR instead of modifying options for the overall treectrl widget. If no \fIoption\fR is specified, the command returns a list with \fIoption\fR-\fIvalue\fR pairs describing all of the available options for the layout. If \fIoption\fR is specified with no \fIvalue\fR, then the command returns the value of the named option. If one or more \fIoption\fR-\fIvalue\fR pairs are specified, then the command modifies the given option(s) to have the given value(s) for the layout; in this case the command returns an empty string. .sp The options of a layout have effect on exactly the one element \fIelement\fR managed by \fIstyle\fR. The following options are supported: .RS .TP \fB\fB-detach\fR\fR \fIboolean\fR Specifies whether the element should be positioned by itself, i.e. independent from the other elements. The default is false. .TP \fB\fB-center\fR\fR \fIflags\fR \fIFlags\fR is a string that contains zero or more of the characters \fBx\fR or \fBy\fR. \fBx\fR causes the element to be centered horizontally, \fBy\fR causes the element to be centered vertically. When more than one element has -center layout, all the elements between the first and last with -center layout in the style's list of elements are centered as a group. Consider the following when there is another element to the right of MyElement: .nf .t style layout MyStyle MyElement -expand we .t style layout MyStyle MyElement -center x .fi With the first call, MyElement will be centered only within the space that is not occupied by the other element, so MyElement will appear off-center towards the left of the style. With the second call, MyElement will be centered within the style so long as it doesn't overlap the other element. .TP \fB\fB-draw\fR\fR \fIboolean\fR This is a \fBper-state\fR option that determines whether an element should be drawn. If the value of the option evaluates to false for a given item state, then the element is not drawn, although it still consumes space in the layout. .TP \fB\fB-expand\fR\fR \fIflags\fR This option allows the external padding around the element to increase when a style has more screen space than it needs. \fIFlags\fR is a string that contains zero or more of the characters \fBn\fR, \fBs\fR, \fBw\fR or \fBe\fR. Each letter refers to the padding on the top, bottom, left, or right that should be allowed to increase. This option is typically used to justify an element. The default is an empty string. .TP \fB\fB-iexpand\fR\fR \fIflags\fR This option allows the internal padding of the element and the display area of the element to increase when a style has more screen space than it needs. \fIFlags\fR is a string that contains zero or more of the characters \fBx\fR, \fBy\fR, \fBn\fR, \fBs\fR, \fBw\fR or \fBe\fR. For \fBn\fR, \fBs\fR, \fBw\fR and \fBe\fR, each letter refers to the padding on the top, bottom, left, or right that should be allowed to increase. For \fBx\fR and \fBy\fR, each letter refers to the horizontal and vertical screen space the element can display itself in (i.e., the space between the padding). Note that if the \fB-union\fR option is specified for this element, then the \fBx\fR and \fBy\fR flags have no effect, since the size of an element with \fB-union\fR layout is determined by the elements it surrounds. The default is an empty string. .TP \fB\fB-indent\fR\fR \fIboolean\fR For item styles, this option specifies whether the element should be positioned to the right of the button/line area in the tree column. When false, the element is displayed beneath the buttons and lines in the tree column. This option is ignored unless the \fB-detach\fR option is true. .sp For header styles, this option specifies whether the element should be positioned to the right of the -canvaspadx padding. This option is ignored unless the \fB-detach\fR option is true or the \fB-union\fR option is specified. .sp The default is true. .TP \fB\fB-ipadx\fR\fR \fIamount\fR .TP \fB\fB-ipady\fR\fR \fIamount\fR \fIAmount\fR specifies how much internal padding to leave on the left and right (for \fB-ipadx\fR) or top and bottom (for \fB-ipady\fR) sides of the element. \fIAmount\fR may be a list of two values to specify padding for the two sides separately. The default value is 0. This option is typically used with the \fB-union\fR layout option, to create space around the enclosed elements. .TP \fB\fB-minheight\fR\fR \fIpixels\fR .TP \fB\fB-height\fR\fR \fIpixels\fR .TP \fB\fB-maxheight\fR\fR \fIpixels\fR Specifies the minimum, fixed, and maximum height of the display area of the element. The default is unspecified. .TP \fB\fB-minwidth\fR\fR \fIpixels\fR .TP \fB\fB-width\fR\fR \fIpixels\fR .TP \fB\fB-maxwidth\fR\fR \fIpixels\fR Specifies the minimum, fixed, and maximum width of the display area of the element. The default is unspecified. .TP \fB\fB-padx\fR\fR \fIamount\fR .TP \fB\fB-pady\fR\fR \fIamount\fR \fIAmount\fR specifies how much external padding to leave on the left and right (for \fB-padx\fR) or top and bottom (for \fB-pady\fR) sides of the element. \fIAmount\fR may be a list of two values to specify padding for the two sides separately. The default value is 0. .TP \fB\fB-squeeze\fR\fR \fIflags\fR This option allows the display area of an element to decrease when a style has less space than it needs. \fIFlags\fR is a string that contains zero or more of the characters \fBx\fR or \fBy\fR. \fBx\fR allows display area to decrease horizontally, \fBy\fR allows display area to decrease vertically. This option is typically used for \fBtext\fR elements and will cause the text element to display an ellipsis (...) and/or wrap lines. The default is an empty string. .TP \fB\fB-sticky\fR\fR \fIflags\fR This option controls how the actual display information (image, text, etc) of an element is positioned (or stretched) within its display area. \fIFlags\fR is a string that contains zero or more of the characters \fBn\fR, \fBs\fR, \fBw\fR or \fBe\fR. Each letter refers to the top, bottom, left or right side of the display area that the display information should "stick" to. The default is nswe. .TP \fB\fB-union\fR\fR \fIelementList\fR Specifies a list of other elements which this element will surround. The size of an element with \fB-union\fR layout is determined by the size and position of the elements in \fIelementList\fR. The \fB-ipadx\fR and \fB-ipady\fR options in this case refer to the distance of the edges of the display area of this element from those elements it surrounds. This option is typically used to display a selection rectangle around a piece of text. If none of the elements in \fIelementList\fR are visible, then the element is not displayed. .TP \fB\fB-visible\fR\fR \fIboolean\fR This is a \fBper-state\fR option that controls visibility of an element. If the value of the option evaluates to false for a given item state, then the element is not displayed and consumes no space in the layout. .RE .TP \fIpathName\fR \fBstyle names\fR Returns a list containing the names of all existing styles. .RE .TP \fIpathName\fR \fBtheme\fR \fIoption\fR ?\fIarg ...\fR? This command is used to interact with the platform-specific theme. The exact behavior of the command depends on the \fIoption\fR argument that follows the \fBtheme\fR argument. The following forms of the command are supported: .RS .TP \fIpathName\fR \fBtheme platform\fR Returns the API used to draw themed parts of the treectrl. On Mac OS X the result is always \fBaqua\fR. On MS Windows the result is \fBvisualstyles\fR if the uxtheme.dll was loaded and visual themes are in use, otherwise \fBX11\fR is returned to indicate the Tk Xlib calls are drawing the themed parts. On Unix systems the result is \fBgtk\fR if the Gtk+ version of treectrl was built, otherwise \fBX11\fR is returned. .TP \fIpathName\fR \fBtheme setwindowtheme\fR \fIappname\fR The command is available on MS Windows only. If \fIappname\fR is "Explorer" then the item buttons look like those in the Explorer file browser (disclosure triangles under Windows Vista/7). If \fIappname\fR is an empty string then the buttons revert to their default appearance according to the system's current visual style. .RE .TP \fIpathName\fR \fBtoggle\fR ?\fB-recurse\fR? ?\fIitemDesc ...\fR? Use \fBitem toggle\fR instead. .TP \fIpathName\fR \fBxview\fR ?\fIargs\fR? This command is used to query and change the horizontal position of the information displayed in the treectrl's window. It can take any of the following forms: .RS .TP \fIpathName\fR \fBxview\fR 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 tree's area is off-screen to the left, the middle 40% is visible in the window, and 40% of the tree is off-screen to the right. These are the same values passed to scrollbars via the \fB-xscrollcommand\fR option. .TP \fIpathName\fR \fBxview moveto\fR \fIfraction\fR Adjusts the view in the window so that \fIfraction\fR of the total width of the tree is off-screen to the left. \fIFraction\fR must be a fraction between 0 and 1. A \fB\fR event is generated. .TP \fIpathName\fR \fBxview scroll\fR \fInumber\fR \fIwhat\fR This command shifts the view in the window left or right according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR or an abbreviation of one of these. If \fIwhat\fR is \fBunits\fR, the view adjusts left or right in units determined by the \fB-xscrollincrement\fR option (which may be zero, see the description of that option). If \fIwhat\fR is \fBpages\fR then the view adjusts in units of nine-tenths the window's width. If \fInumber\fR is negative then information farther to the left becomes visible; if it is positive then information farther to the right becomes visible. A \fB\fR event is generated. .RE .TP \fIpathName\fR \fByview\fR ?\fIargs\fR? This command is used to query and change the vertical position of the information displayed in the treectrl's window. It can take any of the following forms: .RS .TP \fIpathName\fR \fByview\fR Returns a list containing two elements. Each element is a real fraction between 0 and 1; together they describe the vertical span that is visible in the window. For example, if the first element is .6 and the second element is 1.0, the lowest 40% of the tree's area is visible in the window. These are the same values passed to scrollbars via the \fB-yscrollcommand\fR option. .TP \fIpathName\fR \fByview moveto\fR \fIfraction\fR Adjusts the view in the window so that \fIfraction\fR of the tree's area is off-screen to the top. \fIFraction\fR is a fraction between 0 and 1. A \fB\fR event is generated. .TP \fIpathName\fR \fByview scroll\fR \fInumber\fR \fIwhat\fR This command adjusts the view in the window up or down according to \fInumber\fR and \fIwhat\fR. \fINumber\fR must be an integer. \fIWhat\fR must be either \fBunits\fR or \fBpages\fR. If \fIwhat\fR is \fBunits\fR, the view adjusts up or down in units of the \fB-yscrollincrement\fR option (which may be zero, see the description of that option). If \fIwhat\fR is \fBpages\fR then the view adjusts in units of nine-tenths the window's height. If \fInumber\fR is negative then higher information becomes visible; if it is positive then lower information becomes visible. A \fB\fR event is generated. .RE .PP .SH HEADERS A treectrl widget can display zero or more rows of column headers. When a treectrl widget is created, a single row of column headers (aka a header-row) is created as well; this top header-row cannot be deleted. Additional header-rows can be created with the \fBheader create\fR command and deleted with \fBheader delete\fR. .PP There are no commands for changing the order of header-rows; they are displayed from top to bottom in the order they were created. .PP Drag-and-drop reordering of column headers is supported within a widget. To control column header drag-and-drop, use the \fBheader dragconfigure\fR command. .PP Header-rows in a treectrl may be specified in a number of ways. See \fBHEADER DESCRIPTION\fR below. .PP The appearance of individual column headers within a header-row may be customized in two different ways: .IP [1] By configuring various column header options with the \fBheader configure\fR command .IP [2] By assigning a style to a column header with the \fBheader style\fR command. .PP .PP When one of the options below is specified as \fBper-state\fR, the state names are those described in \fBSTATES\fR for headers only, i.e. do not use item state names. .PP The following options are supported for each individual column header: .TP \fB\fB-arrow\fR\fR \fIdirection\fR Indicates whether or not a sort arrow should be drawn in the column header. \fIDirection\fR must have one of the values \fBnone\fR (the default), \fBup\fR, or \fBdown\fR. .TP \fB\fB-arrowbitmap\fR\fR \fIbitmap\fR Specifies as a \fBper-state\fR option the name of a bitmap to use to draw the arrow if this column's -arrow option is not \fBnone\fR. .TP \fB\fB-arrowgravity\fR\fR \fIdirection\fR Indicates onto which side the sort arrow should be packed, if there is more space available for drawing the arrow then needed. \fIdirection\fR must be either \fBleft\fR (the default) or \fBright\fR. .TP \fB\fB-arrowimage\fR\fR \fIimage\fR Specifies as a \fBper-state\fR option the name of an image to use to draw the sort arrow if this column's -arrow option is not \fBnone\fR. If an image is specified for a certain state, it overrides the -arrowbitmap option. .TP \fB\fB-arrowpadx\fR\fR \fIamount\fR \fIAmount\fR specifies how much padding to leave on the left and right of the sort arrow. \fIAmount\fR may be a list of two values to specify padding for left and right separately; it defaults to 6. .TP \fB\fB-arrowpady\fR\fR \fIamount\fR \fIAmount\fR specifies how much padding to leave on the top and bottom of the sort arrow. \fIAmount\fR may be a list of two values to specify padding for top and bottom separately; it defaults to 0. .TP \fB\fB-arrowside\fR\fR \fIside\fR Indicates on which side of the bitmap/image/text the sort arrow should be drawn. \fISide\fR must be either \fBleft\fR or \fBright\fR (the default). .TP \fB\fB-bitmap\fR\fR \fIbitmap\fR Specifies the name of a bitmap to display to the left of the column title. .TP \fB\fB-background\fR\fR \fIcolor\fR Specifies as a \fBper-state\fR option the color to use for the background of the column header. .TP \fB\fB-borderwidth\fR\fR \fIsize\fR Specifies a non-negative value indicating the width of the 3-D border to draw around the outside of the column header (if such a border is being drawn; the \fB-relief\fR column option determines this). The value may have any of the forms acceptable to \fBTk_GetPixels\fR. .TP \fB\fB-button\fR\fR \fIboolean\fR Indicates whether or not the column header should be treated like a pushbutton. When this option is true, the default bindings track events in the header and generate a event when a event occurs in the header. See \fBDYNAMIC EVENTS\fR. .TP \fB\fB-font\fR\fR \fIfontName\fR Specifies the font to use for displaying the column title inside the column header. When the value of this option is unspecified, the font specified by the widget option \fB-headerfont\fR is used. .TP \fB\fB-image\fR\fR \fIimage\fR Specifies the name of an image to display to the left of the column title. This option overrides the \fB-bitmap\fR column option. .TP \fB\fB-imagepadx\fR\fR \fIamount\fR \fIAmount\fR specifies how much padding to leave on the left and right of the image (or bitmap). \fIAmount\fR may be a list of two values to specify padding for left and right separately; it defaults to 6. .TP \fB\fB-imagepady\fR\fR \fIamount\fR \fIAmount\fR specifies how much padding to leave on the top and bottom of the image (or bitmap). \fIAmount\fR may be a list of two values to specify padding for top and bottom separately; it defaults to 0. .TP \fB\fB-justify\fR\fR \fIjustification\fR This option determines how the image and text in the column header are positioned. Must be one of \fBleft\fR (the default), \fBcenter\fR, or \fBright\fR. .TP \fB\fB-state\fR\fR \fIstate\fR Specifies one of three states for the column header: \fBnormal\fR, \fBactive\fR, or \fBpressed\fR. The active state is used when the mouse is over the header. The pressed state is used when the mouse button is pressed in the header. .sp Changing the value of this option also affects the current set of \fBheader states\fR for the column header, which may affect both the \fBper-state\fR options mentioned here (such as \fB-arrowimage\fR) as well as the elements in any style that may be assigned to the column header. .TP \fB\fB-text\fR\fR \fItext\fR Specifies a text string to be displayed as the column title. .TP \fB\fB-textcolor\fR\fR \fIcolor\fR Specifies as a \fBper-state\fR option the color to display the column title with. When the value of this option is unspecified, the title will be drawn according to the system theme color, if any, otherwise the widget option \fB-headerforeground\fR is used. The default is unspecified. .TP \fB\fB-textlines\fR\fR \fIcount\fR Specifies the maximum number of lines of text to display in the column title. If this value is zero, the number of lines displayed is determined by any newline characters and the effects of wrapping when the column width is less than needed. The default is 1. Note: Under OSX/Aqua this value is always set to 1 when the treectrl's \fB-usetheme\fR option is true, because the Appearance Manager uses a fixed height for the column header; there is only room for a single line of text. .TP \fB\fB-textpadx\fR\fR \fIamount\fR \fIAmount\fR specifies how much padding to leave on the left and right of the text. \fIAmount\fR may be a list of two values to specify padding for left and right separately; it defaults to 6. .TP \fB\fB-textpady\fR\fR \fIamount\fR \fIAmount\fR specifies how much padding to leave on the top and bottom of the text. \fIAmount\fR may be a list of two values to specify padding for top and bottom separately; it defaults to 0. .PP .SH "HEADER DESCRIPTION" Many of the commands for a treectrl take as an argument a description of which header-rows to operate on. A \fIheader description\fR is a properly-formed tcl list of keywords and arguments. The first word of a header description must be one of the following: .TP \fIid\fR Specifies a unique header-row identifier, where \fIid\fR should be the return value of a prior call of the \fBheader create\fR widget command, or \fB0\fR to specify the ever-present top header-row. .TP \fIQUALIFIERS\fR Specifies a list of qualifiers. This gives the same result as \fBall\fR followed by \fIQUALIFIERS\fR; i.e., every header-row is tested for a match. .TP \fItagExpr\fR \fIQUALIFIERS\fR \fITagExpr\fR is a tag expression (see \fBITEM AND COLUMN TAGS\fR) against which every header-row's tags are tested for a match. You may run into trouble if \fItagExpr\fR looks like a header-row id or other keyword; also, \fItagExpr\fR must look like a single list element since header-row descriptions are properly-formed lists. To be safe you may want to use the \fBtag\fR qualifier followed by \fItagExpr\fR. .nf .t header dragconfigure {tag -funky} -draw yes .fi .TP \fBall\fR \fIQUALIFIERS\fR Matches every header-row which satisfies \fIQUALIFIERS\fR. .TP \fBfirst\fR \fIQUALIFIERS\fR Indicates the top header-row of the treectrl, or the first header-row starting from the top that satisfies \fIQUALIFIERS\fR. .TP \fBend\fR \fIQUALIFIERS\fR .TP \fBlast\fR \fIQUALIFIERS\fR Indicates the last header-row which satisfies \fIQUALIFIERS\fR. .PP The word \fIQUALIFIERS\fR above represents a series of zero or more of the following terms that changes which header-row is chosen: .TP \fBtag\fR \fItagExpr\fR \fITagExpr\fR is a tag expression (see \fBITEM AND COLUMN TAGS\fR) against which a header-row's tags are tested for a match. .TP \fBvisible\fR When this qualifier is given, only header-rows that are displayed are matched. A header-row is displayed only if both the \fB-showheader\fR widget option and \fB-visible\fR header-row option are true. Also, if only the tail column is visible, then header-rows are not displayed. .TP \fB!visible\fR When this qualifier is given, only header-rows that are *not* displayed are matched. .PP .SH COLUMNS A treectrl widget is capable of displaying multiple columns next to each other. An item can be considered as a row, which reaches over all columns. .PP Columns in a treectrl may be specified in a number of ways. See \fBCOLUMN DESCRIPTION\fR below. .PP There is always one special column, the \fBtail\fR column, which fills all space to the right of the last ordinary column. This column has no unique ID; it can only be specified by the keyword \fBtail\fR. .PP For compatibility with older versions of treectrl (which did not support more than one row of column headers) any of the configuration options mentioned in the \fBHEADERS\fR section, such as \fB-arrow\fR, \fB-text\fR, etc, may be passed to the top header-row through the \fBcolumn configure\fR command and queried with the \fBcolumn cget\fR command. .PP The following options are supported for columns: .TP \fB\fB-expand\fR\fR \fIboolean\fR Indicates whether or not any extra horizontal space should be distributed to this column. This option has no effect if the \fB-width\fR option is set. .TP \fB\fB-gridleftcolor\fR\fR \fIcolor\fR .TP \fB\fB-gridrightcolor\fR\fR \fIcolor\fR Specifies the color of the lines drawn down the left and right edges of the column. These so-called "grid lines" are drawn over the elements of each item style in the column and down into the whitespace region below any items. The default value for each option is an empty string meaning no lines are drawn. .TP \fB\fB-itembackground\fR\fR \fIcolorList\fR Specifies a list of zero or more colors, which are used as alternating background colors for items in this column. See also the \fB-backgroundmode\fR widget option for more on this. .TP \fB\fB-itemjustify\fR\fR \fIjustification\fR This option determines how the item styles in this column are aligned horizontally. Must be one of \fBleft\fR, \fBcenter\fR, or \fBright\fR. The default value is an empty string (for compatibility with older versions), in which case the column option \fB-justify\fR is used to align item styles in this column. .TP \fB\fB-itemstyle\fR\fR \fIstyle\fR \fIStyle\fR is the name of a style that should be set in this column for newly-created items. .TP \fB\fB-justify\fR\fR \fIjustification\fR This option determines how item styles in this column are aligned horizontally unless overriden by the \fB-itemjustify\fR option for this column. Must be one of \fBleft\fR (the default), \fBcenter\fR, or \fBright\fR. .sp For compatibility with older versions of treectrl (which did not allow multiple rows of column headers), changing the value of this option also changes the \fB-justify\fR option of the column header in the top \fBheader-row\fR. .TP \fB\fB-lock\fR\fR \fIlock\fR This option allows a column to stick to the left or right edge of the window. A locked column scrolls vertically but not horizontally. Must be one of \fBnone\fR (the default), \fBleft\fR, or \fBright\fR. .TP \fB\fB-maxwidth\fR\fR \fIsize\fR Specifies the maximum size, in screen units, that will be permitted for this column. If \fIsize\fR is an empty string, then there is no limit on the maximum size of the column. This option has no effect if the \fB-width\fR option is set. .TP \fB\fB-minwidth\fR\fR \fIsize\fR Specifies the minimum size, in screen units, that will be permitted for this column. If \fIsize\fR is an empty string, then the minimum size of the column is zero. This option has no effect if the \fB-width\fR option is set. .TP \fB\fB-resize\fR\fR \fIboolean\fR Specifies a boolean value that indicates whether the user should be allowed to resize the column by dragging the edge of the column's header. Default is true. .TP \fB\fB-squeeze\fR\fR \fIboolean\fR Specifies a boolean value that indicates whether or not the column should shrink when the content width of the treectrl is less than the total needed width of all visible columns. Defaults to false, which means the column will not get smaller than its needed width. The column will not get smaller than the value of its \fB-minwidth\fR option, if specified. This option has no effect if the \fB-width\fR option is set. .TP \fB\fB-stepwidth\fR\fR \fIsize\fR Deprecated. Use the treectrl's \fB-itemwidthmultiple\fR option instead. .TP \fB\fB-tags\fR\fR \fItagList\fR \fITagList\fR is a list of tag names that can be used to identify the column. See also the \fBcolumn tag\fR command. .TP \fB\fB-uniform\fR\fR \fIgroup\fR When a non-empty value is supplied, this option places the column in a \fIuniform group\fR with other columns that have the same value for \fB-uniform\fR. The space for columns belonging to a uniform group is allocated so that their sizes are always in strict proportion to their \fB-weight\fR values. This option is based on the grid geometry manager. .TP \fB\fB-visible\fR\fR \fIboolean\fR Indicates whether or not the column should be displayed. .TP \fB\fB-weight\fR\fR \fIinteger\fR Sets the relative weight for apportioning any extra space among columns. A weight of zero (0) indicates the column will not deviate from its requested size. A column whose weight is two will grow at twice the rate as a column of weight one when extra space is allocated to columns. This option is based on the grid geometry manager. .TP \fB\fB-width\fR\fR \fIsize\fR Specifies a fixed width for the column. If this value is an empty string, then the column width is calculated as the maximum of: a) the width requested by items; b) the width requested by the column's header; and c) the column's \fB-minwidth\fR option. This calculated width is also affected by the \fB-expand\fR, \fB-squeeze\fR, \fB-uniform\fR and \fB-weight\fR options. In any case, the calculated width will not be greater than the \fB-maxwidth\fR option, if specified. .TP \fB\fB-widthhack\fR\fR \fIboolean\fR Deprecated. Use the treectrl's \fB-itemwidthequal\fR option instead. .PP .SH "COLUMN DESCRIPTION" Many of the commands and options for a treectrl take as an argument a description of which column to operate on. See the \fBEXAMPLES\fR section for examples. The initial part of a column description must begin with one of the following terms: .TP \fIid\fR Specifies the unique column identifier, where \fIid\fR should be the return value of a prior call of the \fBcolumn create\fR widget command. See also the \fB-columnprefix\fR option. .TP \fIQUALIFIERS\fR Specifies a list of qualifiers. This gives the same result as \fBall\fR followed by \fIQUALIFIERS\fR; i.e., every column is tested for a match. .TP \fItagExpr\fR \fIQUALIFIERS\fR \fITagExpr\fR is a tag expression (see \fBITEM AND COLUMN TAGS\fR) against which every column's tags are tested for a match. This keyword cannot be followed by any modifiers unless a single column is matched. You may run into trouble if \fItagExpr\fR looks like a column id or other keyword; also, \fItagExpr\fR must look like a single list element since column descriptions are properly-formed lists. To be safe you may want to use the \fBtag\fR qualifier followed by \fItagExpr\fR. .TP \fBall\fR \fIQUALIFIERS\fR Indicates every column, including the tail column if the command allows it, which match \fIQUALIFIERS\fR. .TP \fBfirst\fR \fIQUALIFIERS\fR Indicates the leftmost column of the treectrl which matches \fIQUALIFIERS\fR. .TP \fBend\fR \fIQUALIFIERS\fR .TP \fBlast\fR \fIQUALIFIERS\fR Indicates the rightmost column of the treectrl (but not the tail column) which matches \fIQUALIFIERS\fR. .TP \fBlist\fR \fIcolumnDescs\fR \fIColumnDescs\fR is a list (a single argument, i.e. "list {a b c}" not "list a b c") of other column descriptions. This keyword cannot be followed by any modifiers unless a single column is matched. .TP \fBorder\fR \fIn\fR \fIQUALIFIERS\fR Indicates the \fIn\fRth column in the list of columns as returned by the \fBcolumn order\fR command. .TP \fBrange\fR \fIfirst last\fR \fIQUALIFIERS\fR \fIFirst\fR and \fIlast\fR specify a range of columns. This keyword cannot be followed by any modifiers unless a single column is specified. .TP \fBtail\fR Indicates the ever-present tail column of the treectrl. .TP \fBtree\fR Indicates the column specified by the -treecolumn option of the treectrl. .PP .PP The initial part of the column description (matching any of the values above) may be followed by one or more \fImodifier\fRs. A modifier changes the column used relative to the description up to this point. It may be specified in any of the following forms: .TP \fBnext\fR \fIQUALIFIERS\fR Use the column to the right matching \fIQUALIFIERS\fR. .TP \fBprev\fR \fIQUALIFIERS\fR Use the column to the left matching \fIQUALIFIERS\fR. .TP \fBspan\fR \fIN\fR \fIQUALIFIERS\fR Starting with (and counting) the single column specified by the column description so far, walk at most \fIN\fR columns rightwards, stopping if any of the following conditions is met: .RS .IP [1] A column does not match \fIQUALIFIERS\fR. .IP [2] A column's -lock option does not match the first column's -lock option. .RE .PP The word \fIQUALIFIERS\fR above represents a sequence of zero or more of the following terms that changes which column is chosen: .TP \fBtag\fR \fItagExpr\fR \fITagExpr\fR is a tag expression (see \fBITEM AND COLUMN TAGS\fR) against which a column's tags are tested for a match. .TP \fB!tail\fR When this qualifier is given, the tail column is not matched. .TP \fBvisible\fR When this qualifier is given, only columns whose \fB-visible\fR option is TRUE are considered. .TP \fB!visible\fR When this qualifier is given, only columns whose \fB-visible\fR option is FALSE are considered. .PP .SH STATES For every column header and every item a set of boolean states is managed. These states play an integral role in the appearance of headers and items; that role is described in detail in \fBPER-STATE OPTIONS\fR. The set of states available to headers is separate from the set of states available to items. .TP HEADER STATES The following states are predefined for every column header: .RS .TP \fBactive\fR .TP \fBnormal\fR .TP \fBpressed\fR These states mirror the value of a column header's configuration option \fB-state\fR. Exactly one of these states is set at any time in each column header. .TP \fBdown\fR .TP \fBup\fR These states mirror the value of a column header's configuration option \fB-arrow\fR. If the \fB-arrow\fR option is \fBnone\fR, then neither of these states is set. .TP \fBbackground\fR This state is set for every header-row if the toplevel window containing the treectrl is not the foreground active window. This state cannot be modified by means of a widget command, but is maintained in reaction to the and windowing system events. .TP \fBfocus\fR This state is set for every header-row if the treectrl widget currently has the focus. It cannot be modified by means of a widget command, but is maintained in reaction to the and windowing system events. .RE .TP ITEM STATES The following states are predefined for every item: .RS .TP \fBactive\fR At all times this state is set for exactly one item. The active item is used with keyboard navigation. When the treectrl widget is created or when the active item is deleted, the root item will become the active item. This state can be modified by means of the widget command \fBactivate\fR. .TP \fBenabled\fR This state is set for every item when it is created. Disabled items cannot be selected and are ignored by the default bindings when navigating via the keyboard. This state can be modified by means of the widget command \fBitem enabled\fR. .TP \fBfocus\fR This state is set for every item if the treectrl widget currently has the focus. It cannot be modified by means of a widget command, but is maintained in reaction to the and events. .TP \fBopen\fR If this state is switched on, the descendants of the item are displayed - the item is expanded. If this state is switched off, the descendants of the item are not displayed - the item is collapsed. For a new item this state is switched on by default. This state can be modified by means of the widget commands \fBitem expand\fR, \fBitem collapse\fR, or \fBitem toggle\fR. .TP \fBselected\fR This state is set for every item included in the selection. It can be modified by means of the widget command \fBselection\fR. .RE .sp By means of the \fBstate define\fR widget command, up to 27 additional states can be defined. .PP .SH "PER-STATE OPTIONS" The visual appearance of an item can change depending on the state the item is in, such as being the active item, being included in the selection, being collapsed, or some combination of those or other states. When a configuration option is described as \fIper-state\fR, it means the option describes a value which varies depending on the state of the item. If a per-state option is specified as a single value, the value is used for all states. Otherwise the per-state option must be specified as an even-numbered list. For example, to use the font "Times 12 bold" in a \fBtext\fR element regardless of the item state you can write: .nf $T element configure MyTextElement -font {{Times 12 bold}} .fi However, to use a different font when the item is selected you could write: .nf $T element configure MyTextElement -font {{Courier 10} selected {Times 12 bold} {}} .fi In the example above, the -font option reads "value stateList value stateList". If \fIstateList\fR is an empty list, the preceding \fIvalue\fR is used regardless of the item state. A non-empty stateList specifies a list of states which must be set for the item in order to use the preceding value. Each stateList can also include state names preceded by a ! sign, indicating the state must *not* be set for the item. For example: .nf $T element configure MyRectElement -fill {blue {selected focus} gray {selected !focus}} .fi In the example above, the \fBrect\fR element is filled with blue when the treectrl has the focus and the item is selected. If the treectrl does not have the focus, the example specifies that gray should be used for selected items. Also note that if the item is not selected, no color is specified for the -fill option. .PP Each value-stateList pair is checked in order from left to right. The value associated with the first stateList that matches the current item state is used. So stateLists should be listed from most-specific to least-specific. .nf $T element configure MyRectElement -fill {gray {selected} blue {selected focus}} .fi Written this way, gray will always be used for selected items since it appears first, and blue will never be used for selected items regardless of the focus. .PP A value followed by an empty stateList should always be last since it will be chosen regardless of the item's state. .SH "ELEMENTS AND STYLES" \fIElements\fR and \fIstyles\fR are the core visual building blocks that determine the appearance of items (and optionally column headers). An element can be of type \fBbitmap\fR, \fBborder\fR, \fBheader\fR, \fBimage\fR, \fBrect\fR, \fBtext\fR or \fBwindow\fR. One or more elements can be assigned to a style which manages the layout of those elements. It may be helpful to think of an element as a Tk widget and a style as a Tk geometry manager such as \fBgrid\fR, \fBpack\fR or \fBplace\fR. .PP When an element is created by the \fBelement create\fR command, that element is referred to as a \fImaster\fR element. Similarly, a style that is created by \fBstyle create\fR is called a \fImaster\fR style. When a master style is assigned to a column of an item by the \fBitem style set\fR command, a new instance style is allocated which refers back to the master style and its master elements. In this way, a single master style may be shared by multiple columns of multiple items. If a master element or master style is modified, those changes affect all the items whose instance styles and elements refer to those masters. .PP Although you probably want the font and selection-rectangle colors to be shared by all items, you most likely don't want the text to be the same for every column of every item. The \fBitem element configure\fR command can be used to override a master element's configuration options for a specific column of an item. When you call \fBitem element configure\fR (or \fBitem text\fR or \fBitem image\fR), a new instance element is allocated, if one wasn't already, and that instance element's options will override the master element's. .PP All of the element configuration options described below are unspecified by default, meaning that no value whatsoever has been given to the option. It may seem strange to you that a boolean option would be unspecified instead of simply "true" or "false". The reason for this is that when an instance element used by an item has no value specified for an option, that instance element refers to the master element for the value of that option. This allows items which are displaying a certain element to be redisplayed when the master element's options change. The benefits of this are that you don't need to configure the font or text color for every item in a treectrl individually, saving CPU cycles and memory. .PP You may be thinking that to change the color of a selection rectangle you would call \fBitem element configure\fR when an item was selected, but that is not usually the case. It would be wasteful to allocate a new instance element for a selection rectangle just because an item became selected. The solution is to allow the appearance of the selection rectangle master element to change based on the selected state of the item. This is described in \fBPER-STATE OPTIONS\fR. .PP For each element type there is a section below describing the options which can modify an element of that type. .SH "BITMAP ELEMENT" An element of type \fBbitmap\fR can be used to display a bitmap in an item. The following options are supported for bitmap elements: .TP \fB\fB-background\fR\fR \fIcolor\fR Specifies as a \fBper-state\fR option the color to use for each of the bitmap's '0' valued pixels. If the value for a certain state is an empty string (the default), the bitmap is drawn transparent. .TP \fB\fB-bitmap\fR\fR \fIbitmap\fR Specifies as a \fBper-state\fR option the bitmap to display in the element. .TP \fB\fB-draw\fR\fR \fIboolean\fR Deprecated; use the style layout option \fB-draw\fR instead. Specifies as a \fBper-state\fR option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. .TP \fB\fB-foreground\fR\fR \fIcolor\fR Specifies as a \fBper-state\fR option the color to use for each of the bitmap's '1' valued pixels. If the value for a certain state is an empty string (the default), the bitmap's foreground color is black. .PP .SH "BORDER ELEMENT" An element of type \fBborder\fR can be used to display a 3D border in an item. The following options are supported for border elements: .TP \fB\fB-background\fR\fR \fIcolor\fR Specifies as a \fBper-state\fR option the color to use for the background of the border. If the value for a certain state is an empty string (the default), the element will not be drawn. .TP \fB\fB-draw\fR\fR \fIboolean\fR Deprecated; use the style layout option \fB-draw\fR instead. Specifies as a \fBper-state\fR option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. .TP \fB\fB-filled\fR\fR \fIboolean\fR Specifies whether the interior of the border should be filled with the background color. If this option is unspecified (the default), it it treated as false which means that only the edges of the border will be drawn. .TP \fB\fB-height\fR\fR \fIsize\fR Specifies the height of the border. If this value is unspecified (the default), the border will be exactly as tall as its display area as determined by the style layout options. .TP \fB\fB-relief\fR\fR \fIrelief\fR Specifies as a \fBper-state\fR option the relief of the border. If the value for a certain state is an empty string (the default), it is treated as flat. For acceptable values see the description of the \fB-relief\fR option in the \fBoptions\fR manual page. .TP \fB\fB-thickness\fR\fR \fIthickness\fR Specifies the thickness of the edges of the border. .TP \fB\fB-width\fR\fR \fIsize\fR Specifies the width of the border. If this value is unspecified (the default), the border will be exactly as wide as its display area as determined by the style layout options. .PP .SH "HEADER ELEMENT" An element of type \fBheader\fR can be used to display a themed (or non-themed) column header background and sort arrow. Header elements are best used surrounding other elements via the style layout option \fB-union\fR, so that the sort arrow can be displayed correctly. .PP Some of the options for this type of element get their default values from the \fBheader state\fR flags that are set in the column header in which the element is displayed. In particular, the \fB-arrow\fR option gets its default value by checking the \fBup\fR and \fBdown\fR state flags, and the \fB-state\fR option gets its default value by checking the \fBactive\fR, \fBnormal\fR, and \fBpressed\fR state flags. If elements of this type are displayed in an item instead of a column header, then this behavior isn't used since those state flags aren't meaningful for items. .PP The following options are supported for header elements: .TP \fB\fB-arrow\fR\fR \fIdirection\fR Indicates whether or not a sort arrow should be drawn. \fIDirection\fR must have one of the values \fBnone\fR, \fBup\fR, or \fBdown\fR. If unspecified, the value defaults to \fBnone\fR (but see the note above regarding header states). .TP \fB\fB-arrowbitmap\fR\fR \fIbitmap\fR Specifies as a \fBper-state\fR option the name of a bitmap to use to draw the sort arrow if this element's -arrow option is not \fBnone\fR. This option is ignored when drawing themed headers on Mac OS X. .TP \fB\fB-arrowgravity\fR\fR \fIdirection\fR Indicates onto which side the sort arrow should be packed, if there is more space available for drawing the arrow than needed. \fIDirection\fR must be either \fBleft\fR or \fBright\fR. If unspecified, the value defaults to \fBleft\fR. This option is ignored when drawing themed headers on Mac OS X. .TP \fB\fB-arrowimage\fR\fR \fIimage\fR Specifies as a \fBper-state\fR option the name of an image to use to draw the sort arrow if this element's -arrow option is not \fBnone\fR. If an image is specified for a certain state, it overrides the -arrowbitmap option. This option is ignored when drawing themed headers on Mac OS X. .TP \fB\fB-arrowpadx\fR\fR \fIamount\fR \fIAmount\fR specifies how much padding to leave on the left and right of the sort arrow. \fIAmount\fR may be a list of two values to specify padding for the left and right separately. If unspecified, the value defaults to 6. Padding to the right of the sort arrow is ignored when drawing themed headers on Mac OS X. .TP \fB\fB-arrowpady\fR\fR \fIamount\fR \fIAmount\fR specifies how much padding to leave on the top and bottom of the sort arrow. \fIAmount\fR may be a list of two values to specify padding for the top and bottom separately. If unspecified, the value defaults to 0. This option is ignored when drawing themed headers on Mac OS X. .TP \fB\fB-arrowside\fR\fR \fIside\fR Indicates on which side of the element the sort arrow should be drawn. \fISide\fR must be either \fBleft\fR or \fBright\fR. If unspecified, the value defaults to \fBright\fR. .TP \fB\fB-background\fR\fR \fIcolor\fR Specifies as a \fBper-state\fR option the color to use for the non-themed background and 3D border. If unspecified, the value defaults to either the Tk button widget's -background or -activebackground color. .TP \fB\fB-borderwidth\fR\fR \fIsize\fR Specifies a non-negative value indicating the width of the non-themed 3D border to draw around the inner edges of the element (if such a border is being drawn; the \fB-relief\fR option determines this). The value may have any of the forms acceptable to \fBTk_GetPixels\fR. If unspecified, the value defaults to 2. .TP \fB\fB-state\fR\fR \fIstate\fR Specifies one of three states for the element: \fBnormal\fR, \fBactive\fR, or \fBpressed\fR. The active state is used when the mouse is over the header. The pressed state is used when the mouse button is pressed in the header. If unspecified, the value defaults to \fBnormal\fR (but see the note above regarding header states). .PP .SH "IMAGE ELEMENT" An element of type \fBimage\fR can be used to display an image in an item. The following options are supported for image elements: .TP \fB\fB-draw\fR\fR \fIboolean\fR Deprecated; use the style layout option \fB-draw\fR instead. Specifies as a \fBper-state\fR option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. .TP \fB\fB-height\fR\fR \fIsize\fR Specifies the requested height of the display area for this element. If unspecified (the default), the element requests a height equal to the height of the image, or zero if there is no image. .TP \fB\fB-image\fR\fR \fIimage\fR Specifies as a \fBper-state\fR option the image to display in the element. .TP \fB\fB-tiled\fR\fR \fIboolean\fR Specifies a boolean indicating whether or not the image should be tiled horizontally and vertically within the display area for the element. The default is false. .TP \fB\fB-width\fR\fR \fIsize\fR Specifies the requested width of the display area for this element. If unspecified (the default), the element requests a width equal to the width of the image, or zero if there is no image. .PP .SH "RECTANGLE ELEMENT" An element of type \fBrect\fR can be used to display a rectangle in an item. The following options are supported for rectangle elements: .TP \fB\fB-draw\fR\fR \fIboolean\fR Deprecated; use the style layout option \fB-draw\fR instead. Specifies as a \fBper-state\fR option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. .TP \fB\fB-fill\fR\fR \fIcolor\fR Specifies as a \fBper-state\fR option the color to be used to fill the rectangle's area. If the color for a certain state is an empty string (the default), then the rectangle will not be filled (but the outline may still be drawn). .TP \fB\fB-height\fR\fR \fIsize\fR Specifies the height of the rectangle. If this value is unspecified (the default), the rectangle will be exactly as tall as its display area as determined by the style layout options. .TP \fB\fB-open\fR\fR \fIopen\fR Specifies as a \fBper-state\fR option which edges of the rectangle should be left open. This option may be used to get an incomplete drawing of the outline and rounded corners, often to give the appearance of the rectangle extending over adjacent columns or items. \fIOpen\fR is a string that contains zero or more of the characters \fBn\fR, \fBs\fR, \fBe\fR or \fBw\fR. Each letter refers to an edge (north, south, east, or west) on which the outline and rounded corners will not be drawn. The default is the empty string, which causes all rounded corners and the outline to be drawn. .TP \fB\fB-outline\fR\fR \fIcolor\fR Specifies as a \fBper-state\fR option the color to be used to draw the outline of the rectangle. If the color for a certain state is an empty string (the default), then no outline is drawn for the rectangle. .TP \fB\fB-outlinewidth\fR\fR \fIoutlineWidth\fR Specifies the width of the outline to be drawn around the rectangle's region. \fIoutlineWidth\fR may be in any of the forms acceptable to \fBTk_GetPixels\fR. If this option is specified as an empty string (the default), then no outline is drawn. .TP \fB\fB-rx\fR\fR \fIradius\fR .TP \fB\fB-ry\fR\fR \fIradius\fR Specifies the x and y radius of each corner of a rounded rectangle in any of the forms acceptable to \fBTk_GetPixels\fR. .TP \fB\fB-showfocus\fR\fR \fIboolean\fR Specifies a boolean value indicating whether a "focus ring" should be drawn around the rectangle, if the item containing the rectangle is the active item and the treectrl widget currently has the focus. If this option is specified as an empty string (the default), then a focus rectangle is not drawn. .TP \fB\fB-width\fR\fR \fIsize\fR Specifies the width of the rectangle. If this value is unspecified (the default), the rectangle will be exactly as wide as its display area as determined by the style layout options. .PP .SH "TEXT ELEMENT" An element of type \fBtext\fR can be used to display a text in an item. The following options are supported for text elements: .TP \fB\fB-draw\fR\fR \fIboolean\fR Deprecated; use the style layout option \fB-draw\fR instead. Specifies as a \fBper-state\fR option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. .TP \fB\fB-data\fR\fR \fIdata\fR Specifies a value that together with the \fB-datatype\fR and \fB-format\fR options will be displayed as text. .TP \fB\fB-datatype\fR\fR \fIdataType\fR Specifies the type of information in the \fB-data\fR option. Acceptable values are \fBdouble\fR, \fBinteger\fR, \fBlong\fR, \fBstring\fR, or \fBtime\fR. .TP \fB\fB-fill\fR\fR \fIcolor\fR Specifies as a \fBper-state\fR option the foreground color to use when displaying text. .sp In items, if the color for a certain state is an empty string (the default), then the text will be displayed using the color specified by the treectrl's \fB-foreground\fR option. .sp In headers, if the color for a certain state is an empty string, then the text will be displayed using the system theme color on Gtk+; if that color is not specified then the \fB-headerforeground\fR option is used. .TP \fB\fB-font\fR\fR \fIfont\fR Specifies as a \fBper-state\fR option the font to use when displaying the text. If the font for a certain state is an empty string, the text is displayed using the font specified by the treectrl's \fB-font\fR option in items or the \fB-headerfont\fR option in headers. .TP \fB\fB-format\fR\fR \fIformatString\fR This option specifies the format string used to display the value of the \fB-data\fR option. If \fB-datatype\fR is \fBtime\fR, \fIformatString\fR should be a valid format string for the Tcl \fBclock\fR command. For all other \fB-datatype\fR values \fIformatString\fR should be a valid format string for the Tcl \fBformat\fR command. If this value is unspecified the following defaults are used: for -datatype double "%g", for -datatype integer "%d", for -datatype long "%ld", for -datatype string "%s", and for -datatype time the default format string of the Tcl \fBclock\fR command. .TP \fB\fB-justify\fR\fR \fIhow\fR Specifies how to justify the text when multiple lines are displayed. \fIHow\fR must be one of the values \fBleft\fR, \fBright\fR, or \fBcenter\fR. If this option is specified as an empty string (the default), \fBleft\fR is used. .TP \fB\fB-lines\fR\fR \fIlineCount\fR Specifies the maximum number of lines to display. If more than \fIlineCount\fR lines would be displayed, the last line will be truncated with an ellipsis at the right. If this option is specified as zero or an empty string (the default), there is no limit to the number of lines displayed. .TP \fB\fB-lmargin1\fR\fR \fIpixels\fR \fIPixels\fR is a screen distance that specifies how much a line of text should be indented. If a line of text wraps, this option only applies to the first line on the display; the \fB-lmargin2\fR option controls the indentation for subsequent lines. If this option is specified as zero or an empty string (the default), then the line is not indented. This option was based on the Tk Text widget tag option of the same name. .TP \fB\fB-lmargin2\fR\fR \fIpixels\fR \fIPixels\fR is a screen distance that specifies how much a line of text should be indented. If a line of text wraps, this option only applies to the second and later display lines for a line of text. If this option is specified as zero or an empty string (the default), then the line is not indented. This option was based on the Tk Text widget tag option of the same name. .TP \fB\fB-text\fR\fR \fIstring\fR \fIString\fR specifies a string to be displayed by the element. \fIString\fR may contain newline characters in which case multiple lines of text will be displayed. If this option is specified, the \fB-data\fR, \fB-datatype\fR, \fB-format\fR, and \fB-textvariable\fR options are ignored. .TP \fB\fB-textvariable\fR\fR \fIvarName\fR Specifies the name of a variable. The value of the variable is a string to be displayed by the element; if the variable value changes then the element will automatically update itself to display the new value. If this option is specified, the \fB-data\fR, \fB-datatype\fR, and \fB-format\fR options are ignored. .TP \fB\fB-underline\fR\fR \fIcharIndex\fR Specifies the integer index of a character to underline. 0 corresponds to the first character. If \fIcharIndex\fR is unspecified (the default), less than zero or greater than the index of the last displayed character, the underline is not drawn. .TP \fB\fB-width\fR\fR \fIsize\fR Specifies the maximum line length in any of the forms acceptable to \fBTk_GetPixels\fR. For text to wrap lines the value of the \fB-width\fR option must be less than the needed width of the text, or the display area for this element must be less than the needed width of the text. For the display area to be less than the needed width of the text, one of the style layout options \fB-maxwidth\fR, \fB-width\fR or \fB-squeeze\fR must be used. .TP \fB\fB-wrap\fR\fR \fImode\fR \fIMode\fR specifies how to handle lines in the text that are longer than the maximum line length. Acceptable values are \fBnone\fR, \fBchar\fR or \fBword\fR. If this option is unspecified (the default), \fBword\fR is used. See the \fB-width\fR option for a description of how the maximum line length is determined. .PP .SH "WINDOW ELEMENT" An element of type \fBwindow\fR can be used to display a Tk window in an item. The following options are supported for window elements: .TP \fB\fB-clip\fR\fR \fIboolean\fR Specifies whether the associated Tk window is a borderless frame which should be used to clip its child window so it doesn't overlap the header, borders, or other items or columns. When this option is true, the treectrl manages the geometry of both the \fB-window\fR widget and its first child widget; in this case the \fB-window\fR widget (which should be a borderless frame) is kept sized and positioned so that it is never out-of-bounds. .TP \fB\fB-destroy\fR\fR \fIboolean\fR Specifies whether the associated Tk window should be destroyed when the element is deleted. The element is deleted when the item containing the element is deleted, when the column containing the element is deleted, or when the style assigned to the item's column is changed. If this option is unspecified (the default), it is treated as false and the Tk window will not be destroyed. .TP \fB\fB-draw\fR\fR \fIboolean\fR Deprecated; use the style layout option \fB-draw\fR instead. Specifies as a \fBper-state\fR option whether to draw the element. If the value for a certain state is an empty string (the default), it is treated as true and the element will be drawn. .TP \fB\fB-window\fR\fR \fIpathName\fR Specifies the window to associate with this element. The window specified by \fIpathName\fR must either be a child of the treectrl widget or a child of some ancestor of the treectrl widget. \fIPathName\fR may not refer to a top-level window. This option cannot be specified by the \fBelement create\fR or \fBelement configure\fR commands, only by the \fBitem element configure\fR command; i.e., the element must be associated with a particular item. .PP .SH "ITEM DESCRIPTION" Many of the commands for a treectrl take as an argument a description of which items to operate on. An item description is a properly-formed tcl list of keywords and arguments. The first word of an item description must be one of the following: .TP \fIid\fR Specifies the unique item identifier, where \fIid\fR should be the return value of a prior call of the \fBitem create\fR widget command, or \fB0\fR to specify the ever-present root item. See also the \fB-itemprefix\fR option. .TP \fIQUALIFIERS\fR Specifies a list of qualifiers. This gives the same result as \fBall\fR followed by \fIQUALIFIERS\fR; i.e., every item is tested for a match. .TP \fItagExpr\fR \fIQUALIFIERS\fR \fITagExpr\fR is a tag expression (see \fBITEM AND COLUMN TAGS\fR) against which every item's tags are tested for a match. This keyword cannot be followed by any modifiers unless a single item is matched. You may run into trouble if \fItagExpr\fR looks like an item id or other keyword; also, \fItagExpr\fR must look like a single list element since item descriptions are properly-formed lists. To be safe you may want to use the \fBtag\fR qualifier followed by \fItagExpr\fR. .TP \fBactive\fR Indicates the item that is currently active, i.e. normally the item specified as argument of the last successful \fBactivate\fR widget command, or the root item if no such call happened yet. .TP \fBanchor\fR Indicates the anchor item of the selection, i.e. normally the item specified as argument of the last successful \fBselection anchor\fR widget command, or the root item if no such call happened yet. .TP \fBall\fR \fIQUALIFIERS\fR Indicates every item including orphans which match \fIQUALIFIERS\fR. This keyword cannot be followed by any modifiers unless a single item is matched. .TP \fBfirst\fR \fIQUALIFIERS\fR Indicates the first item of the treectrl (the root item), or the first item matching \fIQUALIFIERS\fR. .TP \fBend\fR \fIQUALIFIERS\fR .TP \fBlast\fR \fIQUALIFIERS\fR Indicates the last item which matches \fIQUALIFIERS\fR. .TP \fBlist\fR \fIitemDescs\fR \fIItemDescs\fR is a list (a single argument, i.e. "list {a b c}" not "list a b c") of other item descriptions. This keyword cannot be followed by any modifiers unless a single item is matched. .TP \fBnearest\fR \fIx y\fR Indicates the item nearest to the point given by \fIx\fR and \fIy\fR. .TP \fBrnc\fR \fIrow column\fR Indicates the item in the given \fIrow\fR and \fIcolumn\fR. The row and column corresponds to the on-screen arrangement of items as determined by the -orient and -wrap options. You can memorize \fBrnc\fR as an abbreviation of "row 'n' column". .TP \fBrange\fR \fIfirst last\fR \fIQUALIFIERS\fR \fIFirst\fR and \fIlast\fR specify a range of items. This keyword cannot be followed by any modifiers unless a single item is matched. .TP \fBroot\fR Indicates the root item of the treectrl. .PP .PP The initial part of the item description (matching any of the values above) may be followed by one or more \fImodifier\fRs. A modifier changes the item used relative to the description up to this point. It may be specified in any of the following forms: .TP \fBabove\fR Use the item one row above in this column. .TP \fBancestors\fR \fIQUALIFIERS\fR Use the ancestors of the item (like \fBitem ancestors\fR but QUALIFIERS may change which ancestors match). This keyword cannot be followed by any modifiers. .TP \fBbelow\fR Use the item one row below in this column. .TP \fBbottom\fR Use the item in the last row of this column. .TP \fBchild\fR \fIn\fR \fIQUALIFIERS\fR Use the \fIn\fRth child of the item. .TP \fBchildren\fR \fIQUALIFIERS\fR Use the children of the item (like \fBitem children\fR but QUALIFIERS may change which children match). This keyword cannot be followed by any modifiers. .TP \fBdescendants\fR \fIQUALIFIERS\fR Use the descendants of the item (like \fBitem descendants\fR but QUALIFIERS may change which descendants match). This keyword cannot be followed by any modifiers. .TP \fBfirstchild\fR \fIQUALIFIERS\fR Use the first child of the item. .TP \fBlastchild\fR \fIQUALIFIERS\fR Use the last child of the item. .TP \fBleft\fR Use the item one column to the left in the same row. .TP \fBleftmost\fR Use the item of the first column in the same row. .TP \fBnext\fR \fIQUALIFIERS\fR Use the next item, which is the first item from the following list: the first child, the next sibling or the next sibling of the nearest ancestor which has one. .TP \fBnextsibling\fR \fIQUALIFIERS\fR Use the next sibling of the item. .TP \fBparent\fR Use the parent of the item. .TP \fBprev\fR \fIQUALIFIERS\fR Use the last child of the previous sibling, or the parent if there is no previous sibling. .TP \fBprevsibling\fR \fIQUALIFIERS\fR Use the previous sibling of the item. .TP \fBright\fR Use the item one column to the right in the same row. .TP \fBrightmost\fR Use the item of the last column in the same row. .TP \fBsibling\fR \fIn\fR \fIQUALIFIERS\fR Use the \fIn\fRth child of the item's parent. .TP \fBtop\fR Use the item in the first row of this column. .PP The word \fIQUALIFIERS\fR above represents a series of zero or more of the following terms that changes which item is chosen: .TP \fBdepth\fR \fIdepth\fR Matches items whose depth (as returned by the \fBdepth\fR command) is equal to \fIdepth\fR. .TP \fBstate\fR \fIstateList\fR \fIStateList\fR is a list of item state names (static and dynamic, see \fBSTATES\fR). Only items that have the given states set (or unset if the '!' prefix is used) are considered. .TP \fBtag\fR \fItagExpr\fR \fITagExpr\fR is a tag expression (see \fBITEM AND COLUMN TAGS\fR) against which an item's tags are tested for a match. .TP \fBvisible\fR When this qualifier is given, only items that are displayed are considered. .TP \fB!visible\fR When this qualifier is given, only items that are *not* displayed are considered. .PP To get the first item in the list that is enabled: .nf $T item id "first state enabled" .fi To get the ancestors that are not open of the last item in the list: .nf $T item id "last ancestors state !open" .fi To get the visible descendants of the root item: .nf $T item id "root descendants visible" .fi To get the every hidden item with tag "a" or "b": .nf $T item id "all !visible tag a||b" $T item id "!visible tag a||b" $T item id "tag a||b !visible" $T item id "a||b !visible" .fi .SH "EVENTS AND SCRIPT SUBSTITUTIONS" The \fIscript\fR argument to \fBnotify bind\fR is a Tcl script, which will be evaluated whenever the given event is generated. \fIScript\fR will be executed in the same interpreter that the \fBnotify bind\fR command was executed in, and it will run at global level (only global variables will be accessible). If \fIscript\fR contains any \fB%\fR characters, then the script will not be evaluated directly. Instead, a new script will be generated by replacing each \fB%\fR, and the character following it, with information from the current event. Unlike the regular Tk \fBbind\fR mechanism, each event generated by a treectrl widget has its own set of %-substitutions. .PP The following %-substitutions are valid for all static events: .TP \fB%%\fR Replaced with a single % .TP \fB%d\fR The detail name .TP \fB%e\fR The event name .TP \fB%P\fR The pattern, either or .TP \fB%W\fR The object argument to the \fBnotify bind\fR command .TP \fB%T\fR The treectrl widget which generated the event .TP \fB%?\fR A list of the format {char value char value ...} for each %-substitution character and the value it is replaced by .PP .PP The following events may be generated by a treectrl widget: .TP \fB\fR Generated whenever the active item changes. .RS .TP \fB%c\fR The current active item .TP \fB%p\fR The previous active item .RE .TP \fB\fR Generated before an item is collapsed. .RS .TP \fB%I\fR The item id .RE .TP \fB\fR Generated after an item is collapsed. .RS .TP \fB%I\fR The item id .RE .TP \fB\fR Generated before an item is expanded. This event is useful if you want to add child items to the item just before the item is expanded. .RS .TP \fB%I\fR The item id .RE .TP \fB\fR Generated after an item is expanded. .RS .TP \fB%I\fR The item id .RE .TP \fB\fR Generated when items are about to be deleted by the \fBitem delete\fR command. .RS .TP \fB%i\fR List of items ids being deleted. .RE .TP \fB\fR Generated when items become visible on screen and when items are no longer visible on screen. This event is useful if you have a very large number of items and want to assign styles only when items are actually going to be displayed. .RS .TP \fB%h\fR List of items ids which are no longer visible. .TP \fB%v\fR List of items ids which are now visible. .RE .TP \fB\fR Generated whenever the view in the treectrl changes in such a way that a horizontal scrollbar should be redisplayed. .RS .TP \fB%l\fR Same as the first fraction appended to \fB-xscrollcommand\fR. Think \fIlower\fR. .TP \fB%u\fR Same as the second fraction appended to \fB-xscrollcommand\fR. Think \fIupper\fR. .RE .TP \fB\fR Generated whenever the view in the treectrl changes in such a way that a vertical scrollbar should be redisplayed. .RS .TP \fB%l\fR Same as the first fraction appended to \fB-yscrollcommand\fR. Think \fIlower\fR. .TP \fB%u\fR Same as the second fraction appended to \fB-yscrollcommand\fR. Think \fIupper\fR. .RE .TP \fB\fR Generated whenever the selection changes. This event gives information about how the selection changed. .RS .TP \fB%c\fR Same as the \fBselection count\fR widget command .TP \fB%D\fR List of newly-deselected item ids .TP \fB%S\fR List of newly-selected item ids .RE .PP .SH "DYNAMIC EVENTS" In addition to the pre-defined static events such as and , new dynamic events can be created by using the \fBnotify install\fR command. .PP The library scripts provide an example of using a dynamic event called , which is generated when the mouse button is clicked and released over a column header. .nf # Example application code treectrl .t .t notify install .t notify bind MyTag { puts "column header %C clicked in header-row %H in treectrl %T" } # Library code in treectrl.tcl proc ::TreeCtrl::Release1 {w x y} { ... $w notify generate [list H $Priv(header) C $Priv(column)] \\ [list ::TreeCtrl::PercentsCmd $w] ... } .fi In the example above, a new treectrl widget is created and the event is installed. A script is bound to the event with \fBnotify bind\fR which will print out the column ID, header ID and widget name to the console. In a real application, any script bound to would be used to sort the list based on the column header that was clicked. .PP Note there is no \fIpercentsCommand\fR argument to \fBnotify install\fR; instead, the call to \fBnotify generate\fR specifies the %-substitution command. The \fIcharMap\fR argument to \fBnotify generate\fR provides a list of %-substitution characters and values which is used by ::TreeCtrl::PercentsCmd. In the example, any %C in any script bound to the event would be replaced by the value of $Priv(column), and %H would be replaced by $Priv(header). The library procedure ::TreeCtrl::PercentsCmd also supports the same common %-substitution characters as the built-in static events, such as %T, %P, %? etc. .PP The following dynamic events may be generated by the library scripts: .TP \fB\fR This event is generated just after the user begins dragging a column header. At the time this event is generated, the \fBheader dragconfigure\fR option \fB-imagecolumn\fR is set to the unique ID of the column being dragged, the \fB-imageoffset\fR option is set to the horizontal distance the mouse pointer has moved, and the \fB-imagespan\fR option is set to the span of the column header that was initially clicked. .TP \fB\fR This event is generated each time a new place to drop the dragged column header is found. At the time this event is generated, the \fBheader dragconfigure\fR option \fB-indicatorcolumn\fR is set to the unique ID of the column before or after which the dragged column will be dropped, and the \fB-indicatorspan\fR option is set to the span of the column header for this newly-chosen indicator column. .TP \fB\fR This event is generated when the user has successfully dragged and dropped a column header to a new position. The library scripts do not actually move the dragged column. You must bind a script to this event to move the column. See \fBEXAMPLES\fR. .TP \fB\fR This event is generated after the user finally releases the left mouse button while dragging a column header. This event is generated after all the other events even when the column wasn't dragged to a new location (i.e., even when no \fB\fR event was generated). .RS .TP \fB%H\fR The \fBheader-row\fR that contains the column header. .TP \fB%C\fR The column whose header is dragged within the header-row. .TP \fB%b\fR The column to move the dragged column(s) before. Valid for \fB\fR only. .RE .TP \fB\fR .TP \fB\fR .TP \fB\fR Generated whenever the user drag-and-drops a file into a directory. This event is generated by the filelist-bindings.tcl library code, which is not used by default. See the "Explorer" demos. .RS .TP \fB%I\fR The item that the user dropped the dragged items on. .TP \fB%l\fR (lowercase L) The list of dragged items. .RE .TP \fB\fR .TP \fB\fR .TP \fB\fR The filelist-bindings.tcl code will display a text-editing window if the user clicks on a selected file/folder name. See the "Explorer" demos. .RS .TP \fB%I\fR The item containing the edited text element. .TP \fB%C\fR The column containing the edited text element. .TP \fB%E\fR The name of the edited text element. .TP \fB%t\fR The edited text. .RE .TP \fB\fR Generated whenever the user clicks and releases the left mouse button in a column header if the column header's -button option is true. You can bind a script to this event to sort the list. .RS .TP \fB%H\fR The \fBheader-row\fR that contains the column header. .TP \fB%C\fR The column whose header was clicked. .RE .TP \fB\fR Generated when the column header option \fB-state\fR is changed by the library scripts during Motion and Button events. .RS .TP \fB%H\fR The \fBheader-row\fR that displays the column header. .TP \fB%C\fR The column within the header-row whose header option \fB-state\fR changed. .TP \fB%s\fR The new value of the column header option \fB-state\fR. .RE .PP .SH "DEFAULT BINDINGS" Tk automatically creates class bindings for treectrl widgets that give them the following default behavior. .IP [1] Clicking mouse button 1 over an item positions the active cursor on the item, sets the input focus to this widget, and resets the selection of the widget to this item, if it is not already in the selection. .IP [2] Clicking mouse button 1 with the Control key down will reposition the active cursor and add the item to the selection without ever removing any items from the selection. .IP [3] If the mouse is dragged out of the widget while button 1 is pressed, the treectrl will automatically scroll to make more items visible (if there are more items off-screen on the side where the mouse left the window). .IP [4] The Left and Right keys move the active cursor one item to the left or right; for an hierarchical tree with vertical orientation nothing will happen, since it has no two items in the same row. The selection is set to include only the active item. If Left or Right is typed with the Shift key down, then the active cursor moves and the selection is extended to include the new item. .IP [5] The Up and Down keys move the active cursor one item up or down. The selection is set to include only the active item. If Up or Down is typed with the Shift key down, then the active cursor moves and the selection is extended to include the new item. .IP [6] The Next and Prior keys move the active cursor forward or backwards by one screenful, without affecting the selection. .IP [7] Control-Next and Control-Prior scroll the view right or left by one page without moving the active cursor or affecting the selection. Control-Left and Control-Right behave the same. .IP [8] The Home and End keys scroll to the left or right end of the widget without moving the active cursor or affecting the selection. .IP [9] The Control-Home and Control-End keys scroll to the top or bottom of the widget, they also activate and select the first or last item. If also the Shift key is down, then the active cursor moves and the selection is extended to include the new item. .IP [10] The Space and Select keys set the selection to the active item. .IP [11] Control-/ selects the entire contents of the widget. .IP [12] Control-\\\\ clears any selection in the widget. .IP [13] The + and - keys expand or collapse the active item, the Return key toggles the active item. .IP [14] The mousewheel scrolls the view of the widget four lines up or down depending on the direction, the wheel was turned. The active cursor or the selection is not affected. .PP .SH GRADIENTS Color gradients are an easy way to give your lists a more modern appearance. Since Tk provides no support for drawing gradients, the TkPath extension was used as a guide when implementing gradients in TkTreeCtrl. The current implementation has some limitations, however: .IP [1] Only linear gradients are supported. .IP [2] Gradients can only be painted left-to-right or top-to-bottom, not at arbitrary angles. .IP [3] Gradients look bad on low-color displays. Before using gradients, you should check that the display's color depth is at least 15 or 16 by calling the \fBwinfo depth\fR command. .IP [4] Gradients are fully opaque when XFillRectangle() is used to draw them (see below). This means the \fBopacity\fR value of each color stop is ignored. Keep that in mind if your application is cross-platform. .IP [5] Rounded rectangles cannot be filled or outlined with a gradient when XFillRectangle() is used to draw gradients (see below). Instead, the rounded rectangle is painted with the gradient's first \fB-stops\fR color. .PP Gradients may be used in the following places: .IP [1] The -gridleftcolor and -gridrightcolor options of columns. .IP [2] The -itembackground option of columns. .IP [3] The -fill and -outline options of rect elements. .IP [4] The -fill and -outline options of the \fBmarquee configure\fR command. .PP .PP On Microsoft Windows, GDI+ is used where it is available (gdiplus.dll is dynamically loaded at run-time). On Mac OS X, CoreGraphics is used to draw gradients. With the Gtk+ build of treectrl, libcairo is used to draw gradients. When native gradient support is available, all the talk below about \fB-steps\fR can safely be ignored. .PP When no native support for gradients is available, gradients are drawn simply by filling sub-rectangles using XFillRectangle(). The number of sub-rectangles drawn and number of colors that make up the displayed gradient are controlled by the gradient's \fB-steps\fR and \fB-stops\fR options. The number of sub-rectangles is equal to the length of the \fB-stops\fR option multiplied by the value of the \fB-steps\fR option. For example: .nf $T gradient create myGradient -stops {{0 white} {1 gray}} -steps 8 .fi This gradient will be drawn with 2x8=16 sub-rectangles of color. The higher the \fB-steps\fR value, the smoother the color transitions will be, and the slower the gradient will be to draw. For the best appearance, make the number of sub-rectangles drawn less than or equal to the height or width of the gradient being drawn. So if you have a rect element 18 pixels tall, use a vertical gradient that has steps X stops=18. Avoid using gradients with steps X stops greater than the height or width of the rectangle being drawn, because then colors will overlap. .SH "GRADIENT COORDINATES" By default, a gradient brush is exactly the same size as whatever rectangle is being painted. For example, if a column's \fB-itembackground\fR option specifies a gradient name, then the background of an item is painted with all the colors of the gradient. So a vertical gradient from blue to green will start blue at the top and end with green at the bottom of every item. .PP By specifying any of the \fB-bottom\fR, \fB-left\fR, \fB-right\fR or \fB-top\fR gradient options the size of the gradient brush does not need to match that of the rectangle being painted. These options can be used to make a gradient appear to span across the entire width or height of the treectrl window, or across the entire \fBcanvas\fR, for example. .PP There is no point specifying \fB-left\fR or \fB-right\fR if the gradient is vertical, since the gradient's colors are constant horizontally, so changing the horizontal size of the brush won't change the appearance of the gradient. The same reasoning applies for the \fB-top\fR and \fB-bottom\fR options for a horizontal gradient. .PP .nf package require treectrl set T [treectrl .t -itemheight 20 -showheader no] $T gradient create G1 -orient vertical -top {0.0 canvas} -bottom {1.0 canvas} \\ -stops {{0.0 blue} {0.5 green} {1.0 red}} -steps 25 $T column create -expand yes -itembackground G1 pack $T -expand yes -fill both .fi .SH EXAMPLES Get the unique identifier for the leftmost visible column: .nf set id [$T column index "first visible"] .fi Delete the leftmost column: .nf $T column delete "order 0" .fi Take the visible column that is to the left of the last column, and move that column in front of the tail column: .nf $T column move "last prev visible" tail .fi Get the unique identifier for the first visible item: .nf set id [$T item index "first visible"] .fi Delete the parent of the item that is under the point x,y: .nf $T item delete "nearest $x $y parent" .fi Add the 10th child of the second child of the root item to the selection: .nf $T selection add "root firstchild nextsibling child 10" .fi Move a column that the user drag-and-dropped: .nf $T header dragconfigure -enable yes $T notify install $T notify bind MyTag { %T column move %C %b } .fi .SH "SEE ALSO" bind(n), bitmap(n), image(n), listbox(n), options(n) .SH KEYWORDS tree, widgettktreectrl-2.4.1/doc/What-is-New-in-TkTreeCtrl.html0000644000076400010400000032217511646360115022353 0ustar TimAdministrators What's New in TkTreeCtrl

What's New in TkTreeCtrl 2.4.1

Bug Fixes

  • [BUG 3421503] Creating a new treectrl widget would crash the application if the default value of either of the -buttonbitmap or -buttonimage options was changed using the Tk option database.
  • [BUG 3421503] Random crashes could result when using hidden columns due to writing past the end of an array.

What's New in TkTreeCtrl 2.4

Changes since 2.4b2:
  • There were no changes since 2.4b2.
Changes since 2.4b1:
  • Fixed the header config option -text being treated like a per-state option.
  • Fixed rectangle and 3D border drawing on X11 due to 16-bit coordinates.  When items or headers were very wide, rectangles and borders wouldn't be drawn correctly.
  • Fixed dragging headers in locked columns not displaying correctly.
  • Fixed [identify] when right-locked headers were drawn over left-locked headers, the point was reported as being in the left-locked headers.
  • Fixed a library-script error when dragging headers when only locked columns were visible.
  • Fixed -canvaspady being ignored when only locked columns were visible.
  • Fixed the column-resize proxy line going past the right edge of a column when resizing right-locked columns.
  • Right-locked columns are always resized by their left edge now.  Previously, only the leftmost and rightmost right-locked columns were resized by their left edge, which was inconsistent and weird.
  • If an instance element was displaying its master's -textvariable string, the instance element would not be redisplayed when that -textvariable variable was modified.
  • The spans of dragged headers are restricted to the range of dragged columns, and the spans of non-dragged headers are terminated if they reach the first dragged column.
  • Improved column-spanning behavior.  See "Column Spanning" below.
  • Fixed widget borders not being redrawn if an <Expose> event didn't also overlap the content area.
  • Fixed the -background and -borderwidth header options being ignored in the tail column.
  • Fixed a few memory leaks with the new column header code.

Header Command

New
Comment
header create
Creates a new row of column headers.  The result is a unique ID for that header-row.
header delete
Deletes one or more header-rows.  The top header-row, created when a treectrl is created, cannot be deleted.
header cget
header configure
These commands work on both entire header-rows and individual columns within header-rows.  The column configure command may also be used to configure column headers in the top header-row.
header bbox
header compare
header count
header element
header id
header image
header span
header state
header style
header text
header tag
These commands have the same syntax as the item subcommands of the same name.
Header-rows are actually implemented as items.

The header image and header text commands will change either the first image or text element in a custom style assigned to a column header, or the -image and -text options of a column header when no custom style is assigned.

The header state command operates on header states, which are distinct from item states. See the updated section called STATES in the manual.
header dragcget
header dragconfigure
Same as the column dragcget and column dragconfigure commands.

The visual feedback when dragging column headers has changed.  As a result, the following options are deprecated and have no effect:
  • -imagecolor
  • -indicatorcolor
  • -indicatorside

Column Configuration Options

Option
Comment
-arrow direction
-arrowbitmap bitmap
-arrowgravity direction
-arrowimage image
-arrowpadx amount
-arrowpady amount
-arrowside side
-background color
-bitmap bitmap
-borderwidth size
-button boolean
-font fontName
-image image
-imagepadx amount
-imagepady amount
-justify justification
-state state
-text text
-textcolor color
-textlines count
-textpadx amount
-textpady amount
All these options related to column headers are no longer a part of a column itself.  Instead, these options were moved to the new column header API.

These options can still be accessed using column cget and column configure, but only for the top row of column headers.

To access these options in header-rows other than the top row, use the header cget and header configure command.

Element Command

Arguments Changed
Comment
element create
element cget
The new option -statedomain accepts a value of item or header.  The default value is item.  This option is used to distinguish between elements used in items and elements used in column headers, since items and headers have a different set of state flags.  The value of this option cannot  be changed.

Item Command

New
Comment
item state define
item state linkage
item state names
item state undefine
All the old subcommands of the widget state command are now in the updated item state command.  This was done because items and headers have a different set of states.  Defining new header states is done using the new header state command.

Style Command

Arguments Changed
Comment
style create
style cget
The new option -statedomain accepts a value of item or header.  The default value is item.  This option is used to distinguish between styles used in items and styles used in column headers, since items and headers have a different set of state flags.  The value of this option cannot  be changed.
style layout
A new style layout option was added called -center.  The -center option allows one or more elements to be centered within a style.

TreeCtrl Command

Arguments/Result Changed
Comment
bbox
Three new areas are defined, header.left, header.none, and header.right, to get the bounds of the different groups of locked/unlocked column headers.  The words after "header." are each possible value of the column option -lock.
identify
To make the result of this command easier to use, especially with the new column header code, a new option was added that sets the elements of an array variable rather than returning the result as a list.
.t identify -array id $x $y
The above call will alter the array variable named "id" with info about what is under the given coordinates.

TreeCtrl Configuration Options

New Comment
-headerfont
This is the font used for drawing text in column headers.  The default value is TkHeadingFont where that font is defined (usually on Tk 8.5+), otherwise it is the default listbox font.  On Mac OS X, TkHeadingFont is the small system font used for drawing text in the fixed-height headers.
This new option results in a different default look to column text on X11, where TkHeadingFont is a bold font.
-headerfg
-headerforeground
This is the foreground text color used when drawing text in column headers.  On Gtk+, the system theme may override this color.

Headers

The treectrl widget now supports multiple rows of column headers.  In the documentation, an entire row of column headers is referred to as a header-row.
  • There is always one header-row with the unique ID "0".  It may also be referred to using the header description "first". This top header-row cannot be deleted.
  • Configuring column header options (such as -image and -text) in the top header-row can be done using column configure, the same as in previous versions. To configure column header options in specific header-rows, the header configure command must be used.
  • Column spanning is supported using the header span command.
  • The appearance of column headers may be customized using styles. When creating elements and styles for use in column headers, the "-statedomain header" option must be used.
    .t element create MyHeaderElement text -statedomain header
    .t style create MyHeaderStyle -statedomain header

Element Changes

  • There is a brand-new element type called header which displays a themed (or non-themed) column header background and sort arrow.
  • To support the new column header code - which is implemented using styles - bitmap, image, and text elements are offset by 1,1 pixels when displayed in a column header that is in the "pressed" state.
  • The default color of text elements in column headers is -headerforeground, not -foreground.
  • The default font of text elements in column headers is -headerfont, not -font.

Event Changes

  • The <ColumnDrag> and <Header> events have a new substitution character, %H, which is replaced by the unique ID of the header-row involved.
  • A new event, <ColumnDrag-indicator>, is generated whenever the place to drop a dragged column header is updated.
  • A new event, <Header-state>, is generated whenever the state of an individual column header is changed during mouse-pointer events.

Column Spanning

Previously, a style spanning more than one column would request all of its width in the first column of the span. Now, a style distributes its width across all the visible columns in a span, taking into account the -minwidth, -width, and -maxwidth column options.

Also, when calculating the needed height of an item or header, spans were ignored.  Only the width of the first column in a span was considered when calculating the needed height of a style.  As a result, an item might appear much taller than it needed when lines of text were wrapping.

Demo Changes

  • A new demo called "Headers" was added to demonstrate multiple rows of column headers and customizing the appearance of column headers using styles.
  • The "Column Spanning" demo was updated to take advantage of the new column-spanning algorithm.  Previously, the -width option of each column needed to be set to the width of the "Span 1" style, otherwise the columns would have been as wide as the widest style in that column, and resizing columns caused gaps to appear between styles.
  • The three "Gradients" demos were updated to take advantage of the new column-spanning algorithm.  Previously, the -width of the text elements displaying long lines of descriptive text was set to the total width of the columns.  If the text was allowed to wrap, the height of the items would be wrong since spans were ignored.  Now the text wraps nicely when columns are resized.

What's New in TkTreeCtrl 2.3.2

Bug Fixes

  • Fixed a bug where elements could expand too much, due to not accounting for the padding of elements in a -union correctly.
  • Build fix: don't use GNU Make conditionals in the Makefile.  Instead, parts of the name of the archive created by the 'dist-win' target are calculated in configure.ac.
  • Build fix: make sure $MATH_LIBS (including -lm on AIX) is added to the list of link libraries on Unix platforms.
  • Build fix: removed trailing commas from some enum declarations to make strict C89 compilers happy (i.e., AIX).
  • Build fix: the Mac OS X SDK prior to version 10.5 does not have CGFloat defined.
  • Build fix: the Microsoft Platform SDK does not include <vsstyle.h>, unlike the Windows SDK, therefore that header file is no longer used.

What's New in TkTreeCtrl 2.3.1

Style Configuration Options

NewComment
-buttony
This option allows you to specify the distance from the top of an item that the expand/collapse button is drawn.  When the value of this option is unspecified, the button is centered vertically in the item.

Demo Changes

  • The Style Editor now has 2 scale widgets to make testing the -expand and -squeeze layout options easier.
  • Rewrote the "Outlook Express (Folders)" demo to use a single item style instead of 4 different styles.
  • Fixed an off-by-1 error in the placement of the iMovie demo name-editing entry widget.

Bug Fixes

  • 64bit: Fixed pointer truncation leading to crashes when memory allocations exceeded 4GB.
  • 64bit: Lots of casting to quiet MSVC compiler warnings.
  • 64bit: Fixed shellicon debug build failure when using MSVC.
  • Removed the use of <gdiplus.h> which broke MinGW-w64 builds and MinGW32 cross-compilation.
  • Fixed panic() when running the X11 debug build.
  • Use Tcl_PrintDouble() and Tcl_NewDoubleObj() instead of the %g specifier to fix a bug reported on comp.lang.tcl where the floating point numbers passed to the scrollbar command contained a comma (due to a locale issue).
  • Hit-testing of buttons now considers the vertical placement and size of buttons. Previously, the [identify] command would report that the given coordinates were over a button no matter how tall the item was.
  • Mac OS X: Column header layout was broken, resulting in incorrect justification of the header bitmap/image/text as well as the sort arrow being drawn overtop the bitmap/image/text.
  • The needed width of all item styles in a column was not being recalculated when deleting items.
  • The needed width of column headers was not being recalculated when the -usetheme option changed.
  • Some commands, such as [item bbox], would return incorrect results if called after a column was resized but before the next display update.
  • The calculation of the minimum size needed by a style was broken when -squeeze layout was used except for -squeeze=x -orient=horizontal.
  • The -itembackground colors were not being drawn when a transparent -backgroundimage was used.

What's New in TkTreeCtrl 2.3

Changes since 2.3b1
  • Removed the gradient api command.
  • New option -enabled may be passed to the item create command.
  • The Escape key cancels any drag-and-drop in progress with the TreeCtrlFileList bindings.
  • With -selectmode=single the marquee is not used with the TreeCtrlFileList bindings.
  • Fixed the <Escape> key causing an error when the last visible item was selected.
  • Updated the documentation to include -gridleftcolor and -gridrightcolor.
  • Added a section to the documentation titled THE CANVAS and linked to that section wherever the canvas is mentioned.

Column Configuration Options

New
Comment
-gridleftcolor
-gridrightcolor
So-called "grid lines". These two options specify a color or gradient to draw on the left and/or right edge of the column.  The lines are drawn overtop an item's style and down in the whitespace region below any items.
Usage Changed
How it changed
-itembackground
Item background colors can be a Tk color or a gradient name.

Item background colors are now drawn below items in the whitespace region even when item wrapping is being used.  Previously item background colors were not drawn below items when wrapping was used.
-textcolor
This is now a per-state option, just like the -background option, which may be incompatible.  If you previously specified a Tk color name with a space in it, such as "light blue", then you will need to make the value a proper list:
$T column configure $C -textcolor [list "light blue"]
When this option is unspecified (the default), the system theme can specify the color.  Currently that behavior is only used with the Gtk+ build of treectrl.

Item Command

New
Comment
buttonstate
The value of this option can be active, normal or pressed.  This is used to change the appearance of the expand/collapse buttons.  On Gtk+ the buttons change appearance when the mouse pointer is over them and when they are clicked.  On Mac OS X the buttons change appearance when they are clicked.  On MS Windows the buttons change appearance when the mouse pointer is over them, but only when the Explorer theme is used (see the new theme setwindowtheme command).
Arguments Changed
What changed
create
New option -enabled.
collapse
expand
toggle
A new option -animate was added to support animated disclosure triangles on Gtk+ and Mac OS X.  The library scripts pass the -animate option when clicking on a button, but not when toggling items using the keyboard.

Marquee Configuration Options

NewComment
-fill
Specifies the fill color for the selection rectangle.  The value can be a Tk color or a gradient name or an empty string (the default).  When this option isn't an empty string the dotted outline is not drawn.  By specifying the name of a semi-transparent gradient a modern-looking selection rectangle can be achieved.
-outline
Specifies the outline color for the selection rectangle.  The value can be a Tk color, a gradient name, or an empty string which is the default.  When this option isn't an empty string the dotted outline is not drawn.

Style Layout Options

Behavior Changed
What changed
-union
Previously, nesting -union elements had undefined behavior.  Now it is ok to include an element with -union layout in another element's -union list.

TreeCtrl Configuration Options

New Comment
-bgimage
This is a synonym for the -backgroundimage option.
-bgimageanchor Controls the alignment of the -backgroundimage.  The value is a standard Tk anchor position such as "nw", "se" or "center", etc.  The image is aligned to the content area when the image doesn't scroll, otherwise the image is aligned to the canvas.  The default is "nw".
-bgimageopaque
A boolean that indicates whether or not the -backgroundimage is partially transparent.  This is needed because there is no way to tell in Tk whether an image contains transparency.  The default is true, so if you use a transparent -backgroundimage you must set this to false.
-bgimagescroll
Controls whether the -backgroundimage scrolls along with the items or remains locked in place.  The value can be an emptry string for no scrolling, "x" for horizontal scrolling only, "y" for vertical scrolling only, or "xy" (the default) for scrolling in both directions.
-bgimagetile
Controls whether the -backgroundimage is tiled along the x and y axes.  The value can be "", "x", "y" or "xy" (the default).
-buttontracking
On Mac OS X and Gtk+ the expand/collapse buttons don't toggle when they are clicked, only when the mouse button is released over them, like regular pushbuttons.  The value of this option is a boolean; when true the buttons toggle when the mouse button is released, when false the buttons toggle when clicked.  The default is true on Mac OS X and Gtk+, false on Win32 and X11.
-canvaspadx
-canvaspady
These options allow whitespace margins around the edges of the canvas.  This is useful for 2D views where you don't want the items to butt against the window borders.  The value of each option is a list of one or two screen distances specifying the width of the left/right margins and the height of the top/bottom margins respectively.
-itemgapx
-itemgapy
These options allow whitespace gaps between adjacent items.  This is useful for 2D views such as an icon view in a file browser or an image thumbnail list.  The value of each option is a screen distance defaulting to zero.
-xscrollsmoothing
-yscrollsmoothing
When these options are set to true and the xview or yview commands are called to scroll by "units", scrolling occurs according to the -xscrollincrement or -yscrollincrement options, and all other scrolling is done as if the -xscrollincrement or -yscrollincrement options were set to 1.  The effect is that when dragging the scrollbar thumb scrolling is very smooth, but when clicking the scrollbar buttons scrolling is done in coarser increments.
Usage ChangedHow it changed
-columnresizemode
The default value is "realtime", it used to be "proxy".
-showlines
The default value is false on Mac OS X and Gtk+, true on Win32 and X11.
-usetheme
The default value is now true.  Complete reversal from previous versions, head for the hills.

TreeCtrl Command

New Comment
gradient Linear gradients!  There are a number of issues when using gradients, see the demos and the relevant sections in the manual page for more info.
theme
The theme platform command returns the API used to draw themed parts of the treectrl.
  • On Mac OS X the result is always aqua.
  • On MS Windows the result is visualstyles if the uxtheme.dll was loaded and visual themes are in use, otherwise X11 is returned to indicate the Tk Xlib calls are drawing the themed parts.
  • On Unix systems the result is gtk if the Gtk+ version of treectrl was built, otherwise X11 is returned.
MS Windows only: The theme setwindowtheme command takes the name of an application whose theme should be used.  If you call...
$T theme setwindowtheme "Explorer"
...on Windows 7 the disclosure triangles of the Explorer file browser will be used rather than +/- buttons.

Gtk+ Theme

  • Pass --enable-gtk=yes to configure to build a Gtk+ version of treectrl.  This requires proper pkg-config setup for the gtk+-2.0 and gdk-pixbuf-xlib-2.0 libraries.
  • Leave the column option -textcolor={} so the theme colors will be used for column header labels.
  • Leave the new widget option -buttontracking=yes for native behavior when clicking buttons.
  • BUG: Currently the theme does not change when the system theme changes.

Rect Element

  • Rounded rectangles can be drawn using the new rect element configuration options -rx and -ry.  These options specify the radius of the corners as screen distances.  The values are restricted to a maximum of half the width or height of the rectangle when being displayed.
  • The -open option is now per-state.  See the "Outlook Express (Newsgroup)" demo where the active outline of the selection rectangle appears to span across columns.  In previous versions that required 3 different styles.
  • The -fill and -outline options can be a Tk color or a gradient.

Library Scripts

  • The treectrl window gets the focus after a <ButtonPress-2> event begins scan-dragging.
  • The Escape key cancels any drag-and-drop in progress with the TreeCtrlFileList bindings.
  • With -selectmode=single the marquee is not used with the TreeCtrlFileList bindings.
  • Added some hackery to the TreeCtrlFileList bindings for emulating the complicated selection behavior of Windows 7 Explorer:
    • Added TreeCtrl::FileListEmulateWin7 to indicate the Windows 7 behavior should be used.
    • Added TreeCtrl::SetSensitiveMarquee, just like TreeCtrl::SetSensitive but indicates which elements respond to the selection rectangle. Typically this is the same as the elements passed toTreeCtrl::SetSensitive with the addition of the selection rectangle elements.

Build Changes

  • Added macosx/ unix/ and win/ subdirectories with platform-specific code in each.
  • The --enable-cocoa configure option was removed when building on Mac OS X.  Instead the configure script determines whether Tk was built using the Cocoa API by examining the TK_LIBS variable.
  • Cross-compiling on a Unix host using the MingW toolchain should work out-of-the-box now.  If the --host configure option contains "mingw32" then TEA_PLATFORM is set to "windows".
  • The 'make clean' target does a better job cleaning what it should.  It doesn't remove the .manifest file generated by configure (make distclean does that), only the linker-generated .manifest when building with MSVC is removed.  Resource file objects are cleaned as well.
  • Various tweaks were made to allow building using the Visual Studio 2008 compiler.
  • Updated to TEA 3.9.

Shellicon Package

  • The shellicon package is used to display native file and folder icons on MS Windows.  It was updated with a new option -useselected.  The value of -useselected may be always, auto or never to control whether the selected version of an icon should be drawn.  The default is auto meaning draw the selected icon if the item is selected.

Demo Changes

  • Added "Explorer (Details, Win7)" and "Explorer (Large Icons, Win7)" demos which very closely match the appearance and behavior of the Windows 7 file explorer.  These demos use gradients, rounded rectangles and the new -canvaspadx, -canvaspady, -itemgapx and -itemgapy options.
  • New demos "Gradients", "Gradients II" and "Gradients II" demonstrate and describe various gradient features.
  • The "Column Spanning" demo uses gradients.
  • The ::tk::mac::iconBitmap is used where available for native filesystem icons on Mac OS X.
  • Fixed a bug with increasing/decreasing the font size if the font size was negative (i.e. on X11).
  • New options were added to the context menu: -bgimageanchor, -bgimageopaque, -bgimagescroll, -bgimagetile, -buttontracking, -xscrollsmoothing and -yscrollsmoothing.

Bug Fixes

  • Fixed non-themed expand/collapse buttons being one pixel too large on Mac OS X.
  • Fixed dotted line and dotted rectangle drawing on Mac OS X.
  • Fixed the column option -arrowpady being broken for -arrowimage, -arrowbitmap and when themed arrows were drawn. It only worked when the X11 fallback was used.
  • Fix "Bug 3104147 - Error after widget was destroyed".  Various [after] callbacks did not check that the treectrl still existed.
  • Fix "Bug 3104148 - column "202" doesn't exist".  Check that the previously-highlighted column exists before configuring its state in MotionInHeader.
  • Fixed <Left> and <Right> arrow keys not moving to adjacent items when some items had -wrap=true.
  • Fixed error with autoscanning when the content area was completely obscurred by locked columns.
  • Fixed the ordering of some entries in the treectrl option table.
  • Fixed the <Escape> key causing an error when the last visible item was selected.

What's New in TkTreeCtrl 2.2.10

TreeCtrl Configuration Options

Ignored Comment
-doublebuffer This option no longer has any effect but was left in to avoid incompatibilities.  Instead, the amount of double-buffering is chosen depending on the platform.  Modern platforms such as Mac OS X double-buffer each toplevel whereas older platforms such as Windows XP do not.

Text Element Options

New Comment
-lmargin1 Specifies how much the first line of text should be indented.
-lmargin2 Specifies how much the 2nd or greater lines should be indented when a line of text wraps.

Mac OS X support for Tk 8.6

Tk 8.6 dropped support for the Carbon API in favor of the modern Cocoa API on Mac OS X. TkTreeCtrl was updated to build using either Carbon (Tk 8.4/8.5) or Cocoa (Tk 8.6). If you are using the back-port of the Cocoa version with Tk 8.5 you can pass the --enable-cocoa=yes configure option when configuring TkTreeCtrl.

Build Changes

  • Updated to TEA version 3.7 which supports the MODULE_SCOPE macro.  As a result, private symbols are not exported by the treectrl shared library on platforms that support it (i.e., gcc's __visibility__("hidden")).

Bug Fixes

  • Fixed a crash during error processing in [item create] due to missing return statements for the -count and -height options.
  • Fixed a bug where all item styles would be lost when deleting the 3rd or greater column. This bug affected any item that never had a column record allocated for the 3rd or greater column (usually because no style had been assigned).
  • Fixed a crash in the [item span] command when specifying "all" for the item description.
  • The pkgIndex.tcl file correctly handles installation directories with space or bracket characters.
  • Removed C++ style comments and a spurious semicolon for C89 AIX compliance. [BUG 2886595]
  • Fixed [item sort -decreasing] not being a "stable" sort. [BUG ID 2909930]
  • Fixed flickering of the dragimage under Windows 7; this requires more doublebuffering than WinXP even with Aero.
  • Use more double-buffering on the dragimage to fix flickering/slowness (tested on Ubuntu VM).
  • Fixed drawing of column/row proxy lines where XOR isn't supported (i.e. MacOSX Cocoa).
  • Fixed the loupe (screen capture) command under Windows 7; tested on Win7 x64 (with and without Aero) and on WinXP x32.
  • Fixed an X server error caused by adding a bad rectangle to an XRegion while processing <Expose> events.  This would show up with -doublebuffer=window while resizing the window. [BUG 3015429]

Demo Changes

  • The "Layout" demo uses the new Text element option -lmargin2.
  • Fixed an undefined-variable error when double-clicking between column headers on X11 in the "Random" demo.
  • Fixed the resizing of items containing child windows when the Tile theme changes in the "Big List" demo.  Also added some comments.
  • Disabled the dynamic-appearing scrollbars under X11 where I saw some infinite looping.

What's New in TkTreeCtrl 2.2.9

TreeCtrl Command

Arguments/Result Changed What changed
see OLD: $T see $item
NEW: $T see $item ?$column? ?-center xy?
You can specify a particular column to scroll into view horizontally.
The -center option will center the item/column in the window instead of performing the minimal amount of scrolling to bring it into view at the edge of the window.

Item Configuration Options

New Comment
-wrap When this option is true an item will be the first in a horizontal (when the treectrl option -orient=horizontal) or a vertical (when the treectrl option -orient=vertical) range of items.  See the new "iMovie (Wrap)" demo.

Bug Fixes

  • Fixed a compile error on SunOS due to DUMP_ALLOC being defined in the system headers.
  • Fixed a bug that caused a panic in B_IncrementFind when calling the [see] command before the widget had displayed itself for the first time.
  • Fixed a library script error when attempting to drag a column header when the window was so small the items weren't visible.
  • Fixed two cases where the whitespace would not be properly erased when items being deleted caused scrolling.
  • Fixed column headers being drawn overtop of the bottom edge of window borders if the window was very short.

Demo Changes

  • Added the "iMovie (Wrap)" demo to demonstrate the new item option -wrap.

What's New in TkTreeCtrl 2.2.8

Bug Fixes

  • Fixed a bug that caused a panic in Range_ItemUnderPoint. Thanks to SF.net user 'nobody' who found the problem.
  • Fixed reading an uninitialized variable when calculating column header layout.

What's New in TkTreeCtrl 2.2.7

TreeCtrl Configuration Options

New Comment
-showrootchildbuttons Similar to -showrootlines, this boolean option controls the display of expand/collapse buttons next to child items of the root item.

Indentation change/fix

Previously with -showroot=0, -showbuttons=0, and -showrootlines=0 there was still an extra level of indentation displayed to the left of the root's children. The only way to remove all indentation from the root's children was to set -showlines=0 as well.  This is no longer the case and now behaves as expected. With the new -showrootchildbuttons option it is now possible to remove all indentation from the root's children without affecting the display of buttons/lines on deeper items.

Library Script Changes

treectrl.tcl:

  • The <Left> and <Right> key bindings will collapse and expand the active item if -orient=vertical and -wrap={}.  Otherwise the previous behavior of setting the active item to an adjacent item is used.

Bug Fixes

  • Fixed corruption/crash with ".t column configure -foo" with no option value if -foo is an invalid option.

What's New in TkTreeCtrl 2.2.6

Bug Fixes

  • Fixed ".t item bbox" returning bogus values when asking for the bounds of a column or element in a list with many items (integer overflow).
  • Fixed a segfault on Win64 machines when the system theme changed.
  • Fixed a panic on Win64 when drawing the the marquee and drag-image dotted rectangles due to a too-small struct.

What's New in TkTreeCtrl 2.2.5

Issues regarding the incompatibility of 8.4 built TkTreeCtrl working in 8.5 were resolved. The Mac OS X API issues noted for 2.2.4 remain (they relate to difficult to reconcile core drawing changes).

A Windows DLL manifest is now embedded to address native theme drawing issues.


What's New in TkTreeCtrl 2.2.4

NOTE regarding Tk version compatibility

Under Mac OSX some internal changes to Tk 8.4.15 and Tk 8.4.17 result in incompatibilities:

  • This version of TkTreeCtrl built for Tk 8.4.15 will work with Tk 8.4.15 and 8.4.16 only (under Mac OSX).
  • This version of TkTreeCtrl built for Tk 8.4.17 will work with Tk 8.4.17 only (under Mac OSX).

TreeCtrl Configuration Options

New Comment
-columntagexpr
-itemtagexpr
These boolean options can be used to turn off tag expressions in column descriptions and item descriptions.  When the value of these options is false the characters (', ')', '&', '|', '^' and '!' have no special significance when using tags in column/item descriptions. This is useful for applications which may have arbitrary tags applied to columns or items.

Bug Fixes

  • Fixed partially-exposed transparent photo images not being redrawn when scrolling under X11.
  • Fixed potential crash with Windows theme if the system theme was changed.
  • Fixed ".t item cget -button" always returning 0 when the value of this option wasn't auto.
  • Fixed a drawing issue under Mac OSX where parts of the window would not be erased properly under Tk 8.4.15+ and Tk 8.5a7+.
  • Fixed crashes under Mac OSX with Tk 8.4.17 and Tk 8.5.0.
  • Fixed an old bug caused by a MSVC compiler optimization bug that stopped items being redrawn when the only change in appearance was the expand/collapse button needing to be redrawn.

Misc Changes

  • Changed the item sort code to be a "stable" sort. This means that the pre-sort order of two equal items is used as a tie-breaker.

Demo Changes

  • Added "Increase Font Size" and "Decrease Font Size" menu commands.  Also the Console font is not changed when running under Tk 8.5.

What's New in TkTreeCtrl 2.2.3

Build Changes

  • When building with configure on Windows the --enable-shellicon option will run configure in the shellicon/ subdirectory.
  • 'make dist' will create the source distribution tktreectrl-VERSION.tar.gz.
  • 'make dist-win' will create the Windows binary distribution tktreectrl-VERSION-win32.zip.

Bug Fixes

  • Fixed flickering when redrawing the borders with "-doublebuffer window" when the widget was resized or parts of it were exposed.
  • Fixed undefined reference to vsnprintf when building with the MS compiler under Windows; it should be _vsnprintf.
  • Fixed a symbol conflict with Python 2.5 on ELF-based systems which also defines a symbol "Ellipsis".

What's New in TkTreeCtrl 2.2.2

Column Configuration Options

New Comment
-itemjustify This option allows item styles to be justified separately from the image/text in the column header. If the value of this option is unspecified (the default), then item styles are justified according to the -justify option of the column.

Item Configuration Options

Usage Changed How it changed
-button The value of this option can now be the word auto (or any abbreviation) in which case a button is drawn only when the item has at least one child item with its item option -visible set to true.

Style Layout Changes

  • The element option -draw of every element type is now deprecated. Use the new style layout option -draw instead.
  • The new per-state style layout option -visible controls the visibility of an element. When the value of this option evaluates to false for a given state, the element consumes no space in the layout and is not displayed. If none of the elements surrounded by an element with -union layout are visible, then the element with -union layout is not displayed.

Item Descriptions

  • The index argument to the child and sibling modifiers can now take the form "end?-integer?".
.t item id "root child end-1" ; # get the second-to-last child of the root item

Bug Fixes

  • Text elements were requesting some height from the style layout when displaying an empty string. If you were depending on this behaviour, it is suggested that you set the height of the text element using the -minheight or -height style layout options.
  • Window elements might not be scrolled along with the rest of the list if the area needing to be redrawn due to scrolling was obscurred by other windows. This could only happen on Win32.
  • The ellipsis "..." in text elements is now always displayed if the text element has less space than is needed to display its string. Previously the ellipsis would disappear when there wasn't room for a single character plus the ellipsis.
  • Fixed a layout bug with multi-line text elements when the unsqueezed element did not require a multi-line layout but the squeezed element did.

What's New in TkTreeCtrl 2.2.1

Bug Fixes

  • Fixed panic with -xscrollincrement=0, -showheader=yes, no visible items and headers wider than the window.
  • Fixed the wrong loop variable being used when calculating onscreen columns for an item which resulted in a random crash.
  • Fixed a crash when invalidating a column of an item if the column wasn't the first in a span.
  • Fixed a leak on X11 where the clipping region was not being freed after drawing dotted rectangles.

What's New in TkTreeCtrl 2.2

TreeCtrl Configuration Options

Deprecated What to use instead
-defaultstyle The -itemstyle option of a column.

TreeCtrl Command

Arguments/Result Changed What changed
contentbox The return value is an empty string if the content area is totally obscurred by column headers, borders, and/or locked columns. Typically this will only happen if the window is too small.
selection get Accepts 2 optional arguments to allow in-place lindex and lrange queries of the selection. For example:
.t selection get 0       ; # the first selected item
.t selection get end     ; # the last selected item
.t selection get 1 end-1 ; # every selected item except the first and last
New Comment
bbox Returns the bounding box of different areas of the window. For example:
.t bbox
will return the bounds of the window, and:
.t bbox header
will return the bounds of the column headers, and:
.t bbox content
will return the same result as the [contentbox] command, and:
.t bbox left
.t bbox right
will return the bounds of the left-locked and right-locked columns.

Column Configuration Options

Renamed
New name
-tag -tags
New Comment
-lock This option allows columns to stick to the left or right edge of the window. Locked columns can scroll vertically but not horizontally. Valid values for this option are none (the default), left or right.
-itemstyle Specifies the name of a style to set in this column for newly-created items. This option replaces the treectrl option -defaultstyle.
-uniform These two options operate the same as the grid geometry manager options of the same name. For example:
.t column configure 0 -uniform a
.t column configure 1 -uniform a
will give columns 0 and 1 the same requested width, whichever is the larger of the two columns. And:
.t column configure 0 -uniform a -weight 2
.t column configure 1 -uniform a
will give column 0 twice the maximum of the requested widths of columns 0 and 1. And:
.t column configure 0 -expand yes -weight 2
.t column configure 1 -expand yes
will give column 0 twice the extra space as column 1.
-weight

Column Command

Arguments/Result Changed What changed
column count Takes an optional column-description argument; the result is the number of columns that match the column description. For example:
.t column count visible
will return the number of columns whose -visible option is true, and:
.t column count {tag a^b}
will return the number of columns with either tag "a" or "b", but not both.
New Comment
column tag add Columns can have a list of tag names. Previously only a single tag was allowed. The tail column no longer has the word "tail" as a tag, but it is still referred to by the word "tail" in column descriptions.
column tag expr
column tag names
column tag remove

Item Configuration Options

New Comment
-tags Tags are textual labels applied to items to group them. Tags do not affect the appearance or behaviour of items. Tags can be used in item descriptions to operate on multiple items. More information can be found in the man page.

Item Command

Arguments/Result Changed What changed
item count Takes an optional item-description argument; the result is the number of items that match the item description. For example:
.t item count visible
will return the number of items that are displayed (i.e., those whose ancestors are all expanded, -visible options are true, etc), and:
.t item count {tag a^b}
will return the number of items with either tag "a" or "b", but not both.
item create New option -tags specifies an initial list of tags for created items.
item id Returns a list of item ids if the item description matches multiple items. For example:
.t item id all
will return a list of ids for all items, and:
.t item id "$item children"
will return the ids of every child of an item.
New Comment
item descendants Returns the ids of the children, grandchildren, etc of an item.
item enabled Gets and sets the enabled state for items. All items are enabled when first created. Disabled items cannot be selected, and are ignored by the default key-navigation and mouse bindings.
item tag add Add tags to items. For example:
.t item tag add all {a b c}
will add tags "a", "b" and "c" to every item.
item tag expr Evaluate a tag expression against items. For example:
.t item tag expr $item a
returns 1 if an item has tag "a". Also:
.t item tag expr $item a||b
returns 1 if  an item has tag "a" or "b".
item tag names Return a list of tag names assigned to items. For example:
.t item tag names $item
returns the tag list for an item, and:
.t item tag names all
returns every tag assigned to any item.
item tag remove Remove tags from items. For example:
.t item tag remove all {b c}
will remove tags "b" and "c" from any items that have them.

Text Element

The new option -underline draws an underline under a single character of the displayed text.

Window Element

Window elements can now be properly clipped so they don't draw over the column header, borders, or outside the bounds of the item columns they occupy. This is accomplished by making the window you want to display a child of a borderless frame widget, and setting the new -clip option of the window element to TRUE. So if your program displays a canvas widget in a window element, you would change this code:
set canvas [canvas .t.canvas ...]
.t item element configure $item $column myElement -window $canvas
to this:
set frame [frame .t.clip -borderwidth 0]
set canvas [canvas $frame.canvas ...]
.t item element configure $item $column myElement -window $frame -clip yes
The -clip option tells the window element to manage the geometry of both the -window widget (i.e, the frame) and its first child widget (i.e., the canvas). In this case, the frame widget is kept sized and positioned so that it is never out-of-bounds. You can see this in the "Big List" and "Firefox Privacy" demos.

Item Descriptions

New keywords were added to allow multiple items to be specified by an item description:
  • The keyword list specifies a list of other item descriptions:
    .t item id "list [list $a $b $c]"
  • The keyword range operates like the item range command:
    .t item id "range $first $last"
New modifiers were added to match multiple items:
  • The modifier ancestors operates like the item ancestors command:
    .t item id "$item ancestors"
  • The modifier children operates like the item children command:
    .t item id "$item children"
  • The modifier descendants operates like the item descendants command:
    .t item id "$item descendants"
New qualifiers were added to refine which items are matched:
  • The qualifier depth matches items at a given depth in the heirarchy:
.t item id "all depth 2" ; # find all items that are children of the root's children
.t item id "depth 2" ; # ditto
  • The qualifier !visible matches items that are not displayed:
    .t item id "first !visible" ; # find the first item that is not displayed
  • The qualifier state matches items that have certain states set (or not set if '!' is used):
    .t item id "first state {selected !open}" ; # find the first item that is selected and collapsed
  • The qualifier tag matches items that meet a tag expression:
    .t item id "$item children tag {a && !b}" ; # find children of $item that have tag "a" but not tag "b"

The keyword all may now be followed by a list of qualifiers. For example:
.t item id "all !visible state myState" ; # find every item that is not displayed with user-defined state "myState"
A list of qualifiers may be used as the first part of an item description. This gives the same result as  "all" followed by the qualifiers. For example:
.t item id "!visible state myState" ; # same as the previous example

Column Descriptions

New keywords list and range can be used to match multiple columns.
New qualifiers state, tag, !tail and !visible can be used to restrict which columns are specified.
The keyword all may be followed by a list of qualifiers.
A list of qualifiers may used as the first part of a column description. This gives the same result as  "all" followed by the qualifiers.

Multi-item and multi-column commands

Many commands can now operate on multiple items and/or columns by using the improved item descriptions and column descriptions mentioned above. For example:
.t column configure "range 1 10" -tags {a b c}
.t column delete "tag a"
.t column id "tag {a || b}"
.t item configure "depth 1" -button yes
.t item count visible
.t item element configure "root children" all elem1 -text "Hello"
.t item id "visible"
.t item image all all image1
.t item style map "tag {a && !b}" "tag c" style2 {style1.elem1 style2.elem2}
.t item style set all all style1
.t item state forcolumn all all state1
.t item state set "tag current" ~mouseover
.t item remove "state selected"
.t item span "range 1 10" "range 10 last" 2
.t item text "root children" all "Hello"

Demo Changes

  • New demo "My Computer". Demonstrates disabled items used as headers.
  • New demo "Column Locking". Demonstrates columns that do not scroll horizontally.
  • The "Big List" and "Firefox Privacy" demos were changed to use the new -clip option of window elements.

Misc Changes

  • The tail column header will not be drawn if the tail column's -visible option is false. This can look nicer with some themes.
  • The -itembackground colors for a column are now extended below any items in the simplest (and most typical) case where the treectrl's -orient option is vertical and -wrap option is unspecified. The height of the rows is determined by the -itemheight or -minitemheight options; if neither of those options is specified, then -itembackground colors are not drawn below the items.
  • If -itembackground colors are specified for the tail column, then they are drawn.
  • Memory usage is improved, especially for text elements.

Bug Fixes

  • item create: Fixed bug where -nextsibling and -prevsibling options could specify an orphan item.
  • item delete: Stopped items possibly being double-deleted by nested calls through <Selection> and <ItemDelete> binding scripts.
  • item expanditem collapseitem toggle: Only operate on items which exist when the command is called, not any that might get created by <Expand> or <Collapse> binding scripts.
  • Fixed a crash and a redisplay problem when a master element was configured with a -textvariable and the associated variable changed.
  • When a style with window elements spanned more than one column, the window might be improperly sized during display updates.
  • Windows in window elements would not always be unmapped if columns or items were hidden, or if the span of an item-column changed.
  • The disclosure triangles (i.e., the item buttons) are drawn without a white background under OSX.

What's New in TkTreeCtrl 2.1.1

Column Command

Arguments/Result Changed What changed
column delete
Added an optional second argument allowing a range of columns to be deleted.

Bug Fixes

  • The item sort command will be much faster in many cases. There was a silly error in the pivot-finding code of quicksort which resulted in the slow-down.
  • A column header will be redisplayed if an image in the header is altered.
  • Fixed bus errors on some Unix systems due to alignment problems.

Other Changes

  • The Tk caret is now positioned over the active item when it changes. The Tk caret is used for the Magnifier accessibility application and IME on Windows, as well as XIM under Unix.
  • Improved the appearance of the column headers under OSX.
  • Added <MouseWheel> support to OSX.
  • Changing the -visible option of an item could be slow if any items were selected. That is because non-visible items may not be part of the selection. A change was made so that changes to the selection caused by modifying the -visible option of an item do not occur until the next display update.

Demo Changes

  • New demo "Column Spanning". Demonstrates a 100-column list where styles span from 1 to 20 columns each.
  • The loupe command (which performs screen capture to an image) is now implemented on Windows and OSX thanks to Jeff Hobbs.
  • The screen-magnifier image now resizes with the "loupe" window.

What's New in TkTreeCtrl 2.1

This version should be backwards compatible with 2.0, except for a few obscure changes.

TreeCtrl Configuration Options

New Comment
-itemwidth
-itemwidthequal Deprecates the column -widthhack option.
-itemwidthmultiple Deprecates the column -stepwidth option.

Column Configuration Options

Deprecated What to use instead
-stepwidth treectrl's -itemwidthmultiple option
-widthhack treectrl's -itemwidthequal option

Element Command

New Comment
element perstate Like [item element perstate].

Item Configuration Options

New Comment
-height Overrides the treectrl's -itemheight option

Item Command

Deprecated What to use instead
item element actual item element perstate
item complex item element configure
Behaviour Changed What changed
item bbox No longer returns an error if no style had been assigned to the column.
item state forcolumn No longer returns an error if no style had been assigned to the column.
item style set Does nothing when replacing a style with the same style. Previously the old style was freed before assigning the new style, losing the element config info if the old and new styles were the same.
Potential incompatibility
Arguments/Result Changed What changed
item create Added options: -count -height, -nextsibling, -open, -parent, -prevsibling, and -returnid. Multiple items may be created with one call using the -count option.
item element configure Multiple elements in multiple columns may be configured with a single call. Use '+' to separate elements, and ',' to separate columns. See the docs.
item style set When no column is specified, returns a list of one style name per column. Previously, the list would have less values than the number of columns if no styles had ever been assigned to the rightmost column(s).
Potential incompatibility
item text When no column is specified, returns a list of one string per column.
New Comment
item image Partner to the [item text] command.
item element perstate Not really new, just renamed from [item element actual] to better describe what it does. Accepts a new optional argument which specifies the state to use when determining the value of the per-state option.

The following options no longer return a default value if the per-state option itself does not have a value specified:
  • bitmap -foreground, -background
  • border -relief
  • text -fill, -font
Potential incompatibility
item span A style may now be displayed over multiple adjacent columns.

Notify Command

New Comment
notify unbind
Let's you unbind all scripts from an object with one call.

Style Layout Changes

  • Column justification will now affect the position of elements in 2 situations which previously had no effect (Potential incompatibility):
  1. If a -detach element had a fixed width larger than the other elements.
  2. If an element had -iexpand x specified as well as -maxwidth, leaving some space available.

Element Changes

  • Bitmap, image and text elements are drawn clipped if given less space than they need.
  • Fixed line wrapping of text elements. It did not work for single lines of text at all (Potential incompatibility).
  • The text -wrap option can now be none to disable line wrapping.

Event Changes

  • The new static event <ItemVisibility> is generated when items become visible on screen and when items are no longer visible on screen. This event allows you to create really big lists by only assigning styles when items are about to be displayed. See the EVENTS AND SCRIPT SUBSTITUTIONS section in the help file, and the new demo "Big List".

Other Changes

  • On WinXP, the column header sort arrow is drawn like Explorer draws it if -usetheme is true.

Demo Changes

  • New demo "Big List". Demonstrates the new <ItemVisibility> event, using <Expand-before> to add items on demand, and column spanning.
  • The context menu has a Span submenu that lets you manipulate column spanning in items. See the item span command in the help file.
  • Under WinXP, the "Explorer" demos will use the new shellicon extension if available. This extension allows a treectrl to display file/folder icons using the Win32 Shell API. It may work on other versions of Windows but it hasn't been tested.

What's New in TkTreeCtrl 2.0

TreeCtrl Configuration Options

Replaced What to use instead
-openbuttonimage -buttonimage
-closedbuttonimage -buttonimage
-openbuttonbitmap -buttonbitmap
-closedbuttonbitmap -buttonbitmap
Usage Changed How it changed
-backgroundmode The values "index" and "visindex" are deprecated. The value "order" should be used instead of "index", and "ordervisible" should be used instead of "visindex". This brings agreement with the new "item order" command which replaces the "item index" command.
-treecolumn This used to be any integer value which may or may not have corresponded to an actual column. Now the value must be a valid column description, or an empty string to indicate no column should display buttons/lines.
New
-backgroundimage
-columnprefix
-columnresizemode
-itemprefix
-minitemheight
-usetheme

TreeCtrl Commands

Deprecated What to use instead
compare item compare
index item id
numcolumns column count
numitems item count
range item range

Column Configuration Options

Removed What to use instead
-relief
-state
-sunken -state
Renamed
New name
-arrowpad -arrowpadx
Usage Changed How it changed
-background This is now a per-state option. See COLUMNS in the help file for valid state names.
New

-arrowbitmap

-arrowimage
-arrowpady
-maxwidth
-resize
-state
-textlines

Column Command

Deprecated What to use instead
column index column id
Arguments/Result Changed What changed
column configure
A column description of "all" is allowed if at least one option-value pair is given.
column create The result is a unique identifier. Previously the result was an index in the list of columns.
column delete A column description of "all" is allowed.
New Comment
column compare
column count replaces "numcolumns"
column dragconfigure
column dragcget
column id replaces "column index"
column list
column order

Item Command

Removed What to use instead
item index item order
New Comment
item compare replaces "compare"
item count replaces "numitems"
item id replaces "index"
item order replaces "item index"
item range replaces "range"

Notify Command

Arguments/Result Changed What changed
notify generate
Added optional percentsCommand argument
notify install Old syntax (supported but deprecated):
notify install event eventName
notify install detail eventName detail
New syntax:
notify install <eventName>
notify install <eventName-detail>
notify linkage Old syntax (supported but deprecated):
notify linkage eventName
notify linkage eventName detail
New syntax:
notify linkage <eventName>
notify linkage <eventName-detail>
notify uninstall see notify install above

Style Layout Options

Usage Changed How it changed
-iexpand Two new flags "x' and "y" are allowed. Previously, only the -ipadx and -ipady padding could be expanded by this option. The new xy flags expand the display area of the element, not the padding. To update your code, you will probably want to change this:
$T style layout $S $E -iexpand we
to this:
$T style layout $S $E -iexpand x
Keep in mind that -union elements are not affected by -iexpand xy, since the size of a -union element is determined by the elements it surrounds.
New

-height
-maxheight
-maxwidth
-minheight
-minwidth
-sticky
-width

Element Changes

  • A new element type window was added. See the new demo "Firefox Privacy" and the ELEMENTS section in the help file.
  • All element types have a new per-state boolean option called -draw.
  • The text element type has a new option called -textvariable. See the new demo "Textvariable" and the ELEMENTS section in the help file.

Event Changes

  • 2 new %-substitution characters %P and %? are allowed in binding scripts. See the EVENTS AND SCRIPT SUBSTITUTIONS section in the help file.
  • The new static event <ItemDelete> is generated when items are deleted. See the EVENTS AND SCRIPT SUBSTITUTIONS section in the help file.

Library Script Changes

filelist-bindings.tcl:

  • The Priv(edit) variable, which is used to specify which text elements may be edited, now has the same format as Priv(sensitive). Previously only elements in the first column could be edited.
  • 3 new commands in the TreeCtrl namespace should be used to access the Priv(dragimage), Priv(edit) and Priv(sensitive) variables. The commands are SetDragImage, SetEditable and SetSensitive.
  • Two new dynamic events <Edit-begin> and <Edit-end> are generated when editing a file name.

treectrl.tcl:

  • On OSX/Aqua, the Command key is used to perform discontinuous selection. Previously the Control key was used but Command is specified by Apple's user-interface guidelines.

Other Changes

  • On WinXP, the column headers and open/close buttons are drawn using the system theme if -usetheme is true. The sort arrow is drawn the old-fashioned way.
  • On OSX/Aqua,  the column headers and open/close buttons are drawn using the system theme if -usetheme is true. The sort arrow will be drawn by the Appearance Manager as well. This will override the -arrowside and -arrowgravity options.
  • Columns can be moved by drag-and-drop. See column dragconfigure in the help file.
  • Columns can be specified in new ways. See the COLUMN DESCRIPTION section in the help file.
  • Added new section DYNAMIC EVENTS to the help file.
  • Added new section PER-STATE OPTIONS to the help file.
  • The new style layout option -indent allows elements to be displayed in the button/line area. See the style layout command in the help file and the new demo "Firefox Privacy".
  • The new item description end is equivalent to last.
  • If you have version 1.1 installed, replace the old pkgIndex.tcl file with the one from this version (but replace the version number 2.0 with 1.1). Otherwise the old pkgIndex.tcl file will set the TREECTRL_LIBRARY variable which will override where the library scripts are found.

Demo Changes

  • New demo "Firefox Privacy". Demonstrates the new window element type and -indent style layout option.
  • New demo "Textvariable". Demonstrates the new -textvariable option of the text element.
  • Added a new Event Browser window to display events generated by the main treectrl widget.
  • The context menu can be popped up in all the demo lists. A <Control-ButtonPress-1> binding for this was added under OSX/Aqua.
  • In the "Explorer" demos, the file name is hidden while editing the file name.
tktreectrl-2.4.1/generic/0000755000076400010400000000000011646706171015640 5ustar TimAdministratorstktreectrl-2.4.1/generic/qebind.c0000644000076400010400000017016611562306321017247 0ustar TimAdministrators/* * qebind.c -- * * This module implements quasi-events. * * Copyright (c) 2002-2011 Tim Baker */ /* * A general purpose module that allows a program to send event-like * messages to scripts, and to bind Tcl commands to those quasi-events. * Each event has it's own detail field and other fields, and this * module performs %-substitution on bound scripts just like regular * Tk binding model. * * To use it first call QE_BindInit() to initialize the package. * Then call QE_InstallEvent() for each new event you wish to define. * For events with details, call QE_InstallDetail() to register each * detail associated with a specific event type. Then create a * binding table, which records all binding commands defined by your * scripts, with QE_CreateBindingTable(). QE_BindCmd() is * called to associate a Tcl script with a given event for a particular * object. The objects that commands are bound to can be a Tk widget or any * string, just like the usual "bind" command. Bindings on Tk widgets are * automatically deleted when the widget is destroyed. */ #include #include #ifdef HAVE_INTPTR_T #include #endif #include #include #include "qebind.h" #define dbwin TreeCtrl_dbwin MODULE_SCOPE void dbwin(char *fmt, ...); /* * The macro below is used to modify a "char" value (e.g. by casting * it to an unsigned character) so that it can be used safely with * macros such as isspace. */ #define UCHAR(c) ((unsigned char) (c)) /* * Macros used to cast between pointers and integers (e.g. when storing an int * in ClientData), on 64-bit architectures they avoid gcc warning about "cast * to/from pointer from/to integer of different size". */ #if !defined(INT2PTR) && !defined(PTR2INT) # if defined(HAVE_INTPTR_T) || defined(intptr_t) # define INT2PTR(p) ((void *)(intptr_t)(p)) # define PTR2INT(p) ((int)(intptr_t)(p)) # else # define INT2PTR(p) ((void *)(p)) # define PTR2INT(p) ((int)(p)) # endif #endif int debug_bindings = 0; /* * Allow bindings to be deactivated. */ #define BIND_ACTIVE 1 /* * Allow new events to be added/removed by Tcl commands. */ #define ALLOW_INSTALL 1 /* * Delete scripts bound to a window when that window is destroyed. */ #define DELETE_WIN_BINDINGS 1 typedef struct BindValue { int type; /* Type of event, etc) */ int detail; /* Misc. other information, or 0 for none */ ClientData object; char *command; int specific; /* For less-specific events (detail=0), this is 1 * if a more-specific event (detail>0) exists. */ struct BindValue *nextValue; /* list of BindValues matching event */ #if BIND_ACTIVE int active; /* 1 if binding is "active", 0 otherwise */ #endif /* BIND_ACTIVE */ } BindValue; typedef struct Pattern { int type; /* Type of event */ int detail; /* Misc. other information, or 0 for none */ } Pattern; typedef struct PatternTableKey { int type; /* Type of event */ int detail; /* Misc. other information, or 0 for none */ } PatternTableKey; typedef struct ObjectTableKey { int type; /* Type of event */ int detail; /* Misc. other information, or 0 for none */ ClientData object; /* Object info */ } ObjectTableKey; typedef struct Detail { Tk_Uid name; /* Name of detail */ int code; /* Detail code */ struct EventInfo *event; /* Associated event */ QE_ExpandProc expandProc; /* Callback to expand % in scripts */ #if ALLOW_INSTALL int dynamic; /* Created by QE_InstallCmd() */ char *command; /* Tcl command to expand percents, or NULL */ #endif struct Detail *next; /* List of Details for event */ } Detail; typedef struct EventInfo { char *name; /* Name of event */ int type; /* Type of event */ QE_ExpandProc expandProc; /* Callback to expand % in scripts */ Detail *detailList; /* List of Details */ int nextDetailId; /* Next unique Detail.code */ #if ALLOW_INSTALL int dynamic; /* Created by QE_InstallCmd() */ char *command; /* Tcl command to expand percents, or NULL */ #endif struct EventInfo *next; /* List of all EventInfos */ } EventInfo; typedef struct GenerateField { char which; /* The %-char */ char *string; /* Replace %-char with it */ } GenerateField; typedef struct GenerateData { GenerateField staticField[20]; GenerateField *field; int count; char *command; /* Tcl command to expand percents, or NULL */ } GenerateData; typedef struct BindingTable { Tcl_Interp *interp; Tcl_HashTable patternTable; /* Key: PatternTableKey, Value: (BindValue *) */ Tcl_HashTable objectTable; /* Key: ObjectTableKey, Value: (BindValue *) */ Tcl_HashTable eventTableByName; /* Key: string, Value: EventInfo */ Tcl_HashTable eventTableByType; /* Key: int, Value: EventInfo */ Tcl_HashTable detailTableByType; /* Key: PatternTableKey, Value: Detail */ #if DELETE_WIN_BINDINGS Tcl_HashTable winTable; /* Key: Tk_Uid of window name, Value: WinTableValue */ #endif EventInfo *eventList; /* List of all EventInfos */ int nextEventId; /* Next unique EventInfo.type */ } BindingTable; static void ExpandPercents(BindingTable *bindPtr, ClientData object, char *command, QE_Event *eventPtr, QE_ExpandProc expandProc, Tcl_DString *result); static int ParseEventDescription(BindingTable *bindPtr, char *eventPattern, Pattern *patPtr, EventInfo **eventInfoPtr, Detail **detailPtr); static int FindSequence(BindingTable *bindPtr, ClientData object, char *eventString, int create, int *created, BindValue **result); static void Percents_CharMap(QE_ExpandArgs *args); static void Percents_Command(QE_ExpandArgs *args); #if ALLOW_INSTALL typedef struct PercentsData { GenerateData *gdPtr; char *command; EventInfo *eventPtr; Detail *detailPtr; } PercentsData; #endif static int DeleteBinding(BindingTable *bindPtr, BindValue *valuePtr); static EventInfo *FindEvent(BindingTable *bindPtr, int eventType); int QE_BindInit(Tcl_Interp *interp) { return TCL_OK; } static int CheckName(char *name) { char *p = name; if (*p == '\0') return TCL_ERROR; while ((*p != '\0') && (*p != '-') && !isspace(UCHAR(*p))) p++; if (*p == '\0') return TCL_OK; return TCL_ERROR; } int QE_InstallEvent(QE_BindingTable bindingTable, char *name, QE_ExpandProc expandProc) { BindingTable *bindPtr = (BindingTable *) bindingTable; Tcl_HashEntry *hPtr; EventInfo *eiPtr; int isNew; int type; if (CheckName(name) != TCL_OK) { Tcl_AppendResult(bindPtr->interp, "bad event name \"", name, "\"", (char *) NULL); return 0; } hPtr = Tcl_CreateHashEntry(&bindPtr->eventTableByName, name, &isNew); if (!isNew) { Tcl_AppendResult(bindPtr->interp, "event \"", name, "\" already exists", NULL); return 0; } type = bindPtr->nextEventId++; eiPtr = (EventInfo *) Tcl_Alloc(sizeof(EventInfo)); eiPtr->name = Tcl_Alloc((int) strlen(name) + 1); strcpy(eiPtr->name, name); eiPtr->type = type; eiPtr->expandProc = expandProc; eiPtr->detailList = NULL; eiPtr->nextDetailId = 1; #ifdef ALLOW_INSTALL eiPtr->dynamic = 0; eiPtr->command = NULL; #endif Tcl_SetHashValue(hPtr, (ClientData) eiPtr); hPtr = Tcl_CreateHashEntry(&bindPtr->eventTableByType, (char *) INT2PTR(type), &isNew); Tcl_SetHashValue(hPtr, (ClientData) eiPtr); /* List of EventInfos */ eiPtr->next = bindPtr->eventList; bindPtr->eventList = eiPtr; return type; } int QE_InstallDetail(QE_BindingTable bindingTable, char *name, int eventType, QE_ExpandProc expandProc) { BindingTable *bindPtr = (BindingTable *) bindingTable; Tcl_HashEntry *hPtr; Detail *dPtr; EventInfo *eiPtr; PatternTableKey key; int isNew; int code; if (CheckName(name) != TCL_OK) { Tcl_AppendResult(bindPtr->interp, "bad detail name \"", name, "\"", (char *) NULL); return 0; } /* Find the event this detail goes with */ eiPtr = FindEvent(bindPtr, eventType); if (eiPtr == NULL) return 0; /* Verify the detail is not already defined for this event */ for (dPtr = eiPtr->detailList; dPtr != NULL; dPtr = dPtr->next) { if (strcmp(dPtr->name, name) == 0) { Tcl_AppendResult(bindPtr->interp, "detail \"", name, "\" already exists for event \"", eiPtr->name, "\"", NULL); return 0; } } code = eiPtr->nextDetailId++; /* New Detail for detailTable */ dPtr = (Detail *) Tcl_Alloc(sizeof(Detail)); dPtr->name = Tk_GetUid(name); dPtr->code = code; dPtr->event = eiPtr; dPtr->expandProc = expandProc; #if ALLOW_INSTALL dPtr->dynamic = 0; dPtr->command = NULL; #endif /* Entry to find detail by event type and detail code */ key.type = eventType; key.detail = code; hPtr = Tcl_CreateHashEntry(&bindPtr->detailTableByType, (char *) &key, &isNew); Tcl_SetHashValue(hPtr, (ClientData) dPtr); /* List of Details */ dPtr->next = eiPtr->detailList; eiPtr->detailList = dPtr; return code; } static void DeleteEvent(BindingTable *bindPtr, EventInfo *eiPtr) { EventInfo *eiPrev; Detail *dPtr, *dNext; /* Free Details */ for (dPtr = eiPtr->detailList; dPtr != NULL; dPtr = dNext) { dNext = dPtr->next; #ifdef ALLOW_INSTALL if (dPtr->command != NULL) Tcl_Free(dPtr->command); #endif memset((char *) dPtr, 0xAA, sizeof(Detail)); Tcl_Free((char *) dPtr); } if (bindPtr->eventList == eiPtr) bindPtr->eventList = eiPtr->next; else { for (eiPrev = bindPtr->eventList; eiPrev->next != eiPtr; eiPrev = eiPrev->next) { } eiPrev->next = eiPtr->next; } /* Free EventInfo */ Tcl_Free(eiPtr->name); #ifdef ALLOW_INSTALL if (eiPtr->command != NULL) Tcl_Free(eiPtr->command); #endif memset((char *) eiPtr, 0xAA, sizeof(EventInfo)); Tcl_Free((char *) eiPtr); } int QE_UninstallEvent(QE_BindingTable bindingTable, int eventType) { BindingTable *bindPtr = (BindingTable *) bindingTable; Tcl_HashEntry *hPtr; Tcl_HashSearch search; EventInfo *eiPtr; BindValue *valuePtr, **valueList; Tcl_DString dString; int i, count = 0; /* Find the event */ hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByType, (char *) INT2PTR(eventType)); if (hPtr == NULL) return TCL_ERROR; eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); Tcl_DeleteHashEntry(hPtr); hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, eiPtr->name); Tcl_DeleteHashEntry(hPtr); Tcl_DStringInit(&dString); /* Find all bindings to this event for any object */ hPtr = Tcl_FirstHashEntry(&bindPtr->patternTable, &search); while (hPtr != NULL) { valuePtr = (BindValue *) Tcl_GetHashValue(hPtr); while (valuePtr != NULL) { if (valuePtr->type == eiPtr->type) { Tcl_DStringAppend(&dString, (char *) &valuePtr, sizeof(valuePtr)); count++; } valuePtr = valuePtr->nextValue; } hPtr = Tcl_NextHashEntry(&search); } valueList = (BindValue **) Tcl_DStringValue(&dString); for (i = 0; i < count; i++) DeleteBinding(bindPtr, valueList[i]); Tcl_DStringFree(&dString); DeleteEvent(bindPtr, eiPtr); return TCL_OK; } int QE_UninstallDetail(QE_BindingTable bindingTable, int eventType, int detail) { BindingTable *bindPtr = (BindingTable *) bindingTable; PatternTableKey key; Tcl_HashEntry *hPtr; Detail *dPtr = NULL, *dPrev; EventInfo *eiPtr; /* Find the event */ eiPtr = FindEvent(bindPtr, eventType); if (eiPtr == NULL) return TCL_ERROR; if (eiPtr->detailList == NULL) return TCL_ERROR; /* Delete all bindings on this event/detail for all objects */ while (1) { key.type = eventType; key.detail = detail; hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, (char *) &key); if (hPtr == NULL) break; DeleteBinding(bindPtr, (BindValue *) Tcl_GetHashValue(hPtr)); } if (eiPtr->detailList->code == detail) { dPtr = eiPtr->detailList; eiPtr->detailList = eiPtr->detailList->next; } else { for (dPrev = eiPtr->detailList; dPrev != NULL; dPrev = dPrev->next) { if ((dPrev->next != NULL) && (dPrev->next->code == detail)) { dPtr = dPrev->next; dPrev->next = dPtr->next; break; } } if (dPtr == NULL) return TCL_ERROR; } #ifdef ALLOW_INSTALL if (dPtr->command != NULL) Tcl_Free(dPtr->command); #endif memset((char *) dPtr, 0xAA, sizeof(Detail)); Tcl_Free((char *) dPtr); key.type = eventType; key.detail = detail; hPtr = Tcl_FindHashEntry(&bindPtr->detailTableByType, (char *) &key); Tcl_DeleteHashEntry(hPtr); return TCL_OK; } static EventInfo *FindEvent(BindingTable *bindPtr, int eventType) { Tcl_HashEntry *hPtr; hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByType, (char *) INT2PTR(eventType)); if (hPtr == NULL) return NULL; return (EventInfo *) Tcl_GetHashValue(hPtr); } static Detail *FindDetail(BindingTable *bindPtr, int eventType, int code) { PatternTableKey key; Tcl_HashEntry *hPtr; key.type = eventType; key.detail = code; hPtr = Tcl_FindHashEntry(&bindPtr->detailTableByType, (char *) &key); if (hPtr == NULL) return NULL; return (Detail *) Tcl_GetHashValue(hPtr); } #if DELETE_WIN_BINDINGS typedef struct WinTableValue { BindingTable *bindPtr; ClientData object; Tk_Window tkwin; int count; /* Number of BindValues on object */ } WinTableValue; static void TkWinEventProc(ClientData clientData, XEvent *eventPtr) { WinTableValue *cd = (WinTableValue *) clientData; BindingTable *bindPtr = cd->bindPtr; ClientData object = cd->object; if (eventPtr->type != DestroyNotify) return; QE_DeleteBinding((QE_BindingTable) bindPtr, object, NULL); } #endif QE_BindingTable QE_CreateBindingTable(Tcl_Interp *interp) { BindingTable *bindPtr; bindPtr = (BindingTable *) Tcl_Alloc(sizeof(BindingTable)); bindPtr->interp = interp; Tcl_InitHashTable(&bindPtr->patternTable, sizeof(PatternTableKey) / sizeof(int)); Tcl_InitHashTable(&bindPtr->objectTable, sizeof(ObjectTableKey) / sizeof(int)); Tcl_InitHashTable(&bindPtr->eventTableByName, TCL_STRING_KEYS); Tcl_InitHashTable(&bindPtr->eventTableByType, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&bindPtr->detailTableByType, sizeof(PatternTableKey) / sizeof(int)); #if DELETE_WIN_BINDINGS Tcl_InitHashTable(&bindPtr->winTable, TCL_ONE_WORD_KEYS); #endif bindPtr->nextEventId = 1; bindPtr->eventList = NULL; return (QE_BindingTable) bindPtr; } void QE_DeleteBindingTable(QE_BindingTable bindingTable) { BindingTable *bindPtr = (BindingTable *) bindingTable; Tcl_HashEntry *hPtr; Tcl_HashSearch search; EventInfo *eiPtr, *eiNext; Detail *dPtr, *dNext; hPtr = Tcl_FirstHashEntry(&bindPtr->patternTable, &search); while (hPtr != NULL) { BindValue *valuePtr = (BindValue *) Tcl_GetHashValue(hPtr); while (valuePtr != NULL) { BindValue *nextValue = valuePtr->nextValue; Tcl_Free((char *) valuePtr->command); memset((char *) valuePtr, 0xAA, sizeof(BindValue)); Tcl_Free((char *) valuePtr); valuePtr = nextValue; } hPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&bindPtr->patternTable); Tcl_DeleteHashTable(&bindPtr->objectTable); for (eiPtr = bindPtr->eventList; eiPtr != NULL; eiPtr = eiNext) { eiNext = eiPtr->next; /* Free Detail */ for (dPtr = eiPtr->detailList; dPtr != NULL; dPtr = dNext) { dNext = dPtr->next; #ifdef ALLOW_INSTALL if (dPtr->command != NULL) Tcl_Free(dPtr->command); #endif memset((char *) dPtr, 0xAA, sizeof(Detail)); Tcl_Free((char *) dPtr); } /* Free EventInfo */ Tcl_Free(eiPtr->name); #ifdef ALLOW_INSTALL if (eiPtr->command != NULL) Tcl_Free(eiPtr->command); #endif memset((char *) eiPtr, 0xAA, sizeof(EventInfo)); Tcl_Free((char *) eiPtr); } Tcl_DeleteHashTable(&bindPtr->eventTableByName); Tcl_DeleteHashTable(&bindPtr->eventTableByType); Tcl_DeleteHashTable(&bindPtr->detailTableByType); #if DELETE_WIN_BINDINGS hPtr = Tcl_FirstHashEntry(&bindPtr->winTable, &search); while (hPtr != NULL) { WinTableValue *cd = (WinTableValue *) Tcl_GetHashValue(hPtr); Tk_DeleteEventHandler(cd->tkwin, StructureNotifyMask, TkWinEventProc, (ClientData) cd); Tcl_Free((char *) cd); hPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&bindPtr->winTable); #endif memset((char *) bindPtr, 0xAA, sizeof(BindingTable)); Tcl_Free((char *) bindPtr); } int QE_CreateBinding(QE_BindingTable bindingTable, ClientData object, char *eventString, char *command, int append) { BindingTable *bindPtr = (BindingTable *) bindingTable; BindValue *valuePtr; int isNew, length; char *cmdOld, *cmdNew; if (FindSequence(bindPtr, object, eventString, 1, &isNew, &valuePtr) != TCL_OK) return TCL_ERROR; /* created a new objectTable entry */ if (isNew) { Tcl_HashEntry *hPtr; PatternTableKey key; #if DELETE_WIN_BINDINGS char *winName = (char *) object; if (winName[0] == '.') { Tk_Window tkwin = Tk_MainWindow(bindPtr->interp); Tk_Window tkwin2; tkwin2 = Tk_NameToWindow(bindPtr->interp, winName, tkwin); if (tkwin2 != NULL) { WinTableValue *cd; hPtr = Tcl_CreateHashEntry(&bindPtr->winTable, object, &isNew); if (isNew) { cd = (WinTableValue *) Tcl_Alloc(sizeof(WinTableValue)); cd->bindPtr = bindPtr; cd->object = object; cd->tkwin = tkwin2; cd->count = 0; Tk_CreateEventHandler(tkwin2, StructureNotifyMask, TkWinEventProc, (ClientData) cd); Tcl_SetHashValue(hPtr, (ClientData) cd); } else { cd = (WinTableValue *) Tcl_GetHashValue(hPtr); } /* Number of BindValues for this window */ cd->count++; } } #endif key.type = valuePtr->type; key.detail = valuePtr->detail; hPtr = Tcl_CreateHashEntry(&bindPtr->patternTable, (char *) &key, &isNew); /* * A patternTable entry exists for each different type/detail. * The entry points to a BindValue which is the head of the list * of BindValue's with this same type/detail, but for different * objects. */ if (!isNew) { valuePtr->nextValue = (BindValue *) Tcl_GetHashValue(hPtr); } Tcl_SetHashValue(hPtr, (ClientData) valuePtr); } cmdOld = valuePtr->command; /* Append given command to any existing command */ if (append && cmdOld) { length = (int) (strlen(cmdOld) + strlen(command) + 2); cmdNew = Tcl_Alloc((unsigned) length); (void) sprintf(cmdNew, "%s\n%s", cmdOld, command); } /* Copy the given command */ else { cmdNew = (char *) Tcl_Alloc((unsigned) strlen(command) + 1); (void) strcpy(cmdNew, command); } /* Free the old command, if any */ if (cmdOld) Tcl_Free(cmdOld); /* Save command associated with this binding */ valuePtr->command = cmdNew; return TCL_OK; } int QE_DeleteBinding(QE_BindingTable bindingTable, ClientData object, char *eventString) { BindingTable *bindPtr = (BindingTable *) bindingTable; BindValue *valuePtr, **valueList; /* Delete all bindings on this object */ if (eventString == NULL) { Tcl_HashEntry *hPtr; Tcl_HashSearch search; Tcl_DString dString; int i, count = 0; Tcl_DStringInit(&dString); hPtr = Tcl_FirstHashEntry(&bindPtr->patternTable, &search); while (hPtr != NULL) { valuePtr = (BindValue *) Tcl_GetHashValue(hPtr); while (valuePtr != NULL) { if (valuePtr->object == object) { Tcl_DStringAppend(&dString, (char *) &valuePtr, sizeof(valuePtr)); count++; break; } valuePtr = valuePtr->nextValue; } hPtr = Tcl_NextHashEntry(&search); } valueList = (BindValue **) Tcl_DStringValue(&dString); for (i = 0; i < count; i++) DeleteBinding(bindPtr, valueList[i]); Tcl_DStringFree(&dString); return TCL_OK; } if (FindSequence(bindPtr, object, eventString, 0, NULL, &valuePtr) != TCL_OK) return TCL_ERROR; if (valuePtr == NULL) { Tcl_ResetResult(bindPtr->interp); return TCL_OK; } DeleteBinding(bindPtr, valuePtr); return TCL_OK; } static int DeleteBinding(BindingTable *bindPtr, BindValue *valuePtr) { Tcl_HashEntry *hPtr; BindValue *listPtr; ObjectTableKey keyObj; PatternTableKey keyPat; /* Delete the objectTable entry */ keyObj.type = valuePtr->type; keyObj.detail = valuePtr->detail; keyObj.object = valuePtr->object; hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) &keyObj); if (hPtr == NULL) return TCL_ERROR; /* fatal error */ Tcl_DeleteHashEntry(hPtr); /* Find the patternTable entry for this type/detail */ keyPat.type = valuePtr->type; keyPat.detail = valuePtr->detail; hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, (char *) &keyPat); if (hPtr == NULL) return TCL_ERROR; /* fatal error */ /* * Get the patternTable value. This is the head of a list of * BindValue's that match the type/detail, but for different * objects; */ listPtr = (BindValue *) Tcl_GetHashValue(hPtr); /* The deleted BindValue is the first */ if (listPtr == valuePtr) { /* The deleted BindValue was the only one in the list */ if (valuePtr->nextValue == NULL) { if (debug_bindings) dbwin("QE_DeleteBinding: Deleted pattern type=%d detail=%d\n", valuePtr->type, valuePtr->detail); Tcl_DeleteHashEntry(hPtr); } /* The next BindValue is the new head of the list */ else { Tcl_SetHashValue(hPtr, valuePtr->nextValue); } } /* Look for the deleted BindValue in the list, and remove it */ else { while (1) { if (listPtr->nextValue == NULL) return TCL_ERROR; /* fatal */ if (listPtr->nextValue == valuePtr) { if (debug_bindings) dbwin("QE_DeleteBinding: Unlinked binding type=%d detail=%d\n", valuePtr->type, valuePtr->detail); listPtr->nextValue = valuePtr->nextValue; break; } listPtr = listPtr->nextValue; } } #if DELETE_WIN_BINDINGS { char *winName = (char *) valuePtr->object; if (winName[0] == '.') { WinTableValue *cd; hPtr = Tcl_FindHashEntry(&bindPtr->winTable, winName); if (hPtr == NULL) return TCL_ERROR; /* fatal error */ cd = (WinTableValue *) Tcl_GetHashValue(hPtr); cd->count--; if (cd->count == 0) { Tk_DeleteEventHandler(cd->tkwin, StructureNotifyMask, TkWinEventProc, (ClientData) cd); Tcl_Free((char *) cd); Tcl_DeleteHashEntry(hPtr); } } } #endif Tcl_Free((char *) valuePtr->command); memset((char *) valuePtr, 0xAA, sizeof(BindValue)); Tcl_Free((char *) valuePtr); return TCL_OK; } int QE_GetAllObjects(QE_BindingTable bindingTable) { BindingTable *bindPtr = (BindingTable *) bindingTable; Tcl_HashEntry *hPtr; Tcl_HashSearch search; Tcl_DString dString; ClientData *objectList; int i, count = 0; Tcl_Obj *listObj; Tcl_DStringInit(&dString); hPtr = Tcl_FirstHashEntry(&bindPtr->patternTable, &search); while (hPtr != NULL) { BindValue *valuePtr = (BindValue *) Tcl_GetHashValue(hPtr); while (valuePtr != NULL) { objectList = (ClientData *) Tcl_DStringValue(&dString); for (i = 0; i < count; i++) { if (objectList[i] == valuePtr->object) break; } if (i >= count) { Tcl_DStringAppend(&dString, (char *) &valuePtr->object, sizeof(ClientData)); count++; } valuePtr = valuePtr->nextValue; } hPtr = Tcl_NextHashEntry(&search); } if (count > 0) { listObj = Tcl_NewListObj(0, NULL); objectList = (ClientData *) Tcl_DStringValue(&dString); for (i = 0; i < count; i++) { Tcl_ListObjAppendElement(bindPtr->interp, listObj, Tcl_NewStringObj((char *) objectList[i], -1)); } Tcl_SetObjResult(bindPtr->interp, listObj); } Tcl_DStringFree(&dString); return TCL_OK; } int QE_GetBinding(QE_BindingTable bindingTable, ClientData object, char *eventString) { BindingTable *bindPtr = (BindingTable *) bindingTable; BindValue *valuePtr; if (FindSequence(bindPtr, object, eventString, 0, NULL, &valuePtr) != TCL_OK) return TCL_ERROR; if (valuePtr == NULL) return TCL_OK; Tcl_SetObjResult(bindPtr->interp, Tcl_NewStringObj(valuePtr->command, -1)); return TCL_OK; } static void GetPatternString(BindingTable *bindPtr, BindValue *bindValue, Tcl_DString *dString) { EventInfo *eiPtr; eiPtr = FindEvent(bindPtr, bindValue->type); if (eiPtr != NULL) { Tcl_DStringAppend(dString, "<", 1); Tcl_DStringAppend(dString, eiPtr->name, -1); if (bindValue->detail) { Detail *detail = FindDetail(bindPtr, bindValue->type, bindValue->detail); if (detail != NULL) { Tcl_DStringAppend(dString, "-", 1); Tcl_DStringAppend(dString, detail->name, -1); } } Tcl_DStringAppend(dString, ">", 1); } } int QE_GetAllBindings(QE_BindingTable bindingTable, ClientData object) { BindingTable *bindPtr = (BindingTable *) bindingTable; Tcl_HashEntry *hPtr; Tcl_HashSearch search; Tcl_DString dString; Tcl_DStringInit(&dString); hPtr = Tcl_FirstHashEntry(&bindPtr->patternTable, &search); while (hPtr != NULL) { BindValue *valuePtr = (BindValue *) Tcl_GetHashValue(hPtr); while (valuePtr != NULL) { if (valuePtr->object == object) { Tcl_DStringSetLength(&dString, 0); GetPatternString(bindPtr, valuePtr, &dString); Tcl_AppendElement(bindPtr->interp, Tcl_DStringValue(&dString)); break; } valuePtr = valuePtr->nextValue; } hPtr = Tcl_NextHashEntry(&search); } Tcl_DStringFree(&dString); return TCL_OK; } int QE_GetEventNames(QE_BindingTable bindingTable) { BindingTable *bindPtr = (BindingTable *) bindingTable; EventInfo *eiPtr; for (eiPtr = bindPtr->eventList; eiPtr != NULL; eiPtr = eiPtr->next) { Tcl_AppendElement(bindPtr->interp, eiPtr->name); } return TCL_OK; } int QE_GetDetailNames(QE_BindingTable bindingTable, char *eventName) { BindingTable *bindPtr = (BindingTable *) bindingTable; Tcl_HashEntry *hPtr; EventInfo *eiPtr; Detail *dPtr; hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, eventName); if (hPtr == NULL) { Tcl_AppendResult(bindPtr->interp, "unknown event \"", eventName, "\"", NULL); return TCL_ERROR; } eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); for (dPtr = eiPtr->detailList; dPtr != NULL; dPtr = dPtr->next) { Tcl_AppendElement(bindPtr->interp, dPtr->name); } return TCL_OK; } static void ExpandPercents(BindingTable *bindPtr, ClientData object, char *command, QE_Event *eventPtr, QE_ExpandProc expandProc, Tcl_DString *result) { char *string; QE_ExpandArgs expandArgs; #if 0 Tcl_DStringSetLength(result, 0); if (debug_bindings) dbwin("ExpandPercents on '%s' name=%s type=%d detail=%d expand=%lu\n", object, eiPtr->name, eiPtr->type, eventPtr->detail, eiPtr->expand); #endif expandArgs.bindingTable = (QE_BindingTable) bindPtr; expandArgs.object = object; expandArgs.event = eventPtr->type; expandArgs.detail = eventPtr->detail; expandArgs.result = result; expandArgs.clientData = eventPtr->clientData; while (1) { for (string = command; (*string != 0) && (*string != '%'); string++) { /* Empty loop body. */ } if (string != command) { Tcl_DStringAppend(result, command, (int) (string - command)); command = string; } if (*command == 0) { break; } /* Expand % here */ expandArgs.which = command[1]; (*expandProc)(&expandArgs); command += 2; } } static void BindEvent(BindingTable *bindPtr, QE_Event *eventPtr, int wantDetail, EventInfo *eiPtr, Detail *dPtr, GenerateData *gdPtr) { Tcl_HashEntry *hPtr; BindValue *valuePtr; ObjectTableKey keyObj; PatternTableKey key; Tcl_DString scripts, savedResult; int code; char *p, *end; char *command = gdPtr ? gdPtr->command : NULL; /* Find the first BindValue for this event */ key.type = eventPtr->type; key.detail = wantDetail ? eventPtr->detail : 0; hPtr = Tcl_FindHashEntry(&bindPtr->patternTable, (char *) &key); if (hPtr == NULL) return; /* Collect all scripts, with % expanded, separated by null characters. * Do it this way because anything could happen while evaluating, including * uninstalling events/details, even the interpreter being deleted. */ Tcl_DStringInit(&scripts); for (valuePtr = (BindValue *) Tcl_GetHashValue(hPtr); valuePtr; valuePtr = valuePtr->nextValue) { if (wantDetail && valuePtr->detail) { keyObj.type = key.type; keyObj.detail = 0; keyObj.object = valuePtr->object; hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) &keyObj); if (hPtr != NULL) { BindValue *value2Ptr; value2Ptr = (BindValue *) Tcl_GetHashValue(hPtr); value2Ptr->specific = 1; } } /* * If a binding for a more-specific event exists for this object * and event-type, and this is a binding for a less-specific * event, then skip this binding, since the binding for the * more-specific event was already invoked. */ else if (!wantDetail && valuePtr->specific) { if (debug_bindings) dbwin("QE_BindEvent: Skipping less-specific event type=%d object='%s'\n", valuePtr->type, (char *) valuePtr->object); valuePtr->specific = 0; continue; } #if BIND_ACTIVE /* This binding isn't active */ if (valuePtr->active == 0) continue; #endif /* BIND_ACTIVE */ #if ALLOW_INSTALL if (command == NULL) { if ((dPtr != NULL) && (dPtr->command != NULL)) { command = dPtr->command; } else if (((dPtr == NULL) || ((dPtr != NULL) && (dPtr->expandProc == NULL))) && (eiPtr->command != NULL)) { command = eiPtr->command; } } #endif /* ALLOW_INSTALL */ /* called by QE_GenerateCmd */ if (command != NULL) { PercentsData data; data.gdPtr = gdPtr; data.command = command; data.eventPtr = eiPtr; data.detailPtr = dPtr; eventPtr->clientData = (ClientData) &data; ExpandPercents(bindPtr, valuePtr->object, valuePtr->command, eventPtr, Percents_Command, &scripts); } /* called by QE_GenerateCmd */ else if (gdPtr != NULL) { /* Called QE_GenerateCmd with: * a) a static event and no percentsCommand argument, or * b) a dynamic event with no percentsCommand installed and * no percentsCommand argument */ eventPtr->clientData = (ClientData) gdPtr; ExpandPercents(bindPtr, valuePtr->object, valuePtr->command, eventPtr, Percents_CharMap, &scripts); } else { QE_ExpandProc expandProc = ((dPtr != NULL) && (dPtr->expandProc != NULL)) ? dPtr->expandProc : eiPtr->expandProc; ExpandPercents(bindPtr, valuePtr->object, valuePtr->command, eventPtr, expandProc, &scripts); } /* Separate each script by '\0' */ Tcl_DStringAppend(&scripts, "", 1); Tcl_DStringAppend(&scripts, eiPtr->name, -1); Tcl_DStringAppend(&scripts, "", 1); Tcl_DStringAppend(&scripts, (valuePtr->detail && dPtr) ? dPtr->name : "", -1); Tcl_DStringAppend(&scripts, "", 1); Tcl_DStringAppend(&scripts, valuePtr->object, -1); Tcl_DStringAppend(&scripts, "", 1); } /* Nothing to do. No need to call Tcl_DStringFree(&scripts) */ if (Tcl_DStringLength(&scripts) == 0) return; /* * As in Tk bindings, we expect that bindings may be invoked * in the middle of Tcl commands. So we preserve the current * interpreter result and restore it later. */ Tcl_DStringInit(&savedResult); Tcl_DStringGetResult(bindPtr->interp, &savedResult); p = Tcl_DStringValue(&scripts); end = p + Tcl_DStringLength(&scripts); while (p < end) { code = Tcl_GlobalEval(bindPtr->interp, p); p += strlen(p); p++; if (code != TCL_OK) { if (code == TCL_CONTINUE) { /* Nothing */ } else if (code == TCL_BREAK) { /* Nothing */ } else { char buf[256]; char *eventName = p; char *detailName = p + strlen(p) + 1; char *object = detailName + strlen(detailName) + 1; (void) sprintf(buf, "\n (<%s%s%s> binding on %s)", eventName, detailName[0] ? "-" : "", detailName, object); Tcl_AddErrorInfo(bindPtr->interp, buf); Tcl_BackgroundError(bindPtr->interp); } } /* Skip event\0detail\0object\0 */ p += strlen(p); p++; p += strlen(p); p++; p += strlen(p); p++; } Tcl_DStringFree(&scripts); /* Restore the interpreter result */ Tcl_DStringResult(bindPtr->interp, &savedResult); } static int BindEventWrapper(QE_BindingTable bindingTable, QE_Event *eventPtr, GenerateData *gdPtr) { BindingTable *bindPtr = (BindingTable *) bindingTable; Detail *dPtr = NULL; EventInfo *eiPtr; /* Find the event */ eiPtr = FindEvent(bindPtr, eventPtr->type); if (eiPtr == NULL) return TCL_OK; /* Find the detail */ if (eventPtr->detail) { dPtr = FindDetail(bindPtr, eventPtr->type, eventPtr->detail); if (dPtr == NULL) return TCL_OK; } BindEvent(bindPtr, eventPtr, 1, eiPtr, dPtr, gdPtr); if (eventPtr->detail) BindEvent(bindPtr, eventPtr, 0, eiPtr, dPtr, gdPtr); return TCL_OK; } int QE_BindEvent(QE_BindingTable bindingTable, QE_Event *eventPtr) { return BindEventWrapper(bindingTable, eventPtr, NULL); } static char *GetField(char *p, char *copy, int size) { int ch = *p; while ((ch != '\0') && !isspace(UCHAR(ch)) && ((ch != '>') || (p[1] != '\0')) && (ch != '-') && (size > 1)) { *copy = ch; p++; copy++; size--; ch = *p; } *copy = '\0'; while ((*p == '-') || isspace(UCHAR(*p))) { p++; } return p; } #define FIELD_SIZE 48 static int ParseEventDescription1(BindingTable *bindPtr, char *pattern, char eventName[FIELD_SIZE], char detailName[FIELD_SIZE]) { Tcl_Interp *interp = bindPtr->interp; char *p = pattern; eventName[0] = detailName[0] = '\0'; /* First char must by opening < */ if (*p != '<') { Tcl_AppendResult(interp, "missing \"<\" in event pattern \"", pattern, "\"", (char *) NULL); return TCL_ERROR; } p++; /* Event name (required)*/ p = GetField(p, eventName, FIELD_SIZE); if (debug_bindings) dbwin("GetField='%s'\n", eventName); /* Terminating > */ if (*p == '>') return TCL_OK; /* Detail name (optional) */ p = GetField(p, detailName, FIELD_SIZE); if (debug_bindings) dbwin("GetField='%s'\n", detailName); /* Terminating > */ if (*p != '>') { Tcl_AppendResult(interp, "missing \">\" in event pattern \"", pattern, "\"", (char *) NULL); return TCL_ERROR; } return TCL_OK; } static int ParseEventDescription(BindingTable *bindPtr, char *eventString, Pattern *patPtr, EventInfo **eventInfoPtr, Detail **detailPtr) { Tcl_Interp *interp = bindPtr->interp; Tcl_HashEntry *hPtr; char eventName[FIELD_SIZE], detailName[FIELD_SIZE]; EventInfo *eiPtr; Detail *dPtr; char errorMsg[512]; if (eventInfoPtr) *eventInfoPtr = NULL; if (detailPtr) *detailPtr = NULL; patPtr->type = -1; patPtr->detail = 0; if (ParseEventDescription1(bindPtr, eventString, eventName, detailName) != TCL_OK) return TCL_ERROR; hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, eventName); if (hPtr == NULL) { sprintf(errorMsg, "unknown event \"%.128s\"", eventName); Tcl_SetResult(interp, errorMsg, TCL_VOLATILE); return TCL_ERROR; } eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); patPtr->type = eiPtr->type; if (eventInfoPtr) *eventInfoPtr = eiPtr; if (detailName[0] != '\0') { /* Find detail for the matching event */ for (dPtr = eiPtr->detailList; dPtr != NULL; dPtr = dPtr->next) { if (strcmp(dPtr->name, detailName) == 0) break; } if (dPtr == NULL) { sprintf(errorMsg, "unknown detail \"%.128s\" for event \"%.128s\"", detailName, eiPtr->name); Tcl_SetResult(interp, errorMsg, TCL_VOLATILE); return TCL_ERROR; } patPtr->detail = dPtr->code; if (detailPtr) *detailPtr = dPtr; } return TCL_OK; } static int FindSequence(BindingTable *bindPtr, ClientData object, char *eventString, int create, int *created, BindValue **result) { Tcl_HashEntry *hPtr; Pattern pats; ObjectTableKey key; BindValue *valuePtr; int isNew; if (debug_bindings) dbwin("FindSequence object='%s' pattern='%s'...\n", (char *) object, eventString); if (created) (*created) = 0; /* Event description -> Pattern */ if (ParseEventDescription(bindPtr, eventString, &pats, NULL, NULL) != TCL_OK) return TCL_ERROR; /* type + detail + object -> BindValue */ key.type = pats.type; key.detail = pats.detail; key.object = object; if (create) { hPtr = Tcl_CreateHashEntry(&bindPtr->objectTable, (char *) &key, &isNew); if (isNew) { if (debug_bindings) dbwin("New BindValue for '%s' type=%d detail=%d\n", (char *) object, pats.type, pats.detail); valuePtr = (BindValue *) Tcl_Alloc(sizeof(BindValue)); valuePtr->type = pats.type; valuePtr->detail = pats.detail; valuePtr->object = object; valuePtr->command = NULL; valuePtr->specific = 0; valuePtr->nextValue = NULL; #if BIND_ACTIVE /* This binding is active */ valuePtr->active = 1; #endif /* BIND_ACTIVE */ Tcl_SetHashValue(hPtr, (ClientData) valuePtr); } if (created) (*created) = isNew; (*result) = (BindValue *) Tcl_GetHashValue(hPtr); return TCL_OK; } /* Look for existing objectTable entry */ hPtr = Tcl_FindHashEntry(&bindPtr->objectTable, (char *) &key); if (hPtr == NULL) { (*result) = NULL; return TCL_OK; } (*result) = (BindValue *) Tcl_GetHashValue(hPtr); return TCL_OK; } void QE_ExpandDouble(double number, Tcl_DString *result) { char numStorage[TCL_DOUBLE_SPACE]; Tcl_PrintDouble((Tcl_Interp *) NULL, number, numStorage); Tcl_DStringAppend(result, numStorage, -1); /* QE_ExpandString(numStorage, result); */ } void QE_ExpandNumber(long number, Tcl_DString *result) { char numStorage[TCL_INTEGER_SPACE]; (void) sprintf(numStorage, "%ld", number); Tcl_DStringAppend(result, numStorage, -1); /* QE_ExpandString(numStorage, result); */ } void QE_ExpandString(char *string, Tcl_DString *result) { int length, spaceNeeded, cvtFlags; spaceNeeded = Tcl_ScanElement(string, &cvtFlags); length = Tcl_DStringLength(result); Tcl_DStringSetLength(result, length + spaceNeeded); spaceNeeded = Tcl_ConvertElement(string, Tcl_DStringValue(result) + length, cvtFlags | TCL_DONT_USE_BRACES); Tcl_DStringSetLength(result, length + spaceNeeded); } void QE_ExpandUnknown(char which, Tcl_DString *result) { char string[2]; (void) sprintf(string, "%c", which); QE_ExpandString(string, result); } void QE_ExpandEvent(QE_BindingTable bindingTable, int eventType, Tcl_DString *result) { BindingTable *bindPtr = (BindingTable *) bindingTable; EventInfo *eiPtr = FindEvent(bindPtr, eventType); if (eiPtr != NULL) QE_ExpandString((char *) eiPtr->name, result); else QE_ExpandString("unknown", result); } void QE_ExpandDetail(QE_BindingTable bindingTable, int event, int detail, Tcl_DString *result) { BindingTable *bindPtr = (BindingTable *) bindingTable; Detail *dPtr; if (detail == 0) { QE_ExpandString("", result); return; } dPtr = FindDetail(bindPtr, event, detail); if (dPtr != NULL) QE_ExpandString((char *) dPtr->name, result); else QE_ExpandString("unknown", result); } void QE_ExpandPattern(QE_BindingTable bindingTable, int eventType, int detail, Tcl_DString *result) { BindingTable *bindPtr = (BindingTable *) bindingTable; EventInfo *eiPtr = FindEvent(bindPtr, eventType); Tcl_DStringAppend(result, "<", 1); Tcl_DStringAppend(result, eiPtr ? eiPtr->name : "unknown", -1); if (detail) { Detail *dPtr = FindDetail(bindPtr, eventType, detail); Tcl_DStringAppend(result, "-", 1); Tcl_DStringAppend(result, dPtr ? dPtr->name : "unknown", -1); } Tcl_DStringAppend(result, ">", 1); } int QE_BindCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; Tk_Window tkwin = Tk_MainWindow(bindPtr->interp); ClientData object; char *string; if ((objC < 1) || (objC > 4)) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "?object? ?pattern? ?script?"); return TCL_ERROR; } if (objC == 1) { QE_GetAllObjects(bindingTable); return TCL_OK; } string = Tcl_GetString(objV[1]); if (string[0] == '.') { Tk_Window tkwin2; tkwin2 = Tk_NameToWindow(bindPtr->interp, string, tkwin); if (tkwin2 == NULL) { return TCL_ERROR; } object = (ClientData) Tk_GetUid(Tk_PathName(tkwin2)); } else { object = (ClientData) Tk_GetUid(string); } if (objC == 4) { int append = 0; char *sequence = Tcl_GetString(objV[2]); char *script = Tcl_GetString(objV[3]); if (script[0] == 0) { return QE_DeleteBinding(bindingTable, object, sequence); } if (script[0] == '+') { script++; append = 1; } return QE_CreateBinding(bindingTable, object, sequence, script, append); } else if (objC == 3) { char *sequence = Tcl_GetString(objV[2]); return QE_GetBinding(bindingTable, object, sequence); } else { QE_GetAllBindings(bindingTable, object); } return TCL_OK; } int QE_UnbindCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; Tk_Window tkwin = Tk_MainWindow(bindPtr->interp); ClientData object; char *string, *sequence; if ((objC < 2) || (objC > 3)) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "object ?pattern?"); return TCL_ERROR; } string = Tcl_GetString(objV[1]); if (string[0] == '.') { Tk_Window tkwin2; tkwin2 = Tk_NameToWindow(bindPtr->interp, string, tkwin); if (tkwin2 == NULL) { return TCL_ERROR; } object = (ClientData) Tk_GetUid(Tk_PathName(tkwin2)); } else { object = (ClientData) Tk_GetUid(string); } if (objC == 2) { return QE_DeleteBinding(bindingTable, object, NULL); } sequence = Tcl_GetString(objV[2]); return QE_DeleteBinding(bindingTable, object, sequence); } /* * qegenerate -- Generate events from scripts. * Usage: qegenerate $pattern ?$charMap? ?$percentsCommand? * Desciption: Scripts can generate "fake" quasi-events by providing * a quasi-event pattern and option field/value pairs. */ int QE_GenerateCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; QE_Event fakeEvent; EventInfo *eiPtr; Detail *dPtr; GenerateData genData; GenerateField *fieldPtr; char *p, *t; int listObjc; int i; Tcl_Obj **listObjv; Pattern pats; int result; if (objC < 2 || objC > 4) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "pattern ?charMap? ?percentsCommand?"); return TCL_ERROR; } p = Tcl_GetStringFromObj(objV[1], NULL); if (ParseEventDescription(bindPtr, p, &pats, &eiPtr, &dPtr) != TCL_OK) return TCL_ERROR; /* Can't generate an event without a detail */ if ((dPtr == NULL) && (eiPtr->detailList != NULL)) { Tcl_AppendResult(bindPtr->interp, "cannot generate \"", p, "\": missing detail", (char *) NULL); return TCL_ERROR; } if (objC >= 3) { if (Tcl_ListObjGetElements(bindPtr->interp, objV[2], &listObjc, &listObjv) != TCL_OK) return TCL_ERROR; if (listObjc & 1) { Tcl_AppendResult(bindPtr->interp, "char map must have even number of elements", (char *) NULL); return TCL_ERROR; } genData.count = listObjc / 2; genData.field = genData.staticField; if (genData.count > sizeof(genData.staticField) / sizeof(genData.staticField[0])) { genData.field = (GenerateField *) Tcl_Alloc(sizeof(GenerateField) * genData.count); } genData.count = 0; while (listObjc > 1) { int length; t = Tcl_GetStringFromObj(listObjv[0], &length); if (length != 1) { Tcl_AppendResult(bindPtr->interp, "invalid percent char \"", t, "\"", NULL); result = TCL_ERROR; goto done; } /* Duplicate %-chars result in last duplicate being used */ fieldPtr = NULL; for (i = 0; i < genData.count; i++) { if (genData.field[i].which == t[0]) { fieldPtr = &genData.field[i]; break; } } if (fieldPtr == NULL) fieldPtr = &genData.field[genData.count++]; fieldPtr->which = t[0]; fieldPtr->string = Tcl_GetStringFromObj(listObjv[1], NULL); listObjv += 2; listObjc -= 2; } } else { genData.count = 0; genData.field = genData.staticField; } if (objC == 4) { genData.command = Tcl_GetString(objV[3]); } else { genData.command = NULL; } fakeEvent.type = pats.type; fakeEvent.detail = pats.detail; fakeEvent.clientData = NULL; result = BindEventWrapper(bindingTable, &fakeEvent, &genData); done: if (genData.field != genData.staticField) Tcl_Free((char *) genData.field); return result; } #if BIND_ACTIVE /* qeconfigure $win -active no */ int QE_ConfigureCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; Tcl_Interp *interp = bindPtr->interp; Tk_Window tkwin = Tk_MainWindow(interp); static CONST char *configSwitch[] = {"-active", NULL}; Tcl_Obj *CONST *objPtr; BindValue *valuePtr; char *t, *eventString; int index; ClientData object; if (objC < 3) { Tcl_WrongNumArgs(interp, objOffset + 1, objv, "object pattern ?option? ?value? ?option value ...?"); return TCL_ERROR; } t = Tcl_GetStringFromObj(objV[1], NULL); eventString = Tcl_GetStringFromObj(objV[2], NULL); if (t[0] == '.') { Tk_Window tkwin2; tkwin2 = Tk_NameToWindow(interp, t, tkwin); if (tkwin2 == NULL) { return TCL_ERROR; } object = (ClientData) Tk_GetUid(Tk_PathName(tkwin2)); } else { object = (ClientData) Tk_GetUid(t); } if (FindSequence(bindPtr, object, eventString, 0, NULL, &valuePtr) != TCL_OK) return TCL_ERROR; if (valuePtr == NULL) return TCL_OK; objPtr = objv + objOffset + 3; objc -= objOffset + 3; if (objc == 0) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-active", -1)); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewBooleanObj(valuePtr->active)); Tcl_SetObjResult(interp, listObj); return TCL_OK; } if (objc == 1) { if (Tcl_GetIndexFromObj(interp, objPtr[0], configSwitch, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case 0: /* -active */ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr->active)); break; } return TCL_OK; } while (objc > 1) { if (Tcl_GetIndexFromObj(interp, objPtr[0], configSwitch, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case 0: /* -active */ if (Tcl_GetBooleanFromObj(interp, objPtr[1], &valuePtr->active) != TCL_OK) { return TCL_ERROR; } break; } objPtr += 2; objc -= 2; } return TCL_OK; } #endif /* BIND_ACTIVE */ /* Perform %-substitution with $charMap only */ static void Percents_CharMap(QE_ExpandArgs *args) { GenerateData *gdPtr = (GenerateData *) args->clientData; int i; for (i = 0; i < gdPtr->count; i++) { GenerateField *gfPtr = &gdPtr->field[i]; if (gfPtr->which == args->which) { QE_ExpandString(gfPtr->string, args->result); return; } } QE_ExpandUnknown(args->which, args->result); } /* Perform %-substitution by calling a Tcl command */ static void Percents_Command(QE_ExpandArgs *args) { BindingTable *bindPtr = (BindingTable *) args->bindingTable; Tcl_Interp *interp = bindPtr->interp; PercentsData *data = (PercentsData *) args->clientData; GenerateData *gdPtr = data->gdPtr; EventInfo *eiPtr = data->eventPtr; Detail *dPtr = data->detailPtr; Tcl_DString command; Tcl_SavedResult state; int i; Tcl_DStringInit(&command); Tcl_DStringAppend(&command, data->command, -1); Tcl_DStringAppend(&command, " ", 1); Tcl_DStringAppend(&command, &args->which, 1); Tcl_DStringAppend(&command, " ", 1); Tcl_DStringAppend(&command, (char *) args->object, -1); Tcl_DStringAppend(&command, " ", 1); Tcl_DStringAppend(&command, eiPtr->name, -1); Tcl_DStringAppend(&command, " ", 1); if (dPtr != NULL) Tcl_DStringAppend(&command, dPtr->name, -1); else Tcl_DStringAppend(&command, "{}", -1); Tcl_DStringStartSublist(&command); for (i = 0; i < gdPtr->count; i++) { GenerateField *genField = &gdPtr->field[i]; char string[2]; string[0] = genField->which; string[1] = '\0'; Tcl_DStringAppendElement(&command, string); Tcl_DStringAppendElement(&command, genField->string); } Tcl_DStringEndSublist(&command); Tcl_SaveResult(interp, &state); if (Tcl_EvalEx(interp, Tcl_DStringValue(&command), Tcl_DStringLength(&command), TCL_EVAL_GLOBAL) == TCL_OK) { QE_ExpandString(Tcl_GetStringFromObj(Tcl_GetObjResult(interp), NULL), args->result); } else { QE_ExpandUnknown(args->which, args->result); Tcl_AddErrorInfo(interp, "\n (expanding percents)"); Tcl_BackgroundError(interp); } Tcl_RestoreResult(interp, &state); Tcl_DStringFree(&command); } #if ALLOW_INSTALL static int QE_InstallCmd_New(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; char *pattern, *command = NULL; char eventName[FIELD_SIZE], detailName[FIELD_SIZE]; int id, length; EventInfo *eiPtr; Detail *dPtr = NULL; Tcl_HashEntry *hPtr; if (objC < 2 || objC > 3) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "pattern ?percentsCommand?"); return TCL_ERROR; } pattern = Tcl_GetString(objV[1]); if (ParseEventDescription1(bindPtr, pattern, eventName, detailName) != TCL_OK) return TCL_ERROR; hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, eventName); /* The event is not defined */ if (hPtr == NULL) { id = QE_InstallEvent(bindingTable, eventName, NULL); if (id == 0) return TCL_ERROR; /* Find the event we just installed */ hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, eventName); if (hPtr == NULL) return TCL_ERROR; eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); /* Mark as installed-by-script */ eiPtr->dynamic = 1; } /* The event is already defined */ else { eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); } if (detailName[0]) { for (dPtr = eiPtr->detailList; dPtr != NULL; dPtr = dPtr->next) { if (strcmp(dPtr->name, detailName) == 0) break; } /* The detail is not defined */ if (dPtr == NULL) { /* Define the new detail */ id = QE_InstallDetail(bindingTable, detailName, eiPtr->type, NULL); if (id == 0) return TCL_ERROR; /* Get the detail we just defined */ dPtr = FindDetail(bindPtr, eiPtr->type, id); if (dPtr == NULL) return TCL_ERROR; /* Mark as installed-by-script */ dPtr->dynamic = 1; } } if (objC == 3) command = Tcl_GetStringFromObj(objV[2], &length); if (dPtr != NULL) { if (!dPtr->dynamic) { Tcl_AppendResult(bindPtr->interp, pattern, " is not dynamic", NULL); return TCL_ERROR; } if (command != NULL) { if (dPtr->command) { Tcl_Free(dPtr->command); dPtr->command = NULL; } if (length) { dPtr->command = Tcl_Alloc(length + 1); (void) strcpy(dPtr->command, command); } } if (dPtr->command) Tcl_SetResult(bindPtr->interp, dPtr->command, TCL_VOLATILE); } else { if (!eiPtr->dynamic) { Tcl_AppendResult(bindPtr->interp, pattern, " is not dynamic", NULL); return TCL_ERROR; } if (command != NULL) { if (eiPtr->command) { Tcl_Free(eiPtr->command); eiPtr->command = NULL; } if (length) { eiPtr->command = Tcl_Alloc(length + 1); (void) strcpy(eiPtr->command, command); } } if (eiPtr->command) Tcl_SetResult(bindPtr->interp, eiPtr->command, TCL_VOLATILE); } return TCL_OK; } static int QE_InstallCmd_Old(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; static CONST char *commandOption[] = {"detail", "event", NULL}; int index; if (objC < 2) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "option arg ..."); return TCL_ERROR; } if (Tcl_GetIndexFromObj(bindPtr->interp, objV[1], commandOption, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case 0: /* detail */ { char *eventName, *detailName, *command; int id, length; Detail *dPtr; EventInfo *eiPtr; Tcl_HashEntry *hPtr; if ((objC < 4) || (objC > 5)) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 2, objv, "event detail ?percentsCommand?"); return TCL_ERROR; } /* Find the event type */ eventName = Tcl_GetStringFromObj(objV[2], NULL); hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, eventName); if (hPtr == NULL) { Tcl_AppendResult(bindPtr->interp, "unknown event \"", eventName, "\"", NULL); return TCL_ERROR; } eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); /* Get the detail name */ detailName = Tcl_GetStringFromObj(objV[3], NULL); /* Define the new detail */ id = QE_InstallDetail(bindingTable, detailName, eiPtr->type, NULL); if (id == 0) return TCL_ERROR; /* Get the detail we just defined */ dPtr = FindDetail(bindPtr, eiPtr->type, id); if (dPtr == NULL) return TCL_ERROR; dPtr->dynamic = 1; if (objC == 4) break; /* Set the Tcl command for this detail */ command = Tcl_GetStringFromObj(objV[4], &length); if (length) { dPtr->command = Tcl_Alloc(length + 1); (void) strcpy(dPtr->command, command); } break; } case 1: /* event */ { char *eventName, *command; int id, length; EventInfo *eiPtr; Tcl_HashEntry *hPtr; if (objC < 3 || objC > 4) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 2, objv, "name ?percentsCommand?"); return TCL_ERROR; } eventName = Tcl_GetStringFromObj(objV[2], NULL); id = QE_InstallEvent(bindingTable, eventName, NULL); if (id == 0) return TCL_ERROR; /* Find the event we just installed */ hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, eventName); if (hPtr == NULL) return TCL_ERROR; eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); /* Mark as installed-by-script */ eiPtr->dynamic = 1; if (objC == 3) break; /* Set the Tcl command for this event */ command = Tcl_GetStringFromObj(objV[3], &length); if (length) { eiPtr->command = Tcl_Alloc(length + 1); (void) strcpy(eiPtr->command, command); } break; } } return TCL_OK; } int QE_InstallCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; char *s; int length; if (objC < 2) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "pattern ?percentsCommand?"); return TCL_ERROR; } s = Tcl_GetStringFromObj(objV[1], &length); if (length && (!strcmp(s, "detail") || !strcmp(s, "event"))) return QE_InstallCmd_Old(bindingTable, objOffset, objc, objv); return QE_InstallCmd_New(bindingTable, objOffset, objc, objv); } static int QE_UninstallCmd_New(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; char *pattern; Pattern pats; EventInfo *eiPtr; Detail *dPtr; if (objC != 2) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "pattern"); return TCL_ERROR; } pattern = Tcl_GetString(objV[1]); if (ParseEventDescription(bindPtr, pattern, &pats, &eiPtr, &dPtr) != TCL_OK) return TCL_ERROR; if (dPtr != NULL) { if (!dPtr->dynamic) { Tcl_AppendResult(bindPtr->interp, "can't uninstall static detail \"", dPtr->name, "\"", NULL); return TCL_ERROR; } return QE_UninstallDetail(bindingTable, eiPtr->type, dPtr->code); } if (!eiPtr->dynamic) { Tcl_AppendResult(bindPtr->interp, "can't uninstall static event \"", eiPtr->name, "\"", NULL); return TCL_ERROR; } return QE_UninstallEvent(bindingTable, eiPtr->type); } static int QE_UninstallCmd_Old(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; static CONST char *commandOption[] = {"detail", "event", NULL}; int index; if (objC < 2) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "option arg ..."); return TCL_ERROR; } if (Tcl_GetIndexFromObj(bindPtr->interp, objV[1], commandOption, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case 0: /* detail */ { char *eventName, *detailName; Detail *dPtr; EventInfo *eiPtr; Tcl_HashEntry *hPtr; if (objC != 4) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 2, objv, "event detail"); return TCL_ERROR; } /* Find the event type */ eventName = Tcl_GetStringFromObj(objV[2], NULL); hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, eventName); if (hPtr == NULL) { Tcl_AppendResult(bindPtr->interp, "unknown event \"", eventName, "\"", NULL); return TCL_ERROR; } eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); /* Get the detail name */ detailName = Tcl_GetStringFromObj(objV[3], NULL); for (dPtr = eiPtr->detailList; dPtr != NULL; dPtr = dPtr->next) { if (strcmp(dPtr->name, detailName) == 0) break; } if (dPtr == NULL) { Tcl_AppendResult(bindPtr->interp, "unknown detail \"", detailName, "\" for event \"", eiPtr->name, "\"", NULL); return TCL_ERROR; } if (!dPtr->dynamic) { Tcl_AppendResult(bindPtr->interp, "can't uninstall static detail \"", detailName, "\"", NULL); return TCL_ERROR; } return QE_UninstallDetail(bindingTable, eiPtr->type, dPtr->code); } case 1: /* event */ { Tcl_HashEntry *hPtr; EventInfo *eiPtr; char *eventName; if (objC != 3) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 2, objv, "name"); return TCL_ERROR; } /* Find the event type */ eventName = Tcl_GetStringFromObj(objV[2], NULL); hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, eventName); if (hPtr == NULL) { Tcl_AppendResult(bindPtr->interp, "unknown event \"", eventName, "\"", NULL); return TCL_ERROR; } eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); if (!eiPtr->dynamic) { Tcl_AppendResult(bindPtr->interp, "can't uninstall static event \"", eventName, "\"", NULL); return TCL_ERROR; } return QE_UninstallEvent(bindingTable, eiPtr->type); } } return TCL_OK; } int QE_UninstallCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; char *s; int length; if (objC < 2) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "pattern"); return TCL_ERROR; } s = Tcl_GetStringFromObj(objV[1], &length); if (length && (!strcmp(s, "detail") || !strcmp(s, "event"))) return QE_UninstallCmd_Old(bindingTable, objOffset, objc, objv); return QE_UninstallCmd_New(bindingTable, objOffset, objc, objv); } static int QE_LinkageCmd_New(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; char *pattern; Pattern pats; EventInfo *eiPtr; Detail *dPtr; if (objC != 2) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "pattern"); return TCL_ERROR; } pattern = Tcl_GetString(objV[1]); if (ParseEventDescription(bindPtr, pattern, &pats, &eiPtr, &dPtr) != TCL_OK) return TCL_ERROR; if (dPtr != NULL) { Tcl_SetResult(bindPtr->interp, dPtr->dynamic ? "dynamic" : "static", TCL_STATIC); return TCL_OK; } Tcl_SetResult(bindPtr->interp, eiPtr->dynamic ? "dynamic" : "static", TCL_STATIC); return TCL_OK; } static int QE_LinkageCmd_Old(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; char *eventName, *detailName; Detail *dPtr; EventInfo *eiPtr; Tcl_HashEntry *hPtr; if (objC < 2 || objC > 3) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "event ?detail?"); return TCL_ERROR; } /* Find the event type */ eventName = Tcl_GetStringFromObj(objV[1], NULL); hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, eventName); if (hPtr == NULL) { Tcl_AppendResult(bindPtr->interp, "unknown event \"", eventName, "\"", NULL); return TCL_ERROR; } eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr); if (objC == 2) { Tcl_SetResult(bindPtr->interp, eiPtr->dynamic ? "dynamic" : "static", TCL_STATIC); return TCL_OK; } /* Get the detail name */ detailName = Tcl_GetStringFromObj(objV[2], NULL); for (dPtr = eiPtr->detailList; dPtr != NULL; dPtr = dPtr->next) { if (strcmp(dPtr->name, detailName) == 0) break; } if (dPtr == NULL) { Tcl_AppendResult(bindPtr->interp, "unknown detail \"", detailName, "\" for event \"", eiPtr->name, "\"", NULL); return TCL_ERROR; } Tcl_SetResult(bindPtr->interp, dPtr->dynamic ? "dynamic" : "static", TCL_STATIC); return TCL_OK; } int QE_LinkageCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]) { int objC = objc - objOffset; Tcl_Obj *CONST *objV = objv + objOffset; BindingTable *bindPtr = (BindingTable *) bindingTable; char *s; int length; if (objC < 2) { Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "pattern"); return TCL_ERROR; } s = Tcl_GetStringFromObj(objV[1], &length); if ((objC == 3) || (length && s[0] != '<')) return QE_LinkageCmd_Old(bindingTable, objOffset, objc, objv); return QE_LinkageCmd_New(bindingTable, objOffset, objc, objv); } #endif /* ALLOW_INSTALL */ tktreectrl-2.4.1/generic/qebind.h0000644000076400010400000000701511562306331017245 0ustar TimAdministrators/* * qebind.h -- * * This module is the header for quasi-events. * * Copyright (c) 2002-2011 Tim Baker */ #ifndef INCLUDED_QEBIND_H #define INCLUDED_QEBIND_H /* * Used to tag functions that are only to be visible within the module being * built and not outside it (where this is supported by the linker). */ #ifndef MODULE_SCOPE # ifdef __cplusplus # define MODULE_SCOPE extern "C" # else # define MODULE_SCOPE extern # endif #endif typedef struct QE_BindingTable_ *QE_BindingTable; /* Pass to QE_BindEvent */ typedef struct QE_Event { int type; int detail; ClientData clientData; } QE_Event; typedef struct QE_ExpandArgs { QE_BindingTable bindingTable; char which; ClientData object; Tcl_DString *result; int event; int detail; ClientData clientData; } QE_ExpandArgs; typedef void (*QE_ExpandProc)(QE_ExpandArgs *args); MODULE_SCOPE int debug_bindings; MODULE_SCOPE int QE_BindInit(Tcl_Interp *interp); MODULE_SCOPE QE_BindingTable QE_CreateBindingTable(Tcl_Interp *interp); MODULE_SCOPE void QE_DeleteBindingTable(QE_BindingTable bindingTable); MODULE_SCOPE int QE_InstallEvent(QE_BindingTable bindingTable, char *name, QE_ExpandProc expand); MODULE_SCOPE int QE_InstallDetail(QE_BindingTable bindingTable, char *name, int eventType, QE_ExpandProc expand); MODULE_SCOPE int QE_UninstallEvent(QE_BindingTable bindingTable, int eventType); MODULE_SCOPE int QE_UninstallDetail(QE_BindingTable bindingTable, int eventType, int detail); MODULE_SCOPE int QE_CreateBinding(QE_BindingTable bindingTable, ClientData object, char *eventString, char *command, int append); MODULE_SCOPE int QE_DeleteBinding(QE_BindingTable bindingTable, ClientData object, char *eventString); MODULE_SCOPE int QE_GetAllObjects(QE_BindingTable bindingTable); MODULE_SCOPE int QE_GetBinding(QE_BindingTable bindingTable, ClientData object, char *eventString); MODULE_SCOPE int QE_GetAllBindings(QE_BindingTable bindingTable, ClientData object); MODULE_SCOPE int QE_GetEventNames(QE_BindingTable bindingTable); MODULE_SCOPE int QE_GetDetailNames(QE_BindingTable bindingTable, char *eventName); MODULE_SCOPE int QE_BindEvent(QE_BindingTable bindingTable, QE_Event *eventPtr); MODULE_SCOPE void QE_ExpandDouble(double number, Tcl_DString *result); MODULE_SCOPE void QE_ExpandNumber(long number, Tcl_DString *result); MODULE_SCOPE void QE_ExpandString(char *string, Tcl_DString *result); MODULE_SCOPE void QE_ExpandEvent(QE_BindingTable bindingTable, int eventType, Tcl_DString *result); MODULE_SCOPE void QE_ExpandDetail(QE_BindingTable bindingTable, int event, int detail, Tcl_DString *result); MODULE_SCOPE void QE_ExpandPattern(QE_BindingTable bindingTable, int eventType, int detail, Tcl_DString *result); MODULE_SCOPE void QE_ExpandUnknown(char which, Tcl_DString *result); MODULE_SCOPE int QE_BindCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int QE_ConfigureCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int QE_GenerateCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int QE_InstallCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int QE_UnbindCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int QE_UninstallCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int QE_LinkageCmd(QE_BindingTable bindingTable, int objOffset, int objc, Tcl_Obj *CONST objv[]); #endif /* INCLUDED_QEBIND_H */ tktreectrl-2.4.1/generic/tkTreeColumn.c0000644000076400010400000042273311573760660020435 0ustar TimAdministrators/* * tkTreeColumn.c -- * * This module implements treectrl widget's columns. * * Copyright (c) 2002-2011 Tim Baker * Copyright (c) 2002-2003 Christian Krone * Copyright (c) 2003 ActiveState Corporation */ #include "tkTreeCtrl.h" typedef struct TreeColumn_ TreeColumn_; typedef struct ColumnSpan ColumnSpan; typedef struct SpanArray SpanArray; struct SpanArray { ColumnSpan **spans; int count; /* Number of useful elements in spans[]. */ int alloc; /* Number of elements allocated in spans[]. */ }; /* A structure of the following type is kept for each span in an item or * header that covers a unique range of columns. */ struct ColumnSpan { TreeColumn start; /* First column in the span. */ TreeColumn end; /* Last column in the span. */ int maxNeededWidth; /* Width of the widest style in any item * or header. */ int widthOfColumns; /* Sum of the calculated display widths of * the columns. */ SpanArray spansToRight; /* List of spans following this one. */ ColumnSpan *next; /* Head is TreeColumnPriv_.spans. */ ColumnSpan *nextCur; /* Head is TreeColumnPriv_.spansCur. */ int sumOfSpans; }; /* A structure of the following type is kept for each TreeColumn. * This is used when calculating the requested width of styles. */ typedef struct ColumnReqData ColumnReqData; struct ColumnReqData { int vis; /* TRUE if the column is visible, otherwise FALSE. */ int min; /* -minwidth or -1, no greater than -maxwidth. */ int fixed; /* -width, or -1. */ int max; /* -maxwidth or -1. */ int req; /* The width requested by a all or part of a style * in a single item in this column. */ int maxSingleSpanWidth; /* The widest span of 1. */ int maxSingleItemWidth; /* The widest span of 1 in items. */ int maxSingleHeaderWidth; /* The widest span of 1 in headers. */ SpanArray spans; /* Array of span pointers touching this column.*/ TreeColumn spanMin; /* Any span that includes this column */ TreeColumn spanMax; /* begins on or after spanMin and ends on */ /* or before spanMax. This includes spans */ /* in headers and items. */ int fat; /* TRUE when every spans[].widthOfColumns is greater * than spans[].maxNeededWidth, indicating the column * is wider than needed. */ }; /* A structure of the following type is kept for each TreeCtrl to hold * private data used by this file. */ struct TreeColumnPriv_ { int spansInvalid; /* TRUE if the TreeColumn.spanMin and * TreeColumn.spanMax fields are * out-of-date, otherwise FALSE. */ int reqInvalid; /* TRUE if TreeColumn.reqData is out-of-date, * otherwise FALSE. */ ColumnSpan *spans; /* All the spans for the widget. */ ColumnSpan *freeSpans; /* Unused spans. */ ColumnSpan *spansCur; /* The subset of spans[] for the current * update. */ int allSpansAreOne; /* TRUE if all spans cover exactly one column, * otherwise FALSE. */ }; #ifdef UNIFORM_GROUP typedef struct UniformGroup { Tcl_HashEntry *hPtr; /* Entry in TreeCtrl.uniformGroupHash */ int refCount; /* Number of columns in this group. */ int minSize; /* Used during layout. */ } UniformGroup; #endif /* * The following structure holds information about a single * column in a TreeCtrl. */ struct TreeColumn_ { int width; /* -width */ Tcl_Obj *widthObj; /* -width */ int minWidth; /* -minwidth */ Tcl_Obj *minWidthObj; /* -minwidth */ int maxWidth; /* -maxwidth */ Tcl_Obj *maxWidthObj; /* -maxwidth */ #ifdef DEPRECATED int stepWidth; /* -stepwidth */ Tcl_Obj *stepWidthObj; /* -stepwidth */ int widthHack; /* -widthhack */ #endif /* DEPRECATED */ Tk_Justify justify; /* -justify */ int itemJustify; /* -itemjustify */ int expand; /* -expand */ int squeeze; /* -squeeze */ int visible; /* -visible */ int resize; /* -resize */ TagInfo *tagInfo; /* -tags */ Tcl_Obj *itemBgObj; /* -itembackground */ TreeStyle itemStyle; /* -itemstyle */ int lock; /* -lock */ TreeCtrl *tree; Tk_OptionTable optionTable; int id; /* unique column identifier */ int index; /* order in list of columns */ int offset; /* Total width of preceding columns */ int useWidth; /* -width, -minwidth, or required+expansion */ int widthOfItems; /* width of all TreeItemColumns */ int itemBgCount; /* -itembackground colors */ TreeColor **itemBgColor; /* -itembackground colors */ TreeColumn prev; TreeColumn next; #ifdef UNIFORM_GROUP UniformGroup *uniform; /* -uniform */ int weight; /* -weight */ #endif TreeColumnDInfo dInfo; /* Display info. */ #if COLUMNGRID == 1 Tcl_Obj *gridLeftColorObj; /* -gridleftcolor */ Tcl_Obj *gridRightColorObj; /* -gridrightcolor */ TreeColor *gridLeftColor; /* -gridleftcolor */ TreeColor *gridRightColor; /* -gridrightcolor */ #endif ColumnReqData reqData; }; #ifdef UNIFORM_GROUP /* *---------------------------------------------------------------------- * * UniformGroupCO_Set -- * UniformGroupCO_Get -- * UniformGroupCO_Restore -- * UniformGroupCO_Free -- * * These procedures implement a TK_OPTION_CUSTOM where the custom * option is a UniformGroup. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int UniformGroupCO_Set( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **valuePtr, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; int objEmpty; UniformGroup **internalPtr, *new; if (internalOffset >= 0) internalPtr = (UniformGroup **) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*valuePtr)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) (*valuePtr) = NULL; if (internalPtr != NULL) { if (*valuePtr != NULL) { int isNew; Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(&tree->uniformGroupHash, Tcl_GetString(*valuePtr), &isNew); if (isNew) { new = (UniformGroup *) ckalloc(sizeof(UniformGroup)); new->refCount = 0; new->hPtr = hPtr; Tcl_SetHashValue(hPtr, (ClientData) new); } else { new = (UniformGroup *) Tcl_GetHashValue(hPtr); } new->refCount++; #ifdef TREECTRL_DEBUG if (tree->debug.enable) dbwin("UniformGroupCO_Set: %s refCount=%d\n", Tcl_GetString(*valuePtr), new->refCount); #endif } else { new = NULL; } *((UniformGroup **) saveInternalPtr) = *internalPtr; *internalPtr = new; } return TCL_OK; } static Tcl_Obj * UniformGroupCO_Get( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; UniformGroup *uniform = *(UniformGroup **) (recordPtr + internalOffset); if (uniform == NULL) return NULL; return Tcl_NewStringObj(Tcl_GetHashKey(&tree->uniformGroupHash, uniform->hPtr), -1); } static void UniformGroupCO_Restore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr ) { *(UniformGroup **) internalPtr = *(UniformGroup **) saveInternalPtr; } static void UniformGroupCO_Free( ClientData clientData, Tk_Window tkwin, char *internalPtr ) { UniformGroup *uniform = *(UniformGroup **) internalPtr; #ifdef TREECTRL_DEBUG TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; if (tree->debug.enable && uniform != NULL) { dbwin("UniformGroupCO_Free: %s refCount=%d\n", Tcl_GetHashKey(&tree->uniformGroupHash, uniform->hPtr), uniform->refCount - 1); } #endif if ((uniform != NULL) && (--uniform->refCount <= 0)) { Tcl_DeleteHashEntry(uniform->hPtr); ckfree((char *) uniform); *((UniformGroup **) internalPtr) = NULL; } } static Tk_ObjCustomOption uniformGroupCO = { "uniform group", UniformGroupCO_Set, UniformGroupCO_Get, UniformGroupCO_Restore, UniformGroupCO_Free, (ClientData) NULL }; #endif /* UNIFORM_GROUP */ static CONST char *arrowSideST[] = { "left", "right", (char *) NULL }; static CONST char *lockST[] = { "left", "none", "right", (char *) NULL }; static CONST char *justifyStrings[] = { "left", "right", "center", (char *) NULL }; #define COLU_CONF_TWIDTH 0x0008 /* totalWidth */ #define COLU_CONF_ITEMBG 0x0010 #define COLU_CONF_DISPLAY 0x0040 #define COLU_CONF_JUSTIFY 0x0080 #define COLU_CONF_TAGS 0x0100 #ifdef DEPRECATED #define COLU_CONF_RANGES 0x0800 #endif #if COLUMNGRID == 1 #define COLU_CONF_GRIDLINES 0x1000 #endif static Tk_OptionSpec columnSpecs[] = { {TK_OPTION_BOOLEAN, "-expand", (char *) NULL, (char *) NULL, "0", -1, Tk_Offset(TreeColumn_, expand), 0, (ClientData) NULL, COLU_CONF_TWIDTH}, #if COLUMNGRID==1 {TK_OPTION_CUSTOM, "-gridleftcolor", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TreeColumn_, gridLeftColorObj), Tk_Offset(TreeColumn_, gridLeftColor), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_treecolor, COLU_CONF_GRIDLINES}, {TK_OPTION_CUSTOM, "-gridrightcolor", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TreeColumn_, gridRightColorObj), Tk_Offset(TreeColumn_, gridRightColor), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_treecolor, COLU_CONF_GRIDLINES}, #endif {TK_OPTION_STRING, "-itembackground", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TreeColumn_, itemBgObj), -1, TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_ITEMBG}, {TK_OPTION_CUSTOM, "-itemjustify", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeColumn_, itemJustify), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_JUSTIFY}, {TK_OPTION_CUSTOM, "-itemstyle", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeColumn_, itemStyle), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_style, 0}, {TK_OPTION_JUSTIFY, "-justify", (char *) NULL, (char *) NULL, "left", -1, Tk_Offset(TreeColumn_, justify), 0, (ClientData) NULL, COLU_CONF_DISPLAY | COLU_CONF_JUSTIFY}, {TK_OPTION_STRING_TABLE, "-lock", (char *) NULL, (char *) NULL, "none", -1, Tk_Offset(TreeColumn_, lock), 0, (ClientData) lockST, 0}, {TK_OPTION_PIXELS, "-maxwidth", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TreeColumn_, maxWidthObj), Tk_Offset(TreeColumn_, maxWidth), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TWIDTH}, {TK_OPTION_PIXELS, "-minwidth", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TreeColumn_, minWidthObj), Tk_Offset(TreeColumn_, minWidth), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TWIDTH}, {TK_OPTION_BOOLEAN, "-resize", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeColumn_, resize), 0, (ClientData) NULL, 0}, {TK_OPTION_BOOLEAN, "-squeeze", (char *) NULL, (char *) NULL, "0", -1, Tk_Offset(TreeColumn_, squeeze), 0, (ClientData) NULL, COLU_CONF_TWIDTH}, #ifdef DEPRECATED {TK_OPTION_PIXELS, "-stepwidth", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TreeColumn_, stepWidthObj), Tk_Offset(TreeColumn_, stepWidth), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_RANGES}, #endif /* DEPRECATED */ {TK_OPTION_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeColumn_, tagInfo), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_tagInfo, COLU_CONF_TAGS}, #ifdef UNIFORM_GROUP {TK_OPTION_CUSTOM, "-uniform", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeColumn_, uniform), TK_OPTION_NULL_OK, (ClientData) &uniformGroupCO, COLU_CONF_TWIDTH}, {TK_OPTION_INT, "-weight", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeColumn_, weight), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TWIDTH}, #endif {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TreeColumn_, widthObj), Tk_Offset(TreeColumn_, width), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TWIDTH}, {TK_OPTION_BOOLEAN, "-visible", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeColumn_, visible), 0, (ClientData) NULL, COLU_CONF_TWIDTH | COLU_CONF_DISPLAY}, #ifdef DEPRECATED {TK_OPTION_BOOLEAN, "-widthhack", (char *) NULL, (char *) NULL, "0", -1, Tk_Offset(TreeColumn_, widthHack), 0, (ClientData) NULL, COLU_CONF_RANGES}, #endif /* DEPRECATED */ {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, 0, 0} }; #define IS_TAIL(C) ((C) == tree->columnTail) #define IS_ALL(C) (((C) == COLUMN_ALL) || ((C) == COLUMN_NTAIL)) /* *---------------------------------------------------------------------- * * ColumnCO_Set -- * * Tk_ObjCustomOption.setProc(). Converts a Tcl_Obj holding a * column description into a pointer to a Column. * * Results: * A standard Tcl result. * * Side effects: * May store a TreeColumn pointer into the internal representation * pointer. May change the pointer to the Tcl_Obj to NULL to indicate * that the specified string was empty and that is acceptable. * *---------------------------------------------------------------------- */ static int ColumnCO_Set( ClientData clientData, /* CFO_xxx flags to control the conversion. */ Tcl_Interp *interp, /* Current interpreter. */ Tk_Window tkwin, /* Window for which option is being set. */ Tcl_Obj **value, /* Pointer to the pointer to the value object. * We use a pointer to the pointer because * we may need to return a value (NULL). */ char *recordPtr, /* Pointer to storage for the widget record. */ int internalOffset, /* Offset within *recordPtr at which the * internal value is to be stored. */ char *saveInternalPtr, /* Pointer to storage for the old value. */ int flags /* Flags for the option, set Tk_SetOptions. */ ) { int cfoFlags = PTR2INT(clientData); TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; int objEmpty; TreeColumn new, *internalPtr; if (internalOffset >= 0) internalPtr = (TreeColumn *) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*value)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) (*value) = NULL; else { if (TreeColumn_FromObj(tree, (*value), &new, cfoFlags) != TCL_OK) return TCL_ERROR; } if (internalPtr != NULL) { if ((*value) == NULL) new = NULL; *((TreeColumn *) saveInternalPtr) = *internalPtr; *internalPtr = new; } return TCL_OK; } /* *---------------------------------------------------------------------- * * ColumnCO_Get -- * * Tk_ObjCustomOption.getProc(). Converts a TreeColumn into a * Tcl_Obj string representation. * * Results: * Tcl_Obj containing the string representation of the column. * Returns NULL if the TreeColumn is NULL. * * Side effects: * May create a new Tcl_Obj. * *---------------------------------------------------------------------- */ static Tcl_Obj * ColumnCO_Get( ClientData clientData, /* Not used. */ Tk_Window tkwin, /* Window for which option is being set. */ char *recordPtr, /* Pointer to widget record. */ int internalOffset /* Offset within *recordPtr containing the * sticky value. */ ) { TreeColumn value = *(TreeColumn *) (recordPtr + internalOffset); TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; if (value == NULL) return NULL; #if 0 if (value == COLUMN_ALL) return Tcl_NewStringObj("all", -1); #endif return TreeColumn_ToObj(tree, value); } /* *---------------------------------------------------------------------- * * ColumnCO_Restore -- * * Tk_ObjCustomOption.restoreProc(). Restores a TreeColumn value * from a saved value. * * Results: * None. * * Side effects: * Restores the old value. * *---------------------------------------------------------------------- */ static void ColumnCO_Restore( ClientData clientData, /* Not used. */ Tk_Window tkwin, /* Not used. */ char *internalPtr, /* Where to store old value. */ char *saveInternalPtr) /* Pointer to old value. */ { *(TreeColumn *) internalPtr = *(TreeColumn *) saveInternalPtr; } /* * The following structure contains pointers to functions used for processing * a custom config option that handles Tcl_Obj<->TreeColumn conversion. * A column description must refer to a single column. */ Tk_ObjCustomOption TreeCtrlCO_column = { "column", ColumnCO_Set, ColumnCO_Get, ColumnCO_Restore, NULL, (ClientData) INT2PTR(CFO_NOT_NULL) }; /* * The following structure contains pointers to functions used for processing * a custom config option that handles Tcl_Obj<->TreeColumn conversion. * A column description must refer to a single column. * "tail" is not allowed. */ Tk_ObjCustomOption TreeCtrlCO_column_NOT_TAIL = { "column", ColumnCO_Set, ColumnCO_Get, ColumnCO_Restore, NULL, (ClientData) INT2PTR(CFO_NOT_NULL | CFO_NOT_TAIL) }; static Tk_OptionSpec dragSpecs[] = { {TK_OPTION_BOOLEAN, "-enable", (char *) NULL, (char *) NULL, "0", -1, Tk_Offset(TreeCtrl, columnDrag.enable), 0, (ClientData) NULL, 0}, {TK_OPTION_INT, "-imagealpha", (char *) NULL, (char *) NULL, "200", -1, Tk_Offset(TreeCtrl, columnDrag.alpha), 0, (ClientData) NULL, 0}, {TK_OPTION_COLOR, "-imagecolor", (char *) NULL, (char *) NULL, "gray75", -1, Tk_Offset(TreeCtrl, columnDrag.color), 0, (ClientData) NULL, 0}, {TK_OPTION_CUSTOM, "-imagecolumn", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeCtrl, columnDrag.column), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_column_NOT_TAIL, 0}, {TK_OPTION_PIXELS, "-imageoffset", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TreeCtrl, columnDrag.offsetObj), Tk_Offset(TreeCtrl, columnDrag.offset), 0, (ClientData) NULL, 0}, {TK_OPTION_INT, "-imagespan", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeCtrl, columnDrag.span), 0, (ClientData) NULL, 0}, {TK_OPTION_COLOR, "-indicatorcolor", (char *) NULL, (char *) NULL, "Black", -1, Tk_Offset(TreeCtrl, columnDrag.indColor), 0, (ClientData) NULL, 0}, {TK_OPTION_CUSTOM, "-indicatorcolumn", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeCtrl, columnDrag.indColumn), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_column, 0}, {TK_OPTION_STRING_TABLE, "-indicatorside", (char *) NULL, (char *) NULL, "left", -1, Tk_Offset(TreeCtrl, columnDrag.indSide), 0, (ClientData) arrowSideST, 0}, {TK_OPTION_INT, "-indicatorspan", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeCtrl, columnDrag.indSpan), 0, (ClientData) NULL, 0}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, 0, 0} }; /* *---------------------------------------------------------------------- * * TreeColumn_FirstAndLast -- * * Determine the order of two columns and swap them if needed. * * Results: * The return value is the number of columns in the range between * first and last. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_FirstAndLast( TreeColumn *first, /* Column token. */ TreeColumn *last /* Column token. */ ) { int indexFirst, indexLast, index; indexFirst = TreeColumn_Index(*first); indexLast = TreeColumn_Index(*last); if (indexFirst > indexLast) { TreeColumn column = *first; *first = *last; *last = column; index = indexFirst; indexFirst = indexLast; indexLast = index; } return indexLast - indexFirst + 1; } /* *---------------------------------------------------------------------- * * ColumnHasTag -- * * Checks whether a column has a certain tag. * * Results: * Returns TRUE if the column has the given tag. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int ColumnHasTag( TreeColumn column, /* The column to test. */ Tk_Uid tag /* Tag to look for. */ ) { TagInfo *tagInfo = column->tagInfo; Tk_Uid *tagPtr; int count; if (tagInfo == NULL) return 0; for (tagPtr = tagInfo->tagPtr, count = tagInfo->numTags; count > 0; tagPtr++, count--) { if (*tagPtr == tag) { return 1; } } return 0; } typedef struct Qualifiers { TreeCtrl *tree; int visible; /* 1 for -visible TRUE, 0 for -visible FALSE, -1 for unspecified. */ TagExpr expr; /* Tag expression. */ int exprOK; /* TRUE if expr is valid. */ int lock; /* COLUMN_LOCK_xxx or -1 */ int ntail; /* 1 for !tail, * 0 for unspecified. */ Tk_Uid tag; /* Tag (without operators) or NULL. */ } Qualifiers; /* *---------------------------------------------------------------------- * * Qualifiers_Init -- * * Helper routine for TreeColumnList_FromObj. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Qualifiers_Init( TreeCtrl *tree, /* Widget info. */ Qualifiers *q /* Out: Initialized qualifiers. */ ) { q->tree = tree; q->visible = -1; q->exprOK = FALSE; q->lock = -1; q->ntail = 0; q->tag = NULL; } /* *---------------------------------------------------------------------- * * Qualifiers_Scan -- * * Helper routine for TreeColumnList_FromObj. * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Qualifiers_Scan( Qualifiers *q, /* Must call Qualifiers_Init first, * and Qualifiers_Free if result is TCL_OK. */ int objc, /* Number of arguments. */ Tcl_Obj **objv, /* Argument values. */ int startIndex, /* First objv[] index to look at. */ int *argsUsed /* Out: number of objv[] used. */ ) { TreeCtrl *tree = q->tree; Tcl_Interp *interp = tree->interp; int qual, j = startIndex; static CONST char *qualifiers[] = { "lock", "tag", "visible", "!tail", "!visible", NULL }; enum qualEnum { QUAL_LOCK, QUAL_TAG, QUAL_VISIBLE, QUAL_NOT_TAIL, QUAL_NOT_VISIBLE }; /* Number of arguments used by qualifiers[]. */ static int qualArgs[] = { 2, 2, 1, 1, 1 }; *argsUsed = 0; for (; j < objc; ) { if (Tcl_GetIndexFromObj(NULL, objv[j], qualifiers, NULL, 0, &qual) != TCL_OK) break; if (objc - j < qualArgs[qual]) { Tcl_AppendResult(interp, "missing arguments to \"", Tcl_GetString(objv[j]), "\" qualifier", NULL); goto errorExit; } switch ((enum qualEnum) qual) { case QUAL_LOCK: { if (Tcl_GetIndexFromObj(interp, objv[j + 1], lockST, "lock", 0, &q->lock) != TCL_OK) goto errorExit; break; } case QUAL_TAG: { if (tree->columnTagExpr) { if (q->exprOK) TagExpr_Free(&q->expr); if (TagExpr_Init(tree, objv[j + 1], &q->expr) != TCL_OK) return TCL_ERROR; q->exprOK = TRUE; } else { q->tag = Tk_GetUid(Tcl_GetString(objv[j + 1])); } break; } case QUAL_VISIBLE: { q->visible = 1; break; } case QUAL_NOT_TAIL: { q->ntail = 1; break; } case QUAL_NOT_VISIBLE: { q->visible = 0; break; } } *argsUsed += qualArgs[qual]; j += qualArgs[qual]; } return TCL_OK; errorExit: if (q->exprOK) TagExpr_Free(&q->expr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Qualifies -- * * Helper routine for TreeColumnList_FromObj. * * Results: * Returns TRUE if the column meets the given criteria. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Qualifies( Qualifiers *q, /* Qualifiers to check. */ TreeColumn column /* The column to test. May be NULL. */ ) { /* Note: if the column is NULL it is a "match" because we have run * out of columns to check. */ if (column == NULL) return 1; if ((q->ntail == 1) && (column == column->tree->columnTail)) return 0; if ((q->visible == 1) && !column->visible) return 0; else if ((q->visible == 0) && column->visible) return 0; if (q->exprOK && !TagExpr_Eval(&q->expr, column->tagInfo)) return 0; if ((q->lock != -1) && (column->lock != q->lock)) return 0; if ((q->tag != NULL) && !ColumnHasTag(column, q->tag)) return 0; return 1; } /* *---------------------------------------------------------------------- * * Qualifiers_Free -- * * Helper routine for TreeColumnList_FromObj. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Qualifiers_Free( Qualifiers *q /* Out: Initialized qualifiers. */ ) { if (q->exprOK) TagExpr_Free(&q->expr); } /* *---------------------------------------------------------------------- * * TreeColumnList_FromObj -- * * Parse a Tcl_Obj column description to get a list of columns. * * -- returning a single column -- * ID MODIFIERS * first QUALIFIERS MODIFIERS * end|last QUALIFIERS MODIFIERS * order N QUALIFIERS MODIFIERS * tail * tree * -- returning multiple columns -- * all QUALIFIERS * QUALIFIERS (like "all QUALIFIERS") * list listOfDescs * range first last QUALIFIERS * tag tagExpr QUALIFIERS * TAG-EXPR QUALIFIERS MODIFIERS * * MODIFIERS: * -- returning a single column -- * next QUALIFIERS * prev QUALIFIERS * span N QUALIFIERS * * QUALIFIERS: * state stateList * tag tagExpr * visible * !visible * !tail * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumnList_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *objPtr, /* Column description. */ TreeColumnList *columns, /* Uninitialized list. Caller must free * it with TreeColumnList_Free unless the * result of this function is TCL_ERROR. */ int flags /* CFO_xxx flags. */ ) { Tcl_Interp *interp = tree->interp; int i, objc, index, listIndex; Tcl_Obj **objv, *elemPtr; TreeColumn column = NULL; Qualifiers q; int qualArgsTotal; static CONST char *indexName[] = { "all", "end", "first", "last", "list", "order", "range", "tail", "tree", (char *) NULL }; enum indexEnum { INDEX_ALL, INDEX_END, INDEX_FIRST, INDEX_LAST, INDEX_LIST, INDEX_ORDER, INDEX_RANGE, INDEX_TAIL, INDEX_TREE } ; /* Number of arguments used by indexName[]. */ static int indexArgs[] = { 1, 1, 1, 1, 2, 2, 3, 1, 1 }; /* Boolean: can indexName[] be followed by 1 or more qualifiers. */ static int indexQual[] = { 1, 0, 1, 1, 0, 1, 1, 0, 0 }; static CONST char *modifiers[] = { "next", "prev", "span", (char *) NULL }; enum modEnum { TMOD_NEXT, TMOD_PREV, TMOD_SPAN }; /* Number of arguments used by modifiers[]. */ static int modArgs[] = { 1, 1, 2 }; /* Boolean: can modifiers[] be followed by 1 or more qualifiers. */ static int modQual[] = { 1, 1, 1 }; TreeColumnList_Init(tree, columns, 0); Qualifiers_Init(tree, &q); if (Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK) goto badDesc; if (objc == 0) goto badDesc; listIndex = 0; elemPtr = objv[listIndex]; if (Tcl_GetIndexFromObj(NULL, elemPtr, indexName, NULL, 0, &index) == TCL_OK) { if (objc - listIndex < indexArgs[index]) { Tcl_AppendResult(interp, "missing arguments to \"", Tcl_GetString(elemPtr), "\" keyword", NULL); goto errorExit; } qualArgsTotal = 0; if (indexQual[index]) { if (Qualifiers_Scan(&q, objc, objv, listIndex + indexArgs[index], &qualArgsTotal) != TCL_OK) { goto errorExit; } } switch ((enum indexEnum) index) { case INDEX_ALL: { if (qualArgsTotal) { column = tree->columns; while (column != NULL) { if (Qualifies(&q, column)) { TreeColumnList_Append(columns, column); } column = column->next; } if (!(flags & CFO_NOT_TAIL) && Qualifies(&q, tree->columnTail)) { TreeColumnList_Append(columns, tree->columnTail); } column = NULL; } else if (flags & CFO_LIST_ALL) { column = tree->columns; while (column != NULL) { TreeColumnList_Append(columns, column); column = column->next; } if (!(flags & CFO_NOT_TAIL)) TreeColumnList_Append(columns, tree->columnTail); column = NULL; } else if (flags & CFO_NOT_TAIL) { column = COLUMN_NTAIL; } else { column = COLUMN_ALL; } break; } case INDEX_FIRST: { column = tree->columns; while (!Qualifies(&q, column)) column = column->next; break; } case INDEX_END: case INDEX_LAST: { column = tree->columnLast; while (!Qualifies(&q, column)) { column = column->prev; } break; } case INDEX_LIST: { int listObjc; Tcl_Obj **listObjv; int count; if (Tcl_ListObjGetElements(interp, objv[listIndex + 1], &listObjc, &listObjv) != TCL_OK) goto errorExit; for (i = 0; i < listObjc; i++) { TreeColumnList column2s; if (TreeColumnList_FromObj(tree, listObjv[i], &column2s, flags) != TCL_OK) goto errorExit; TreeColumnList_Concat(columns, &column2s); TreeColumnList_Free(&column2s); } /* If any of the column descriptions in the list is "all", then * clear the list of columns and use "all". */ count = TreeColumnList_Count(columns); for (i = 0; i < count; i++) { TreeColumn column = TreeColumnList_Nth(columns, i); if (IS_ALL(column)) break; } if (i < count) { TreeColumnList_Free(columns); if (flags & CFO_NOT_TAIL) column = COLUMN_NTAIL; else column = COLUMN_ALL; } else column = NULL; break; } case INDEX_ORDER: { int order; if (Tcl_GetIntFromObj(NULL, objv[listIndex + 1], &order) != TCL_OK) goto errorExit; column = tree->columns; while (column != NULL) { if (Qualifies(&q, column)) if (order-- <= 0) break; column = column->next; } break; } case INDEX_RANGE: { TreeColumn _first, _last; if (TreeColumn_FromObj(tree, objv[listIndex + 1], &_first, CFO_NOT_NULL) != TCL_OK) goto errorExit; if (TreeColumn_FromObj(tree, objv[listIndex + 2], &_last, CFO_NOT_NULL) != TCL_OK) goto errorExit; (void) TreeColumn_FirstAndLast(&_first, &_last); column = _first; while (1) { if (Qualifies(&q, column)) { TreeColumnList_Append(columns, column); } if (column == _last) break; column = column->next; if (column == NULL) column = tree->columnTail; } column = NULL; break; } case INDEX_TAIL: { column = tree->columnTail; break; } case INDEX_TREE: { column = tree->columnTree; break; } } listIndex += indexArgs[index] + qualArgsTotal; /* No indexName[] was found. */ } else { int gotId = FALSE, id; TagExpr expr; if (tree->columnPrefixLen) { char *end, *t = Tcl_GetString(elemPtr); if (strncmp(t, tree->columnPrefix, tree->columnPrefixLen) == 0) { t += tree->columnPrefixLen; id = strtoul(t, &end, 10); if ((end != t) && (*end == '\0')) gotId = TRUE; } } else if (Tcl_GetIntFromObj(NULL, elemPtr, &id) == TCL_OK) { gotId = TRUE; } if (gotId) { column = tree->columns; while (column) { if (column->id == id) break; column = column->next; } listIndex++; goto gotFirstPart; } /* Try a list of qualifiers. This has the same effect as * "all QUALIFIERS". */ if (Qualifiers_Scan(&q, objc, objv, listIndex, &qualArgsTotal) != TCL_OK) { goto errorExit; } if (qualArgsTotal) { column = tree->columns; while (column != NULL) { if (Qualifies(&q, column)) { TreeColumnList_Append(columns, column); } column = column->next; } if (!(flags & CFO_NOT_TAIL) && Qualifies(&q, tree->columnTail)) { TreeColumnList_Append(columns, tree->columnTail); } column = NULL; listIndex += qualArgsTotal; goto gotFirstPart; } /* Try a tag or tag expression followed by qualifiers. */ if (objc > 1) { if (Qualifiers_Scan(&q, objc, objv, listIndex + 1, &qualArgsTotal) != TCL_OK) { goto errorExit; } } if (tree->columnTagExpr) { if (TagExpr_Init(tree, elemPtr, &expr) != TCL_OK) goto errorExit; column = tree->columns; while (column != NULL) { if (TagExpr_Eval(&expr, column->tagInfo) && Qualifies(&q, column)) { TreeColumnList_Append(columns, column); } column = column->next; } if (!(flags & CFO_NOT_TAIL) && TagExpr_Eval(&expr, tree->columnTail->tagInfo) && Qualifies(&q, tree->columnTail)) { TreeColumnList_Append(columns, tree->columnTail); } TagExpr_Free(&expr); } else { Tk_Uid tag = Tk_GetUid(Tcl_GetString(elemPtr)); column = tree->columns; while (column != NULL) { if (ColumnHasTag(column, tag) && Qualifies(&q, column)) { TreeColumnList_Append(columns, column); } column = column->next; } if (!(flags & CFO_NOT_TAIL) && ColumnHasTag(tree->columnTail, tag) && Qualifies(&q, tree->columnTail)) { TreeColumnList_Append(columns, tree->columnTail); } } column = NULL; listIndex += 1 + qualArgsTotal; } gotFirstPart: /* If 1 column, use it and clear the list. */ if (TreeColumnList_Count(columns) == 1) { column = TreeColumnList_Nth(columns, 0); columns->count = 0; } /* If "all" but only tail column exists, use it. */ if (IS_ALL(column) && (tree->columns == NULL) && !(flags & CFO_NOT_TAIL)) column = tree->columnTail; /* If > 1 column, no modifiers may follow. */ if ((TreeColumnList_Count(columns) > 1) || IS_ALL(column)) { if (listIndex < objc) { Tcl_AppendResult(interp, "unexpected arguments after \"", (char *) NULL); for (i = 0; i < listIndex; i++) { Tcl_AppendResult(interp, Tcl_GetString(objv[i]), (char *) NULL); if (i != listIndex - 1) Tcl_AppendResult(interp, " ", (char *) NULL); } Tcl_AppendResult(interp, "\"", (char *) NULL); goto errorExit; } } /* This means a valid specification was given, but there is no such column */ if ((TreeColumnList_Count(columns) == 0) && (column == NULL)) { if (flags & CFO_NOT_NULL) goto notNull; /* Empty list returned */ goto goodExit; } /* Process any modifiers following the column we matched above. */ for (; listIndex < objc; /* nothing */) { int qualArgsTotal = 0; elemPtr = objv[listIndex]; if (Tcl_GetIndexFromObj(interp, elemPtr, modifiers, "modifier", 0, &index) != TCL_OK) { goto errorExit; } if (objc - listIndex < modArgs[index]) { Tcl_AppendResult(interp, "missing arguments to \"", Tcl_GetString(elemPtr), "\" modifier", NULL); goto errorExit; } if (modQual[index]) { Qualifiers_Free(&q); Qualifiers_Init(tree, &q); if (Qualifiers_Scan(&q, objc, objv, listIndex + modArgs[index], &qualArgsTotal) != TCL_OK) { goto errorExit; } } switch ((enum modEnum) index) { case TMOD_NEXT: { int isTail = IS_TAIL(column); if (isTail) { column = NULL; break; } column = column->next; while (!Qualifies(&q, column)) column = column->next; if (column == NULL) { column = tree->columnTail; if (!Qualifies(&q, column)) column = NULL; } break; } case TMOD_PREV: { int isTail = IS_TAIL(column); if (isTail) column = tree->columnLast; else column = column->prev; while (!Qualifies(&q, column)) column = column->prev; break; } case TMOD_SPAN: { int span, lock; TreeColumn match = NULL; if (Tcl_GetIntFromObj(NULL, objv[listIndex + 1], &span) != TCL_OK) goto errorExit; lock = column->lock; while (span-- > 0 && column != NULL && column->lock == lock) { if (!Qualifies(&q, column)) break; match = column; column = column->next; } column = match; break; } } if ((TreeColumnList_Count(columns) == 0) && (column == NULL)) { if (flags & CFO_NOT_NULL) goto notNull; /* Empty list returned. */ goto goodExit; } listIndex += modArgs[index] + qualArgsTotal; } if ((flags & CFO_NOT_MANY) && (IS_ALL(column) || (TreeColumnList_Count(columns) > 1))) { FormatResult(interp, "can't specify > 1 column for this command"); goto errorExit; } if ((flags & CFO_NOT_NULL) && (TreeColumnList_Count(columns) == 0) && (column == NULL)) { notNull: FormatResult(interp, "column \"%s\" doesn't exist", Tcl_GetString(objPtr)); goto errorExit; } if (TreeColumnList_Count(columns)) { if (flags & (CFO_NOT_TAIL)) { int i; for (i = 0; i < TreeColumnList_Count(columns); i++) { column = TreeColumnList_Nth(columns, i); if ((flags & CFO_NOT_TAIL) && IS_TAIL(column)) goto notTail; } } } else if (IS_ALL(column)) { TreeColumnList_Append(columns, column); } else { if ((flags & CFO_NOT_TAIL) && IS_TAIL(column)) { notTail: FormatResult(interp, "can't specify \"tail\" for this command"); goto errorExit; } TreeColumnList_Append(columns, column); } goodExit: Qualifiers_Free(&q); return TCL_OK; badDesc: FormatResult(interp, "bad column description \"%s\"", Tcl_GetString(objPtr)); goto errorExit; errorExit: Qualifiers_Free(&q); TreeColumnList_Free(columns); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeColumn_FromObj -- * * Parse a Tcl_Obj column description to get a single column. * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *objPtr, /* Object to parse to a column. */ TreeColumn *columnPtr, /* Returned column. */ int flags /* CFO_xxx flags */ ) { TreeColumnList columns; if (TreeColumnList_FromObj(tree, objPtr, &columns, flags | CFO_NOT_MANY) != TCL_OK) return TCL_ERROR; /* May be NULL. */ (*columnPtr) = TreeColumnList_Nth(&columns, 0); TreeColumnList_Free(&columns); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeColumnForEach_Start -- * * Begin iterating over items. A command might accept two column * descriptions for a range of column, or a single column description * which may itself refer to multiple column. Either column * description could be "all". * * Results: * Returns the first column to iterate over. If an error occurs * then ColumnForEach.error is set to 1. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeColumn TreeColumnForEach_Start( TreeColumnList *columns, /* List of columns. */ TreeColumnList *column2s, /* List of columns or NULL. */ ColumnForEach *iter /* Returned info, pass to TreeColumnForEach_Next. */ ) { TreeCtrl *tree = columns->tree; TreeColumn column, column2 = NULL; column = TreeColumnList_Nth(columns, 0); if (column2s) column2 = TreeColumnList_Nth(column2s, 0); iter->tree = tree; iter->all = FALSE; iter->ntail = FALSE; iter->error = 0; iter->list = NULL; if (IS_ALL(column) || IS_ALL(column2)) { iter->all = TRUE; iter->ntail = (column == COLUMN_NTAIL) || (column2 == COLUMN_NTAIL); if (tree->columns == NULL) return iter->current = iter->ntail ? NULL : tree->columnTail; iter->next = TreeColumn_Next(tree->columns); return iter->current = tree->columns; } if (column2 != NULL) { if (TreeColumn_FirstAndLast(&column, &column2) == 0) { iter->error = 1; return NULL; } iter->next = TreeColumn_Next(column); iter->last = column2; return iter->current = column; } iter->list = columns; iter->index = 0; return iter->current = column; } /* *---------------------------------------------------------------------- * * TreeColumnForEach_Next -- * * Returns the next column to iterate over. Keep calling this until * the result is NULL. * * Results: * Returns the next column to iterate over or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeColumn TreeColumnForEach_Next( ColumnForEach *iter /* Initialized by TreeColumnForEach_Start. */ ) { TreeCtrl *tree = iter->tree; TreeColumn column; if (iter->all) { if (iter->current == tree->columnTail) return iter->current = NULL; column = iter->next; if (column == NULL) return iter->current = iter->ntail ? NULL : tree->columnTail; iter->next = TreeColumn_Next(column); return iter->current = column; } if (iter->list != NULL) { if (iter->index >= TreeColumnList_Count(iter->list)) return iter->current = NULL; return iter->current = TreeColumnList_Nth(iter->list, ++iter->index); } if (iter->current == iter->last) return iter->current = NULL; column = iter->next; iter->next = TreeColumn_Next(column); return iter->current = column; } /* *---------------------------------------------------------------------- * * TreeColumn_ToObj -- * * Return a Tcl_Obj representing a column. * * Results: * A Tcl_Obj. * * Side effects: * Allocates a Tcl_Obj. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeColumn_ToObj( TreeCtrl *tree, /* Widget info. */ TreeColumn column /* Column token to get Tcl_Obj for. */ ) { if (column == tree->columnTail) return Tcl_NewStringObj("tail", -1); if (tree->columnPrefixLen) { char buf[100 + TCL_INTEGER_SPACE]; (void) sprintf(buf, "%s%d", tree->columnPrefix, column->id); return Tcl_NewStringObj(buf, -1); } return Tcl_NewIntObj(column->id); } /* *---------------------------------------------------------------------- * * Tree_FindColumn -- * * Get the N'th column in a TreeCtrl. * * Results: * Token for the N'th column. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeColumn Tree_FindColumn( TreeCtrl *tree, /* Widget info. */ int columnIndex /* 0-based index of the column to return. */ ) { TreeColumn column = tree->columns; if (columnIndex == tree->columnTail->index) return tree->columnTail; while (column != NULL) { if (column->index == columnIndex) break; column = column->next; } return column; } TreeColumn Tree_FirstColumn( TreeCtrl *tree, int lock, int tailOK ) { TreeColumn column = NULL; switch (lock) { case COLUMN_LOCK_LEFT: column = tree->columnLockLeft; break; case COLUMN_LOCK_NONE: column = tree->columnLockNone; if (column == NULL && tailOK) column = tree->columnTail; break; case COLUMN_LOCK_RIGHT: column = tree->columnLockRight; break; default: column = tree->columns; if (column == NULL && tailOK) column = tree->columnTail; break; } return column; } TreeColumn Tree_ColumnToTheRight( TreeColumn column, /* Column token. */ int displayOrder, int tailOK ) { TreeCtrl *tree = column->tree; TreeColumn next = column->next; if (column == tree->columnTail) tailOK = FALSE; if (displayOrder && next == tree->columnLockRight) { return tailOK ? tree->columnTail : NULL; } if (next == NULL && tailOK) return tree->columnTail; return next; } /* *---------------------------------------------------------------------- * * TreeColumn_Next -- * * Return the column to the right of the given one. * * Results: * Token for the next column. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeColumn TreeColumn_Next( TreeColumn column /* Column token. */ ) { return column->next; } /* *---------------------------------------------------------------------- * * TreeColumn_Prev -- * * Return the column to the left of the given one. * * Results: * Token for the previous column. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeColumn TreeColumn_Prev( TreeColumn column /* Column token. */ ) { return column->prev; } /* *---------------------------------------------------------------------- * * Column_FreeColors -- * * Frees an array of XColors. This is used to free the -itembackground * array of colors. * * Results: * None. * * Side effects: * Memory is deallocated, colors are freed. * *---------------------------------------------------------------------- */ static void Column_FreeColors( TreeColumn column, /* Column token. */ TreeColor **colors, /* Array of colors. May be NULL. */ int count /* Number of colors. */ ) { int i; if (colors == NULL) { return; } for (i = 0; i < count; i++) { if (colors[i] != NULL) { Tree_FreeColor(column->tree, colors[i]); } } WCFREE(colors, XColor *, count); } /* *---------------------------------------------------------------------- * * Column_Move -- * * Move a column before another. * * Results: * If the column is moved, then the list of item-columns for every item * is rearranged and the treectrl option -defaultstyles is rearranged. * Whether the column is moved or not, the .index field of every * column is recalculated. * * Side effects: * A redisplay is scheduled if the moved column is visible. * *---------------------------------------------------------------------- */ static void Column_Move( TreeColumn move, /* Column to move. */ TreeColumn before /* Column to place 'move' in front of. * May be the same as 'move'. */ ) { TreeCtrl *tree = move->tree; TreeColumn column, prev, next, last; Tcl_HashEntry *hPtr; Tcl_HashSearch search; TreeItem item; int index; #ifdef DEPRECATED int numStyles; #endif if (move == before) goto renumber; if (move->index == before->index - 1) goto renumber; /* Move the column in every header */ item = tree->headerItems; while (item != NULL) { TreeItem_MoveColumn(tree, item, move->index, before->index); item = TreeItem_GetNextSibling(tree, item); } /* Move the column in every item */ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); TreeItem_MoveColumn(tree, item, move->index, before->index); hPtr = Tcl_NextHashEntry(&search); } /* Indicate that all items must recalculate their list of spans. */ TreeItem_SpansInvalidate(tree, NULL); #ifdef DEPRECATED /* Re-order -defaultstyle */ numStyles = tree->defaultStyle.numStyles; if ((numStyles > 0) && ((before->index < numStyles) || (move->index < numStyles))) { TreeStyle style, *styles; int i, j; Tcl_Obj *staticObjv[STATIC_SIZE], **objv = staticObjv; /* Case 1: move existing */ if ((before->index <= numStyles) && (move->index < numStyles)) { styles = tree->defaultStyle.styles; style = styles[move->index]; for (i = move->index; i < numStyles - 1; i++) styles[i] = styles[i + 1]; j = before->index; if (move->index < before->index) j--; for (i = numStyles - 1; i > j; i--) styles[i] = styles[i - 1]; styles[j] = style; /* Case 2: insert empty between existing */ } else if (before->index < numStyles) { numStyles++; styles = (TreeStyle *) ckalloc(numStyles * sizeof(TreeStyle)); for (i = 0; i < before->index; i++) styles[i] = tree->defaultStyle.styles[i]; styles[i++] = NULL; for (; i < numStyles; i++) styles[i] = tree->defaultStyle.styles[i - 1]; /* Case 3: move existing past end */ } else { numStyles += before->index - numStyles; styles = (TreeStyle *) ckalloc(numStyles * sizeof(TreeStyle)); style = tree->defaultStyle.styles[move->index]; for (i = 0; i < move->index; i++) styles[i] = tree->defaultStyle.styles[i]; for (; i < tree->defaultStyle.numStyles - 1; i++) styles[i] = tree->defaultStyle.styles[i + 1]; for (; i < numStyles - 1; i++) styles[i] = NULL; styles[i] = style; } Tcl_DecrRefCount(tree->defaultStyle.stylesObj); STATIC_ALLOC(objv, Tcl_Obj *, numStyles); for (i = 0; i < numStyles; i++) { if (styles[i] != NULL) objv[i] = TreeStyle_ToObj(styles[i]); else objv[i] = Tcl_NewObj(); } tree->defaultStyle.stylesObj = Tcl_NewListObj(numStyles, objv); Tcl_IncrRefCount(tree->defaultStyle.stylesObj); STATIC_FREE(objv, Tcl_Obj *, numStyles); if (styles != tree->defaultStyle.styles) { ckfree((char *) tree->defaultStyle.styles); tree->defaultStyle.styles = styles; tree->defaultStyle.numStyles = numStyles; } } #endif /* DEPRECATED */ /* Unlink. */ prev = move->prev; next = move->next; if (prev == NULL) tree->columns = next; else prev->next = next; if (next == NULL) tree->columnLast = prev; else next->prev = prev; /* Link. */ if (before == tree->columnTail) { last = tree->columnLast; last->next = move; move->prev = last; move->next = NULL; tree->columnLast = move; } else { prev = before->prev; if (prev == NULL) tree->columns = move; else prev->next = move; before->prev = move; move->prev = prev; move->next = before; } /* Renumber columns */ renumber: tree->columnLockLeft = NULL; tree->columnLockNone = NULL; tree->columnLockRight = NULL; index = 0; column = tree->columns; while (column != NULL) { column->index = index++; if (column->lock == COLUMN_LOCK_LEFT && tree->columnLockLeft == NULL) tree->columnLockLeft = column; if (column->lock == COLUMN_LOCK_NONE && tree->columnLockNone == NULL) tree->columnLockNone = column; if (column->lock == COLUMN_LOCK_RIGHT && tree->columnLockRight == NULL) tree->columnLockRight = column; column = column->next; } if (move->visible) { /* Must update column widths because of expansion. */ /* Also update columnTreeLeft. */ TreeColumns_InvalidateWidth(tree); TreeColumns_InvalidateCounts(tree); } } /* *---------------------------------------------------------------------- * * Column_Config -- * * This procedure is called to process an objc/objv list to set * configuration options for a Column. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then an error message is left in interp's result. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for column; old resources get freed, if there * were any. Display changes may occur. * *---------------------------------------------------------------------- */ static int Column_Config( TreeColumn column, /* Column record. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int createFlag /* TRUE if the Column is being created. */ ) { TreeCtrl *tree = column->tree; TreeColumn_ saved; TreeColumn walk; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; int mask, maskFree = 0; int visible = column->visible; int lock = column->lock; #if COLUMNGRID == 1 int gridLines, prevGridLines = visible && (column->gridLeftColor != NULL || column->gridRightColor != NULL); #endif int objC = 0, hObjC = 0; Tcl_Obj *staticObjV[STATIC_SIZE], **objV = staticObjV; Tcl_Obj *staticHObjV[STATIC_SIZE], **hObjV = staticHObjV; int i; /* Hack -- Pass some options to the underlying header-column */ STATIC_ALLOC(objV, Tcl_Obj *, objc); STATIC_ALLOC(hObjV, Tcl_Obj *, objc); for (i = 0; i < objc; i += 2) { Tk_OptionSpec *specPtr = columnSpecs; int length; CONST char *optionName = Tcl_GetStringFromObj(objv[i], &length); while (specPtr->type != TK_OPTION_END) { if (strncmp(specPtr->optionName, optionName, length) == 0) { objV[objC++] = objv[i]; if (i + 1 < objc) objV[objC++] = objv[i + 1]; /* Pass -justify to the default header as well */ if (strcmp(specPtr->optionName, "-justify") == 0) { hObjV[hObjC++] = objv[i]; if (i + 1 < objc) hObjV[hObjC++] = objv[i + 1]; } break; } specPtr++; } if (specPtr->type == TK_OPTION_END) { hObjV[hObjC++] = objv[i]; if (i + 1 < objc) hObjV[hObjC++] = objv[i + 1]; } } if (TreeHeader_ConsumeColumnConfig(tree, column, hObjC, hObjV, createFlag) != TCL_OK) { STATIC_FREE(objV, Tcl_Obj *, objc); STATIC_FREE(hObjV, Tcl_Obj *, objc); return TCL_ERROR; } /* Init these to prevent compiler warnings */ saved.itemBgCount = 0; saved.itemBgColor = NULL; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tk_SetOptions(tree->interp, (char *) column, column->optionTable, objC, objV, tree->tkwin, &savedOptions, &mask) != TCL_OK) { mask = 0; continue; } /* Wouldn't have to do this if Tk_InitOptions() would return * a mask of configured options like Tk_SetOptions() does. */ if (createFlag) { if (column->itemBgObj != NULL) mask |= COLU_CONF_ITEMBG; } /* * Step 1: Save old values */ if (mask & COLU_CONF_ITEMBG) { saved.itemBgColor = column->itemBgColor; saved.itemBgCount = column->itemBgCount; } if (column == tree->columnTail) { if (column->itemStyle != NULL) { FormatResult(tree->interp, "can't change the -itemstyle option of the tail column"); continue; } if (column->lock != COLUMN_LOCK_NONE) { FormatResult(tree->interp, "can't change the -lock option of the tail column"); continue; } } /* * Step 2: Process new values */ if (mask & COLU_CONF_ITEMBG) { if (column->itemBgObj == NULL) { column->itemBgColor = NULL; column->itemBgCount = 0; } else { int i, length, listObjc; Tcl_Obj **listObjv; TreeColor **colors; if (Tcl_ListObjGetElements(tree->interp, column->itemBgObj, &listObjc, &listObjv) != TCL_OK) continue; colors = (TreeColor **) ckalloc(sizeof(TreeColor *) * listObjc); for (i = 0; i < listObjc; i++) colors[i] = NULL; for (i = 0; i < listObjc; i++) { /* Can specify "" for tree background */ (void) Tcl_GetStringFromObj(listObjv[i], &length); if (length != 0) { colors[i] = Tree_AllocColorFromObj(tree, listObjv[i]); if (colors[i] == NULL) break; } } if (i < listObjc) { Column_FreeColors(column, colors, listObjc); continue; } column->itemBgColor = colors; column->itemBgCount = listObjc; maskFree |= COLU_CONF_ITEMBG; } } /* * Step 3: Free saved values */ if (mask & COLU_CONF_ITEMBG) Column_FreeColors(column, saved.itemBgColor, saved.itemBgCount); Tk_FreeSavedOptions(&savedOptions); STATIC_FREE(objV, Tcl_Obj *, objc); STATIC_FREE(hObjV, Tcl_Obj *, objc); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); /* * Free new values. */ if (maskFree & COLU_CONF_ITEMBG) Column_FreeColors(column, column->itemBgColor, column->itemBgCount); /* * Restore old values. */ if (mask & COLU_CONF_ITEMBG) { column->itemBgColor = saved.itemBgColor; column->itemBgCount = saved.itemBgCount; } Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); STATIC_FREE(objV, Tcl_Obj *, objc); STATIC_FREE(hObjV, Tcl_Obj *, objc); return TCL_ERROR; } } /* Indicate that all items must recalculate their list of spans. */ if (visible != column->visible || lock != column->lock) TreeItem_SpansInvalidate(tree, NULL); if (visible != column->visible || lock != column->lock) TreeColumns_InvalidateCounts(tree); if (mask & COLU_CONF_ITEMBG) { if (!createFlag) { /* Set max -itembackground */ tree->columnBgCnt = 0; walk = tree->columns; while (walk != NULL) { if (walk->visible) { if (walk->itemBgCount > tree->columnBgCnt) tree->columnBgCnt = walk->itemBgCount; } walk = walk->next; } } Tree_DInfoChanged(tree, DINFO_INVALIDATE); /* implicit DINFO_DRAW_WHITESPACE */ } if (!createFlag && (column->lock != lock)) { TreeColumn before = NULL; switch (column->lock) { case COLUMN_LOCK_LEFT: before = tree->columnLockNone; if (before == NULL) before = tree->columnLockRight; break; case COLUMN_LOCK_NONE: if (lock == COLUMN_LOCK_LEFT) { before = tree->columnLockNone; if (before == NULL) before = tree->columnLockRight; } else before = tree->columnLockRight; break; case COLUMN_LOCK_RIGHT: before = NULL; break; } if (before == NULL) before = tree->columnTail; Column_Move(column, before); Tree_DInfoChanged(tree, DINFO_REDO_COLUMN_WIDTH); } /* If there are no more visible columns, the header isn't shown. */ /* Header height may change with the width of columns (due to text wrapping). */ if (mask & COLU_CONF_TWIDTH) { tree->headerHeight = -1; } /* FIXME: only this column needs to be redisplayed. */ if (mask & COLU_CONF_JUSTIFY) Tree_DInfoChanged(tree, DINFO_INVALIDATE); #ifdef DEPRECATED /* -stepwidth and -widthhack */ if (mask & COLU_CONF_RANGES) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); #endif /* Redraw everything */ if (mask & COLU_CONF_TWIDTH) { if ((column->reqData.spanMin != NULL) && /* if it's NULL, then it's hidden or tree->spansInvalid=TRUE */ (column->reqData.spanMin != column->reqData.spanMax)) { /* spans of 1 don't require item-width recalc */ TreeColumns_InvalidateWidthOfItems(tree, column); } TreeColumns_InvalidateWidth(tree); Tree_DInfoChanged(tree, DINFO_DRAW_HEADER); } /* Redraw header only */ else if (mask & COLU_CONF_DISPLAY) { Tree_DInfoChanged(tree, DINFO_DRAW_HEADER); } #if COLUMNGRID == 1 if (mask & COLU_CONF_GRIDLINES) { Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_DRAW_WHITESPACE); } gridLines = column->visible && (column->gridLeftColor != NULL || column->gridRightColor != NULL); if (gridLines != prevGridLines) { tree->columnsWithGridLines += gridLines ? 1 : -1; /*dbwin("tree->columnsWithGridLines is now %d", tree->columnsWithGridLines);*/ } #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * Column_Alloc -- * * Allocate and initialize a new Column record. * * Results: * Pointer to the new Column, or NULL if errors occurred. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ static TreeColumn Column_Alloc( TreeCtrl *tree /* Widget info. */ ) { TreeColumn column; column = (TreeColumn) ckalloc(sizeof(TreeColumn_)); memset(column, '\0', sizeof(TreeColumn_)); column->tree = tree; column->optionTable = Tk_CreateOptionTable(tree->interp, columnSpecs); column->itemJustify = -1; if (Tk_InitOptions(tree->interp, (char *) column, column->optionTable, tree->tkwin) != TCL_OK) { WFREE(column, TreeColumn_); return NULL; } #if 0 if (Tk_SetOptions(header->tree->interp, (char *) column, column->optionTable, 0, NULL, header->tree->tkwin, &savedOptions, (int *) NULL) != TCL_OK) { WFREE(column, TreeColumn_); return NULL; } #endif tree->headerHeight = -1; /* Don't call TreeColumns_InvalidateWidth(), it will fail during * Tree_InitColumns(). */ tree->widthOfColumns = -1; tree->widthOfColumnsLeft = tree->widthOfColumnsRight = -1; column->id = tree->nextColumnId++; tree->columnCount++; return column; } /* *---------------------------------------------------------------------- * * Column_Free -- * * Free a Column. * * Results: * Pointer to the next column. * * Side effects: * Memory is deallocated. If this is the last column being * deleted, the TreeCtrl.nextColumnId field is reset to zero. * *---------------------------------------------------------------------- */ static TreeColumn Column_Free( TreeColumn column /* Column record. */ ) { TreeCtrl *tree = column->tree; TreeColumn next = column->next; Column_FreeColors(column, column->itemBgColor, column->itemBgCount); TreeDisplay_FreeColumnDInfo(tree, column); Tk_FreeConfigOptions((char *) column, column->optionTable, tree->tkwin); if (column->reqData.spans.spans != NULL) ckfree((char *) column->reqData.spans.spans); WFREE(column, TreeColumn_); tree->columnCount--; if (tree->columnCount == 0) tree->nextColumnId = 0; return next; } /* *---------------------------------------------------------------------- * * TreeColumn_SetDInfo -- * * Store a display-info token in a column. Called by the display * code. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeColumn_SetDInfo( TreeColumn column, /* Column record. */ TreeColumnDInfo dInfo /* Display info token. */ ) { column->dInfo = dInfo; } /* *---------------------------------------------------------------------- * * TreeColumn_GetDInfo -- * * Return the display-info token of a column. Called by the display * code. * * Results: * The display-info token or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeColumnDInfo TreeColumn_GetDInfo( TreeColumn column /* Column record. */ ) { return column->dInfo; } /* *---------------------------------------------------------------------- * * TreeColumn_FixedWidth -- * * Return the value of the -width option. * * Results: * The pixel width or -1 if the -width option is unspecified. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_FixedWidth( TreeColumn column /* Column token. */ ) { return column->widthObj ? column->width : -1; } /* *---------------------------------------------------------------------- * * TreeColumn_MinWidth -- * * Return the value of the -minwidth option. * * Results: * The pixel width or -1 if the -minwidth option is unspecified. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_MinWidth( TreeColumn column /* Column token. */ ) { return column->minWidthObj ? column->minWidth : -1; } /* *---------------------------------------------------------------------- * * TreeColumn_MaxWidth -- * * Return the value of the -maxwidth option. * * Results: * The pixel width or -1 if the -maxwidth option is unspecified. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_MaxWidth( TreeColumn column /* Column token. */ ) { return column->maxWidthObj ? column->maxWidth : -1; } #ifdef DEPRECATED /* *---------------------------------------------------------------------- * * TreeColumn_StepWidth -- * * Return the value of the -stepwidth option. * NOTE: -stepwidth is deprecated. * * Results: * The pixel width or -1 if the -stepwidth option is unspecified. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_StepWidth( TreeColumn column /* Column token. */ ) { return column->stepWidthObj ? column->stepWidth : -1; } #endif /* DEPRECATED */ /* *---------------------------------------------------------------------- * * TreeColumn_UseWidth -- * * Return the actual display width of a column. * * Results: * Pixel width. * * Side effects: * The size of any column that is marked out-of-date is * recalculated. This could involve recalculating the size of * every element and style in the column in all items. * *---------------------------------------------------------------------- */ int TreeColumn_UseWidth( TreeColumn column /* Column token. */ ) { /* Update layout if needed */ (void) Tree_WidthOfColumns(column->tree); return column->useWidth; } /* *---------------------------------------------------------------------- * * TreeColumn_Offset -- * * Return the x-offset of a column. * * Results: * Pixel offset. * * Side effects: * Column layout is updated if needed. * *---------------------------------------------------------------------- */ int TreeColumn_Offset( TreeColumn column /* Column token. */ ) { /* Update layout if needed */ (void) Tree_WidthOfColumns(column->tree); return column->offset; } /* *---------------------------------------------------------------------- * * TreeColumn_ItemJustify -- * * Return the value of the -itemjustify config option for a column. * If -itemjustify is unspecified, then return the value of the * -justify option. * * Results: * TK_JUSTIFY_xxx constant. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tk_Justify TreeColumn_ItemJustify( TreeColumn column /* Column token. */ ) { return (column->itemJustify != -1) ? column->itemJustify : column->justify; } #ifdef DEPRECATED /* *---------------------------------------------------------------------- * * TreeColumn_WidthHack -- * * Return the value of the -widthhack config option for a column. * NOTE: -widthhack is deprecated. * * Results: * Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_WidthHack( TreeColumn column /* Column token. */ ) { return column->widthHack; } #endif /* DEPRECATED */ /* *---------------------------------------------------------------------- * * TreeColumn_Squeeze -- * * Return the value of the -squeeze config option for a column. * * Results: * Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_Squeeze( TreeColumn column /* Column token. */ ) { return column->squeeze; } /* *---------------------------------------------------------------------- * * TreeColumn_BackgroundCount -- * * Return the number of -itembackground colors for a column. * * Results: * column->itemBgCount. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_BackgroundCount( TreeColumn column /* Column token. */ ) { return column->itemBgCount; } /* *---------------------------------------------------------------------- * * TreeColumn_BackgroundColor -- * * Return a TreeColor for one color of the -itembackground * config option for a column. * * Results: * A TreeColor, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeColor * TreeColumn_BackgroundColor( TreeColumn column, /* Column token. */ int index /* This number is determined by the display * code. */ ) { if ((index < 0) || (column->itemBgCount == 0)) return NULL; return column->itemBgColor[index % column->itemBgCount]; } #if COLUMNGRID == 1 /* *---------------------------------------------------------------------- * * TreeColumn_GridColors -- * * Returns the color and width for this column's gridlines. * * Results: * Returns the left and right colors and their widths. Either * color may be NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_GridColors( TreeColumn column, /* Column token. */ TreeColor **leftColorPtr, /* Returned left color. */ TreeColor **rightColorPtr, /* Returned right color. */ int *leftWidthPtr, int *rightWidthPtr ) { (*leftColorPtr) = column->gridLeftColor; (*rightColorPtr) = column->gridRightColor; (*leftWidthPtr) = 1; (*rightWidthPtr) = 1; return (*leftColorPtr != NULL && *leftWidthPtr > 0) || (*rightColorPtr != NULL && *rightWidthPtr > 0); } #endif /* *---------------------------------------------------------------------- * * TreeColumn_ItemStyle -- * * Return the value of the -itemstyle config option for a column. * * Results: * TreeStyle or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeStyle TreeColumn_ItemStyle( TreeColumn column /* Column token. */ ) { return column->itemStyle; } /* *---------------------------------------------------------------------- * * TreeColumn_StyleDeleted -- * * Called when a master style is deleted. * * Results: * Clear the column's -itemstyle option if it is the style being * deleted. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeColumn_StyleDeleted( TreeColumn column, /* Column token. */ TreeStyle style /* Style that was deleted. */ ) { if (column->itemStyle == style) column->itemStyle = NULL; } /* *---------------------------------------------------------------------- * * TreeColumn_Visible -- * * Return the value of the -visible config option for a column. * * Results: * Boolean value. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_Visible( TreeColumn column /* Column token. */ ) { return column->visible; } /* *---------------------------------------------------------------------- * * TreeColumn_GetID -- * * Return the unique identifier for a column. * * Results: * Unique integer id. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_GetID( TreeColumn column /* Column token. */ ) { return column->id; } /* *---------------------------------------------------------------------- * * TreeColumn_Lock -- * * Return the value of the -lock option for a column. * * Results: * One of the COLUMN_LOCK_xxx constants. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_Lock( TreeColumn column /* Column token. */ ) { return column->lock; } /* *---------------------------------------------------------------------- * * TreeColumn_Index -- * * Return the 0-based index for a column. * * Results: * Position of the column in the list of columns. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_Index( TreeColumn column /* Column token. */ ) { return column->index; } /* *---------------------------------------------------------------------- * * TreeColumn_VisIndex -- * * Return the 0-based index for a column. * * Results: * Position of the column in the list of visible columns. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_VisIndex( TreeColumn column /* Column token. */ ) { TreeCtrl *tree = column->tree; TreeColumn walk = Tree_FirstColumn(tree, column->lock, TRUE); int index = 0; /* FIXME: slow, this is only used by headers in TreeItem_Indent. */ /* I can't calculate this in LayoutColumns because TreeItem_Indent is * used during that procedure. */ if (!column->visible) return -1; while (walk != column) { if (walk->visible) { /* I only care about the first non-locked visible column (index==0).*/ return 1; index++; } walk = Tree_ColumnToTheRight(walk, TRUE, TRUE); } return index; } /* *---------------------------------------------------------------------- * * ColumnTagCmd -- * * This procedure is invoked to process the [column tag] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int ColumnTagCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; static CONST char *commandNames[] = { "add", "expr", "names", "remove", (char *) NULL }; enum { COMMAND_ADD, COMMAND_EXPR, COMMAND_NAMES, COMMAND_REMOVE }; int index; ColumnForEach iter; TreeColumnList columns; TreeColumn column; int result = TCL_OK; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[3], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { /* T column tag add C tagList */ case COMMAND_ADD: { int i, numTags; Tcl_Obj **listObjv; Tk_Uid staticTags[STATIC_SIZE], *tags = staticTags; if (objc != 6) { Tcl_WrongNumArgs(interp, 4, objv, "column tagList"); return TCL_ERROR; } if (TreeColumnList_FromObj(tree, objv[4], &columns, 0) != TCL_OK) { return TCL_ERROR; } if (Tcl_ListObjGetElements(interp, objv[5], &numTags, &listObjv) != TCL_OK) { result = TCL_ERROR; break; } STATIC_ALLOC(tags, Tk_Uid, numTags); for (i = 0; i < numTags; i++) { tags[i] = Tk_GetUid(Tcl_GetString(listObjv[i])); } COLUMN_FOR_EACH(column, &columns, NULL, &iter) { column->tagInfo = TagInfo_Add(tree, column->tagInfo, tags, numTags); } STATIC_FREE(tags, Tk_Uid, numTags); break; } /* T column tag expr C tagExpr */ case COMMAND_EXPR: { TagExpr expr; int ok = TRUE; if (objc != 6) { Tcl_WrongNumArgs(interp, 4, objv, "column tagExpr"); return TCL_ERROR; } if (TreeColumnList_FromObj(tree, objv[4], &columns, 0) != TCL_OK) { return TCL_ERROR; } if (TagExpr_Init(tree, objv[5], &expr) != TCL_OK) { result = TCL_ERROR; break; } COLUMN_FOR_EACH(column, &columns, NULL, &iter) { if (!TagExpr_Eval(&expr, column->tagInfo)) { ok = FALSE; break; } } TagExpr_Free(&expr); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(ok)); break; } /* T column tag names C */ case COMMAND_NAMES: { Tcl_Obj *listObj; Tk_Uid *tags = NULL; int i, tagSpace = 0, numTags = 0; if (objc != 5) { Tcl_WrongNumArgs(interp, 4, objv, "column"); return TCL_ERROR; } if (TreeColumnList_FromObj(tree, objv[4], &columns, 0) != TCL_OK) { return TCL_ERROR; } COLUMN_FOR_EACH(column, &columns, NULL, &iter) { tags = TagInfo_Names(tree, column->tagInfo, tags, &numTags, &tagSpace); } if (numTags) { listObj = Tcl_NewListObj(0, NULL); for (i = 0; i < numTags; i++) { Tcl_ListObjAppendElement(NULL, listObj, Tcl_NewStringObj((char *) tags[i], -1)); } Tcl_SetObjResult(interp, listObj); ckfree((char *) tags); } break; } /* T column tag remove C tagList */ case COMMAND_REMOVE: { int i, numTags; Tcl_Obj **listObjv; Tk_Uid staticTags[STATIC_SIZE], *tags = staticTags; if (objc != 6) { Tcl_WrongNumArgs(interp, 4, objv, "column tagList"); return TCL_ERROR; } if (TreeColumnList_FromObj(tree, objv[4], &columns, 0) != TCL_OK) { return TCL_ERROR; } if (Tcl_ListObjGetElements(interp, objv[5], &numTags, &listObjv) != TCL_OK) { result = TCL_ERROR; break; } STATIC_ALLOC(tags, Tk_Uid, numTags); for (i = 0; i < numTags; i++) { tags[i] = Tk_GetUid(Tcl_GetString(listObjv[i])); } COLUMN_FOR_EACH(column, &columns, NULL, &iter) { column->tagInfo = TagInfo_Remove(tree, column->tagInfo, tags, numTags); } STATIC_FREE(tags, Tk_Uid, numTags); break; } } TreeColumnList_Free(&columns); return result; } /* *---------------------------------------------------------------------- * * TreeColumnCmd -- * * This procedure is invoked to process the [column] widget * command. See the user documentation for details on what it * does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeColumnCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; static CONST char *commandNames[] = { "bbox", "cget", "compare", "configure", "count", "create", "delete", "dragcget", "dragconfigure", "id", #ifdef DEPRECATED "index", #endif "list", "move", "neededwidth", "order", "tag", "width", (char *) NULL }; enum { COMMAND_BBOX, COMMAND_CGET, COMMAND_COMPARE, COMMAND_CONFIGURE, COMMAND_COUNT, COMMAND_CREATE, COMMAND_DELETE, COMMAND_DRAGCGET, COMMAND_DRAGCONF, COMMAND_ID, #ifdef DEPRECATED COMMAND_INDEX, #endif COMMAND_LIST, COMMAND_MOVE, COMMAND_NEEDEDWIDTH, COMMAND_ORDER, COMMAND_TAG, COMMAND_WIDTH }; int index; TreeColumnList columns; TreeColumn column; ColumnForEach citer; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } TreeColumnList_Init(tree, &columns, 0); switch (index) { case COMMAND_BBOX: { int left, top, width, height; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "column"); return TCL_ERROR; } if (TreeColumn_FromObj(tree, objv[3], &column, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) return TCL_ERROR; if (TreeColumn_Bbox(column, &left, &top, &width, &height) < 0) break; FormatResult(interp, "%d %d %d %d", left, top, left + width, top + height); break; } case COMMAND_CGET: { TreeColumn column; Tcl_Obj *resultObjPtr; if (objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "column option"); return TCL_ERROR; } if (TreeColumn_FromObj(tree, objv[3], &column, CFO_NOT_NULL) != TCL_OK) return TCL_ERROR; { Tk_OptionSpec *specPtr = columnSpecs; int length; CONST char *optionName = Tcl_GetStringFromObj(objv[4], &length); while (specPtr->type != TK_OPTION_END) { if (strncmp(specPtr->optionName, optionName, length) == 0) { break; } specPtr++; } if (specPtr->type == TK_OPTION_END) { return TreeHeader_ConsumeColumnCget(tree, column, objv[4]); } } resultObjPtr = Tk_GetOptionValue(interp, (char *) column, column->optionTable, objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } /* T column compare C op C */ case COMMAND_COMPARE: { TreeColumn column1, column2; static CONST char *opName[] = { "<", "<=", "==", ">=", ">", "!=", NULL }; int op, compare = 0, index1, index2; if (objc != 6) { Tcl_WrongNumArgs(interp, 3, objv, "column1 op column2"); return TCL_ERROR; } if (TreeColumn_FromObj(tree, objv[3], &column1, CFO_NOT_NULL) != TCL_OK) return TCL_ERROR; if (Tcl_GetIndexFromObj(interp, objv[4], opName, "comparison operator", 0, &op) != TCL_OK) return TCL_ERROR; if (TreeColumn_FromObj(tree, objv[5], &column2, CFO_NOT_NULL) != TCL_OK) return TCL_ERROR; index1 = TreeColumn_Index(column1); index2 = TreeColumn_Index(column2); switch (op) { case 0: compare = index1 < index2; break; case 1: compare = index1 <= index2; break; case 2: compare = index1 == index2; break; case 3: compare = index1 >= index2; break; case 4: compare = index1 > index2; break; case 5: compare = index1 != index2; break; } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(compare)); break; } case COMMAND_CONFIGURE: { if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "column ?option? ?value? ?option value ...?"); return TCL_ERROR; } if (objc <= 5) { Tcl_Obj *resultObjPtr; if (TreeColumn_FromObj(tree, objv[3], &column, CFO_NOT_NULL) != TCL_OK) return TCL_ERROR; if (objc == 5) { Tk_OptionSpec *specPtr = columnSpecs; int length; CONST char *optionName = Tcl_GetStringFromObj(objv[4], &length); while (specPtr->type != TK_OPTION_END) { if (strncmp(specPtr->optionName, optionName, length) == 0) { break; } specPtr++; } if (specPtr->type == TK_OPTION_END) { resultObjPtr = TreeHeader_ConsumeColumnOptionInfo(tree, column, objv[4]); if (resultObjPtr == NULL) goto errorExit; Tcl_SetObjResult(interp, resultObjPtr); break; } resultObjPtr = Tk_GetOptionInfo(interp, (char *) column, column->optionTable, (objc == 4) ? (Tcl_Obj *) NULL : objv[4], tree->tkwin); if (resultObjPtr == NULL) goto errorExit; Tcl_SetObjResult(interp, resultObjPtr); } else { /* Return the combined [configure] output of the column and header-column */ Tcl_Obj *objPtr = Tk_GetOptionInfo(interp, (char *) column, column->optionTable, (Tcl_Obj *) NULL, tree->tkwin); resultObjPtr = TreeHeader_ConsumeColumnOptionInfo(tree, column, NULL); Tcl_ListObjAppendList(interp, resultObjPtr, objPtr); Tcl_SetObjResult(interp, resultObjPtr); break; } break; } /* If "all" is specified, get a list of columns instead of * COLUMN_ALL, since changing the -lock option of a column * may reorder columns. */ if (TreeColumnList_FromObj(tree, objv[3], &columns, CFO_LIST_ALL | CFO_NOT_NULL) != TCL_OK) return TCL_ERROR; COLUMN_FOR_EACH(column, &columns, NULL, &citer) { if (Column_Config(column, objc - 4, objv + 4, FALSE) != TCL_OK) goto errorExit; } break; } case COMMAND_CREATE: { TreeColumn column, last = tree->columnLast; TreeItem item; /* FIXME: -count N -tags $tags */ column = Column_Alloc(tree); column->index = TreeColumn_Index(tree->columnTail) + 1; /* after the tail column */ /* Create the item-column and header-column in every header */ item = tree->headerItems; while (item != NULL) { (void) TreeItem_MakeColumnExist(tree, item, column->index); item = TreeItem_GetNextSibling(tree, item); } column->index = TreeColumn_Index(tree->columnTail); if (Column_Config(column, objc - 3, objv + 3, TRUE) != TCL_OK) { /* Delete the item-column and header-column in every header */ item = tree->headerItems; while (item != NULL) { TreeItem_RemoveColumns(tree, item, column->index, column->index); item = TreeItem_GetNextSibling(tree, item); } Column_Free(column); return TCL_ERROR; } if (tree->columns == NULL) { column->index = 0; tree->columns = column; } else { last->next = column; column->prev = last; column->index = last->index + 1; } tree->columnLast = column; tree->columnTail->index++; { TreeColumn before = NULL; switch (column->lock) { case COLUMN_LOCK_LEFT: before = tree->columnLockNone; if (before == NULL) before = tree->columnLockRight; break; case COLUMN_LOCK_NONE: before = tree->columnLockRight; break; case COLUMN_LOCK_RIGHT: before = NULL; break; } if (before == NULL) before = tree->columnTail; Column_Move(column, before); } item = tree->headerItems; while (item != NULL) { TreeItemColumn itemColumn = TreeItem_FindColumn(tree, item, column->index); TreeHeaderColumn_EnsureStyleExists(TreeItem_GetHeader(tree, item), TreeItemColumn_GetHeaderColumn(tree, itemColumn), column); item = TreeItem_GetNextSibling(tree, item); } /* Indicate that all items must recalculate their list of spans. */ TreeItem_SpansInvalidate(tree, NULL); TreeColumns_InvalidateCounts(tree); Tree_DInfoChanged(tree, DINFO_REDO_COLUMN_WIDTH); Tcl_SetObjResult(interp, TreeColumn_ToObj(tree, column)); break; } /* T column delete first ?last? */ case COMMAND_DELETE: { TreeColumnList column2s; TreeColumn prev, next; int flags = CFO_NOT_NULL | CFO_NOT_TAIL; TreeItem item; Tcl_HashEntry *hPtr; Tcl_HashSearch search; int index; if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 3, objv, "first ?last?"); return TCL_ERROR; } if (objc == 5) flags |= CFO_NOT_MANY; if (TreeColumnList_FromObj(tree, objv[3], &columns, flags) != TCL_OK) goto errorExit; if (objc == 5) { if (TreeColumnList_FromObj(tree, objv[4], &column2s, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) goto errorExit; } COLUMN_FOR_EACH(column, &columns, (objc == 5) ? &column2s : NULL, &citer) { /* T column delete "all" */ if (citer.all) { column = tree->columns; while (column != NULL) { TreeDisplay_ColumnDeleted(tree, column); TreeHeader_ColumnDeleted(tree, column); TreeGradient_ColumnDeleted(tree, column); #if COLUMNGRID == 1 if (column->visible && (column->gridLeftColor != NULL || column->gridRightColor != NULL)) { tree->columnsWithGridLines -= 1; } #endif column = Column_Free(column); } tree->columnTail->index = 0; tree->columns = NULL; tree->columnLast = NULL; tree->columnLockLeft = NULL; tree->columnLockNone = NULL; tree->columnLockRight = NULL; /* Delete all TreeItemColumns */ item = tree->headerItems; while (item != NULL) { TreeItem_RemoveAllColumns(tree, item); item = TreeItem_GetNextSibling(tree, item); } /* Delete all TreeItemColumns */ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); TreeItem_RemoveAllColumns(tree, item); hPtr = Tcl_NextHashEntry(&search); } tree->columnTree = NULL; goto doneDELETE; } /* Delete all TreeItemColumns */ item = tree->headerItems; while (item != NULL) { TreeItem_RemoveColumns(tree, item, column->index, column->index); item = TreeItem_GetNextSibling(tree, item); } /* Delete all TreeItemColumns */ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); TreeItem_RemoveColumns(tree, item, column->index, column->index); hPtr = Tcl_NextHashEntry(&search); } TreeDisplay_ColumnDeleted(tree, column); TreeHeader_ColumnDeleted(tree, column); TreeGradient_ColumnDeleted(tree, column); #if COLUMNGRID == 1 if (column->visible && (column->gridLeftColor != NULL || column->gridRightColor != NULL)) { tree->columnsWithGridLines -= 1; /*dbwin("tree->columnsWithGridLines is now %d", tree->columnsWithGridLines);*/ } #endif /* Unlink. */ prev = column->prev; next = column->next; if (prev == NULL) tree->columns = next; else prev->next = next; if (next == NULL) tree->columnLast = prev; else next->prev = prev; if (column == tree->columnTree) tree->columnTree = NULL; (void) Column_Free(column); /* Renumber trailing columns */ column = next; while (column != NULL) { column->index--; column = column->next; } } tree->columnLockLeft = NULL; tree->columnLockNone = NULL; tree->columnLockRight = NULL; index = 0; column = tree->columns; while (column != NULL) { column->index = index++; if (column->lock == COLUMN_LOCK_LEFT && tree->columnLockLeft == NULL) tree->columnLockLeft = column; if (column->lock == COLUMN_LOCK_NONE && tree->columnLockNone == NULL) tree->columnLockNone = column; if (column->lock == COLUMN_LOCK_RIGHT && tree->columnLockRight == NULL) tree->columnLockRight = column; column = column->next; } tree->columnTail->index = index; doneDELETE: TreeColumns_InvalidateCounts(tree); tree->widthOfColumns = tree->headerHeight = -1; tree->widthOfColumnsLeft = tree->widthOfColumnsRight = -1; tree->columnPriv->reqInvalid = TRUE; Tree_DInfoChanged(tree, DINFO_REDO_COLUMN_WIDTH); /* Indicate that all items must recalculate their list of spans. */ TreeItem_SpansInvalidate(tree, NULL); if (objc == 5) TreeColumnList_Free(&column2s); break; } /* T column dragcget option */ case COMMAND_DRAGCGET: { return TreeHeaderCmd(clientData, interp, objc, objv); } /* T column dragconfigure ?option? ?value? ?option value ...? */ case COMMAND_DRAGCONF: { return TreeHeaderCmd(clientData, interp, objc, objv); } case COMMAND_COUNT: { int count = tree->columnCount; if (objc < 3 || objc > 4) { Tcl_WrongNumArgs(interp, 3, objv, "?columnDesc?"); return TCL_ERROR; } if (objc == 4) { if (TreeColumnList_FromObj(tree, objv[3], &columns, 0) != TCL_OK) return TCL_ERROR; count = 0; COLUMN_FOR_EACH(column, &columns, NULL, &citer) { count++; } } Tcl_SetObjResult(interp, Tcl_NewIntObj(count)); break; } case COMMAND_WIDTH: { if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "column"); return TCL_ERROR; } if (TreeColumn_FromObj(tree, objv[3], &column, CFO_NOT_NULL) != TCL_OK) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(TreeColumn_UseWidth(column))); break; } case COMMAND_ID: #ifdef DEPRECATED case COMMAND_INDEX: #endif { Tcl_Obj *listObj; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "column"); return TCL_ERROR; } if (TreeColumnList_FromObj(tree, objv[3], &columns, 0) != TCL_OK) return TCL_ERROR; listObj = Tcl_NewListObj(0, NULL); COLUMN_FOR_EACH(column, &columns, NULL, &citer) { Tcl_ListObjAppendElement(interp, listObj, TreeColumn_ToObj(tree, column)); } Tcl_SetObjResult(interp, listObj); break; } /* T column list ?-visible? */ case COMMAND_LIST: { TreeColumn column = tree->columns; Tcl_Obj *listObj; int visible = FALSE; if (objc > 4) { Tcl_WrongNumArgs(interp, 3, objv, "?-visible?"); return TCL_ERROR; } if (objc == 4) { int len; char *s = Tcl_GetStringFromObj(objv[3], &len); if ((s[0] == '-') && (strncmp(s, "-visible", len) == 0)) visible = TRUE; else { FormatResult(interp, "bad switch \"%s\": must be -visible", s); return TCL_ERROR; } } listObj = Tcl_NewListObj(0, NULL); while (column != NULL) { if (!visible || column->visible) Tcl_ListObjAppendElement(interp, listObj, TreeColumn_ToObj(tree, column)); column = column->next; } Tcl_SetObjResult(interp, listObj); break; } /* T column move C before */ case COMMAND_MOVE: { TreeColumn move, before; TreeColumn first = NULL, last = tree->columnTail; if (objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "column before"); return TCL_ERROR; } if (TreeColumn_FromObj(tree, objv[3], &move, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) return TCL_ERROR; if (TreeColumn_FromObj(tree, objv[4], &before, CFO_NOT_NULL) != TCL_OK) return TCL_ERROR; if ((move == before) || (move->index == before->index - 1)) break; switch (move->lock) { case COLUMN_LOCK_LEFT: first = tree->columnLockLeft; if (tree->columnLockNone != NULL) last = tree->columnLockNone; else if (tree->columnLockRight != NULL) last = tree->columnLockRight; break; case COLUMN_LOCK_NONE: first = tree->columnLockNone; if (tree->columnLockRight != NULL) last = tree->columnLockRight; break; case COLUMN_LOCK_RIGHT: first = tree->columnLockRight; break; } if (before->index < first->index || before->index > last->index) { if (before == tree->columnTail) { FormatResult(tree->interp, "can't move column %s%d before tail: -lock options conflict", tree->columnPrefix, move->id); } else { FormatResult(tree->interp, "can't move column %s%d before column %s%d: -lock options conflict", tree->columnPrefix, move->id, tree->columnPrefix, before->id); } return TCL_ERROR; } Column_Move(move, before); /* Indicate that all items must recalculate their list of spans. */ TreeItem_SpansInvalidate(tree, NULL); break; } case COMMAND_NEEDEDWIDTH: { TreeColumn column; int width; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "column"); return TCL_ERROR; } if (TreeColumn_FromObj(tree, objv[3], &column, CFO_NOT_NULL) != TCL_OK) return TCL_ERROR; /* Update layout if needed */ (void) Tree_CanvasWidth(tree); width = TreeColumn_WidthOfItems(column); width = MAX(width, TreeColumn_WidthOfHeaders(column)); Tcl_SetObjResult(interp, Tcl_NewIntObj(width)); break; } /* T column order C ?-visible? */ case COMMAND_ORDER: { TreeColumn column; int visible = FALSE; int index = 0; if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 3, objv, "column ?-visible?"); return TCL_ERROR; } if (objc == 5) { int len; char *s = Tcl_GetStringFromObj(objv[4], &len); if ((s[0] == '-') && (strncmp(s, "-visible", len) == 0)) visible = TRUE; else { FormatResult(interp, "bad switch \"%s\": must be -visible", s); return TCL_ERROR; } } if (TreeColumn_FromObj(tree, objv[3], &column, CFO_NOT_NULL) != TCL_OK) return TCL_ERROR; if (visible) { TreeColumn walk = tree->columns; while (walk != NULL) { if (walk == column) break; if (walk->visible) index++; walk = walk->next; } if (!column->visible) index = -1; } else { index = column->index; } Tcl_SetObjResult(interp, Tcl_NewIntObj(index)); break; } case COMMAND_TAG: { return ColumnTagCmd(clientData, interp, objc, objv); } } TreeColumnList_Free(&columns); return TCL_OK; errorExit: TreeColumnList_Free(&columns); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * InitColumnReqData -- * * Initialize the ColumnReqData structure in every column. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void InitColumnReqData( TreeCtrl *tree ) { TreeColumnPriv priv = tree->columnPriv; ColumnReqData *cd; TreeColumn column; if (!priv->reqInvalid || tree->columnCount == 0) return; /*dbwin("InitColumnReqData %s\n", Tk_PathName(tree->tkwin));*/ for (column = tree->columns; column != NULL; column = column->next) { cd = &column->reqData; cd->vis = TreeColumn_Visible(column); cd->min = TreeColumn_MinWidth(column); cd->fixed = TreeColumn_FixedWidth(column); cd->max = TreeColumn_MaxWidth(column); /* cd->req = 0;*/ if ((cd->max >= 0) && (cd->min > cd->max)) cd->min = cd->max; } priv->reqInvalid = FALSE; } /* *---------------------------------------------------------------------- * * SpanArray_Add -- * * Adds a ColumnSpan pointer to an array if it isn't already in * the array. * * Results: * None. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void SpanArray_Add( SpanArray *sa, ColumnSpan *cs ) { int i; for (i = 0; i < sa->count; i++) { if (sa->spans[i] == cs) return; } if (sa->alloc < sa->count + 1) { sa->spans = (ColumnSpan **) ckrealloc((char *) sa->spans, sizeof(ColumnSpan *) * (sa->count + 10)); sa->alloc = sa->count + 10; } sa->spans[sa->count++] = cs; } /* *---------------------------------------------------------------------- * * AddColumnSpan -- * * Adds or updates a span record for a range of columns * covered by a span. For every unique range of columns covered * by a span, there exists exactly one ColumnSpan record. * * Results: * Pointer to a new or updated ColumnSpan. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static ColumnSpan * AddColumnSpan( ColumnSpan *spanPrev, /* The span to the left. The span returned * by this function will be added to the * spanToTheRight array of spanPrev if it * wasn't already. */ TreeColumn spanMin, /* First column in the span. */ TreeColumn spanMax, /* Last column in the span. */ int neededWidth, /* Width needed by the span. */ int doHeaders /* TRUE if this span is in a header, FALSE * if the span is in an item. */ ) { TreeCtrl *tree = spanMin->tree; TreeColumnPriv priv = tree->columnPriv; ColumnSpan *cs = priv->spans; ColumnReqData *cd = &spanMin->reqData; TreeColumn column; int i; /* See if a span record exists by checking the list of spans touching * the first column. */ for (i = 0; i < cd->spans.count; i++) { cs = cd->spans.spans[i]; if ((cs->start == spanMin) && (cs->end == spanMax)) break; } if (i < cd->spans.count) { /* Add this span to the list of spans following spanPrev. */ if (spanPrev != NULL && priv->spansInvalid == TRUE) SpanArray_Add(&spanPrev->spansToRight, cs); cs->maxNeededWidth = MAX(cs->maxNeededWidth, neededWidth); /* Remember the widest span of 1 in this column. */ if (spanMin == spanMax) { cd->maxSingleSpanWidth = MAX(cd->maxSingleSpanWidth, neededWidth); if (doHeaders) cd->maxSingleHeaderWidth = MAX(cd->maxSingleHeaderWidth, neededWidth); else cd->maxSingleItemWidth = MAX(cd->maxSingleItemWidth, neededWidth); } return cs; } #ifdef TREECTRL_DEBUG if (priv->spansInvalid == FALSE) BreakIntoDebugger(); #endif if (priv->freeSpans == NULL) { cs = (ColumnSpan *) ckalloc(sizeof(ColumnSpan)); cs->spansToRight.alloc = 0; cs->spansToRight.spans = NULL; } else { cs = priv->freeSpans; priv->freeSpans = cs->next; } cs->start = spanMin; cs->end = spanMax; cs->maxNeededWidth = neededWidth; cs->spansToRight.count = 0; cs->next = priv->spans; priv->spans = cs; cs->nextCur = priv->spansCur; priv->spansCur = cs; /* Add this span to the list of spans following spanPrev. */ if (spanPrev != NULL) SpanArray_Add(&spanPrev->spansToRight, cs); for (column = spanMin; column != spanMax->next; column = column->next) { cd = &column->reqData; /* Add this new span record to the list of span records touching * this column. */ SpanArray_Add(&cd->spans, cs); /* Track the minimum and maximum columns of any span touching this * column.*/ if (priv->spansInvalid == FALSE) { #ifdef TREECTRL_DEBUG if (spanMin->index < cd->spanMin->index) BreakIntoDebugger(); if (spanMax->index > cd->spanMax->index) BreakIntoDebugger(); #endif } else { if (spanMin->index < cd->spanMin->index) cd->spanMin = spanMin; if (spanMax->index > cd->spanMax->index) cd->spanMax = spanMax; } /* Remember the widest span of 1 in this column. */ if (spanMin == spanMax) { cd->maxSingleSpanWidth = MAX(cd->maxSingleSpanWidth, neededWidth); if (doHeaders) cd->maxSingleHeaderWidth = MAX(cd->maxSingleHeaderWidth, neededWidth); else cd->maxSingleItemWidth = MAX(cd->maxSingleItemWidth, neededWidth); } else priv->allSpansAreOne = FALSE; } return cs; } /* s1 -> s2 -> s3 |_ s4 -> s5 s6 -> s7 -> s8 */ static int SumSpanWidths( int *sum, /* The current total span width. */ SpanArray *sa, /* For each span in this array, the * maximum width of each chain of spans * starting with that span is found and * added to *sum. */ TreeColumn end /* The column up to and including which the * sum of spans should be found. */ ) { int i, max = 0; int visited = 0; for (i = 0; i < sa->count; i++) { ColumnSpan *cs = sa->spans[i]; if (cs->end->index <= end->index) { visited++; if (cs->sumOfSpans == -1) { cs->sumOfSpans = cs->maxNeededWidth; visited += SumSpanWidths(&cs->sumOfSpans, &cs->spansToRight, end); } max = MAX(max, cs->sumOfSpans); } } *sum += max; return visited; } /* *---------------------------------------------------------------------- * * TrimTheFat -- * * Removes excess width from columns that may have been added by * DistributeSpanWidthToColumns(). In the scenario below, where * two items and the width needed by each of 3 spans is shown, * Column0 will have a requested width of 75, and Column1 will * have a requested width of 100/2=50, for a total width of * 75+50=125, which is wider than any item needs. At the end of * this procedure, the requested width of Column1 will be 25. * * Column0 Column1 * item1: 75----- 25---- * item2: 100----------- * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void TrimTheFatAux( TreeColumn start, TreeColumn end ) { #ifdef TREECTRL_DEBUG TreeCtrl *tree = start->tree; #endif TreeColumn column; int sumOfSpanWidths = 0; int sumOfColumnWidths = 0, fat, fatPerCol; int numColsThatCanShrink = 0, csn; ColumnReqData *cd; ColumnSpan *cs; int visited; #ifdef TREECTRL_DEBUG if (start->prev != NULL && start->prev->reqData.spanMax->index >= start->index) BreakIntoDebugger(); if (end->next != NULL && end->next->reqData.spanMin->index <= end->index) BreakIntoDebugger(); #endif /* Sum the widths of spans across the range of columns. */ sumOfSpanWidths = 0; visited = SumSpanWidths(&sumOfSpanWidths, &start->reqData.spans, end); if (sumOfSpanWidths <= 0) return; for (column = start; column != end->next; column = column->next) { cd = &column->reqData; if (!cd->vis) continue; sumOfColumnWidths += (cd->fixed >= 0) ? cd->fixed : column->widthOfItems; if (cd->fat && (cd->fixed < 0) && (column->widthOfItems > MAX(cd->maxSingleSpanWidth, cd->min))) numColsThatCanShrink++; } #ifdef TREECTRL_DEBUG if (tree->debug.enable && tree->debug.span) dbwin("%d-%d sumOfColumnWidths %d sumOfSpanWidths %d (visited %d)\n", start->index, end->index, sumOfColumnWidths, sumOfSpanWidths, visited); #endif if (!numColsThatCanShrink) return; fat = sumOfColumnWidths - sumOfSpanWidths; if (fat <= 0) return; while (fat > 0) { int origFat = fat; /* Subtract 1 to smooth out the distribution. May result in more looping. */ fatPerCol = MAX(1, fat / numColsThatCanShrink - 1); for (column = start; column != end->next; column = column->next) { int minSpanFat = -1; cd = &column->reqData; if (!cd->vis || !cd->fat) continue; if ((cd->fixed >= 0) || (column->widthOfItems <= cd->min) || (column->widthOfItems <= cd->maxSingleSpanWidth)) continue; for (csn = 0; csn < cd->spans.count; csn++) { cs = cd->spans.spans[csn]; if (cs->widthOfColumns > cs->maxNeededWidth) { if (minSpanFat == -1) minSpanFat = cs->widthOfColumns - cs->maxNeededWidth; else minSpanFat = MIN(minSpanFat, cs->widthOfColumns - cs->maxNeededWidth); } else { minSpanFat = 0; /* no span touching this column can get smaller */ cd->fat = FALSE; /* FIXME: mark all in this span */ --numColsThatCanShrink; break; } } if (minSpanFat > 0) { int trim = MIN(minSpanFat, fatPerCol); if (column->widthOfItems - trim < cd->min) trim = column->widthOfItems - cd->min; if (column->widthOfItems - trim < cd->maxSingleSpanWidth) trim = column->widthOfItems - cd->maxSingleSpanWidth; #ifdef TREECTRL_DEBUG if (tree->debug.enable && tree->debug.span) dbwin("trimmed %d from %d (numColsThatCanShrink=%d fat=%d minSpanFat=%d)\n", trim, column->index, numColsThatCanShrink, fat, minSpanFat); #endif column->widthOfItems -= trim; fat -= trim; if (fat <= 0) break; for (csn = 0; csn < cd->spans.count; csn++) { cs = cd->spans.spans[csn]; cs->widthOfColumns -= trim; } if (column->widthOfItems <= MAX(cd->maxSingleSpanWidth, cd->min)) --numColsThatCanShrink; } if (numColsThatCanShrink == 0) break; } if (fat == origFat || numColsThatCanShrink == 0) break; } } static void TrimTheFat( TreeColumn start, TreeColumn end ) { TreeColumnPriv priv = start->tree->columnPriv; TreeColumn column; ColumnReqData *cd; ColumnSpan *cs; if (priv->allSpansAreOne) return; #ifdef TREECTRL_DEBUG if (start->prev != NULL && start->prev->reqData.spanMax->index >= start->index) BreakIntoDebugger(); if (end->next != NULL && end->next->reqData.spanMin->index <= end->index) BreakIntoDebugger(); #endif for (cs = priv->spansCur; cs != NULL; cs = cs->nextCur) { /* Sum the current widths of columns in each span record. */ cs->widthOfColumns = 0; for (column = cs->start; column != cs->end->next; column = column->next) { cd = &column->reqData; if (!cd->vis) continue; cs->widthOfColumns += (cd->fixed >= 0) ? cd->fixed : column->widthOfItems; } /* Mark columns that cannot get smaller. */ if (cs->widthOfColumns <= cs->maxNeededWidth) { for (column = cs->start; column != cs->end->next; column = column->next) { cd = &column->reqData; cd->fat = FALSE; } #if 0 } else { priv->minPositiveFatOfAllSpans = MIN(priv->minPositiveFatOfAllSpans, cs->widthOfColumns - cs->maxNeededWidth); #endif } cs->sumOfSpans = -1; } column = start; while (column != end->next) { TreeColumn columnMin, columnMax; /* Operate on the narrowest range of columns whose spans do not * overlap another such range of columns. */ columnMin = column->reqData.spanMin; columnMax = column->reqData.spanMax; while ((columnMax->next != NULL) && (columnMax->next->reqData.spanMin->index <= columnMax->index)) { columnMax = columnMax->next->reqData.spanMax; } TrimTheFatAux(columnMin, columnMax); column = columnMax->next; } } /* *---------------------------------------------------------------------- * * TreeItem_RequestWidthInColumns -- * * Calculates the width needed by styles in a range of columns * for a single header or item. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_RequestWidthInColumns( TreeCtrl *tree, /* Widget info. */ TreeItem item, TreeColumn columnMin, TreeColumn columnMax ) { #ifdef TREECTRL_DEBUG TreeColumnPriv priv = tree->columnPriv; #endif int doHeaders = TreeItem_GetHeader(tree, item) != NULL; int columnIndexMin = TreeColumn_Index(columnMin); int columnIndexMax = TreeColumn_Index(columnMax); int *spans = TreeItem_GetSpans(tree, item); TreeItemColumn itemColumn; TreeColumn treeColumn; int columnIndex, width, indent; ColumnSpan *csPrev = NULL; #ifdef TREECTRL_DEBUG if (columnMax == tree->columnTail) BreakIntoDebugger(); if (priv->reqInvalid) BreakIntoDebugger(); if (columnMin->prev != NULL && columnMin->prev->reqData.spanMax->index >= columnMin->index) BreakIntoDebugger(); if (columnMax->next != NULL && columnMax->next->reqData.spanMin->index <= columnMax->index) BreakIntoDebugger(); #endif treeColumn = columnMin; itemColumn = TreeItem_FindColumn(tree, item, columnIndexMin); if (spans == NULL) { for (columnIndex = columnIndexMin; columnIndex <= columnIndexMax; ++columnIndex) { ColumnReqData *cd = &treeColumn->reqData; if (cd->vis) { width = (itemColumn != NULL) ? TreeItemColumn_NeededWidth(tree, item, itemColumn) : 0; /* FOR COMPATIBILITY ONLY. Don't request width from -indent * if there is no item column. */ if (itemColumn != NULL) { indent = doHeaders ? 0 : TreeItem_Indent(tree, treeColumn, item); width += indent; } csPrev = AddColumnSpan(csPrev, treeColumn, treeColumn, width, doHeaders); } treeColumn = TreeColumn_Next(treeColumn); if (itemColumn != NULL) itemColumn = TreeItemColumn_GetNext(tree, itemColumn); } return; } #if defined(TREECTRL_DEBUG) /* It must be true that a span starts at columnMin. */ if (spans[columnIndexMin] != columnIndexMin) BreakIntoDebugger(); #endif for (columnIndex = columnIndexMin; columnIndex <= columnIndexMax; /*++columnIndex*/) { ColumnReqData *cd = &treeColumn->reqData; int columnIndex2 = columnIndex; TreeColumn treeColumn2 = treeColumn; TreeColumn lastColumnInSpan = treeColumn; #if defined(TREECTRL_DEBUG) if (TreeColumn_Index(treeColumn) != columnIndex) BreakIntoDebugger(); if (itemColumn != NULL && TreeItemColumn_Index(tree, item, itemColumn) != columnIndex) BreakIntoDebugger(); if (spans[columnIndex] != columnIndex) BreakIntoDebugger(); #endif while ((columnIndex2 <= columnIndexMax) && (spans[columnIndex2] == columnIndex)) { lastColumnInSpan = treeColumn2; treeColumn2 = TreeColumn_Next(treeColumn2); columnIndex2++; } if (cd->vis) { width = (itemColumn != NULL) ? TreeItemColumn_NeededWidth(tree, item, itemColumn) : 0; /* Indentation is spread amongst the visible columns as well, and * is only used if the -treecolumn is the first column in the span. */ /* FOR COMPATIBILITY ONLY. Don't request width from -indent * if there is no item column. */ if (itemColumn != NULL) { indent = doHeaders ? 0 : TreeItem_Indent(tree, treeColumn, item); width += indent; } csPrev = AddColumnSpan(csPrev, treeColumn, lastColumnInSpan, width, doHeaders); } treeColumn = TreeColumn_Next(lastColumnInSpan); if (treeColumn == NULL) break; while (/*(itemColumn != NULL) && */(columnIndex < TreeColumn_Index(treeColumn))) { if (itemColumn != NULL) itemColumn = TreeItemColumn_GetNext(tree, itemColumn); ++columnIndex; } } } /* *---------------------------------------------------------------------- * * DistributeSpanWidthToColumns -- * * Ensures that each range of columns covered by a span is wide * enough to contain that span, without violating the -width and * -maxwidth column options. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void DistributeSpanWidthToColumns( TreeColumn start, TreeColumn end ) { TreeCtrl *tree = start->tree; TreeColumnPriv priv = tree->columnPriv; ColumnSpan *cs; ColumnReqData *cd; TreeColumn column; if (priv->allSpansAreOne) { for (column = start; column != end->next; column = column->next) column->widthOfItems = column->reqData.maxSingleSpanWidth; return; } for (cs = priv->spansCur; cs != NULL; cs = cs->nextCur) { int numVisibleColumns = 0, spaceRemaining = cs->maxNeededWidth; int numMinWidth = 0, minMinWidth = -1, varWidth = 0; if (cs->maxNeededWidth <= 0) continue; for (column = cs->start; column != cs->end->next; column = column->next) { cd = &column->reqData; #if defined(TREECTRL_DEBUG) if (cd->vis != TreeColumn_Visible(column)) BreakIntoDebugger(); if (TreeColumn_MaxWidth(column) >= 0 && cd->min > TreeColumn_MaxWidth(column)) BreakIntoDebugger(); if (TreeColumn_MaxWidth(column) < 0 && cd->min != TreeColumn_MinWidth(column)) BreakIntoDebugger(); if (cd->max != TreeColumn_MaxWidth(column)) BreakIntoDebugger(); if (cd->fixed != TreeColumn_FixedWidth(column)) BreakIntoDebugger(); #endif cd->req = 0; if (cd->vis) numVisibleColumns++; } /* Dump space into fixed-width and minwidth */ for (column = cs->start; (spaceRemaining > 0) && (column != cs->end->next); column = column->next) { int spaceUsed; cd = &column->reqData; if (!cd->vis) continue; if (cd->fixed >= 0) { spaceUsed = cd->fixed; numVisibleColumns--; } else if (cd->min >= 0) { spaceUsed = cd->min; ++numMinWidth; if (minMinWidth == -1) minMinWidth = cd->min; else minMinWidth = MIN(minMinWidth, cd->min); } else continue; spaceUsed = MIN(spaceUsed, spaceRemaining); cd->req += spaceUsed; spaceRemaining -= spaceUsed; } /* Distribute width to visible columns in the span. */ while ((spaceRemaining > 0) && (numVisibleColumns > 0)) { int each; int origSpaceRemaining = spaceRemaining; /* This is the amount to give to each column. Some columns * may get one extra pixel (starting from the leftmost column). */ each = MAX(1, spaceRemaining / numVisibleColumns); varWidth += each; /* If all the columns have -minwidth, there will be a lot of * useless looping until varWidth exceeds the smallest -minwidth. */ if (numMinWidth == numVisibleColumns) while (varWidth <= minMinWidth) varWidth += each; for (column = cs->start; (spaceRemaining > 0) && (column != cs->end->next); column = column->next) { int spaceUsed = each; cd = &column->reqData; if (!cd->vis) continue; if (cd->fixed >= 0) continue; if ((cd->max >= 0) && (cd->req >= cd->max)) continue; /* Don't grow minwidth columns until the space of variable-width * columns exceeds that of minwidth. */ if ((cd->min >= 0) && (cd->req >= varWidth)) continue; if (cd->min >= 0) { spaceUsed = MIN(varWidth - cd->req, spaceUsed); } if (cd->max >= 0) { spaceUsed = MIN(cd->max - cd->req, spaceUsed); if (cd->req + MIN(spaceUsed, spaceRemaining) >= cd->max) { spaceUsed = cd->max - cd->req; numVisibleColumns--; } } spaceUsed = MIN(spaceUsed, spaceRemaining); cd->req += spaceUsed; #if defined(TREECTRL_DEBUG) if (cd->fixed >= 0 && cd->req > cd->fixed) BreakIntoDebugger(); if (cd->fixed < 0 && cd->max >= 0 && cd->req > cd->max) BreakIntoDebugger(); #endif spaceRemaining -= spaceUsed; } if (spaceRemaining == origSpaceRemaining) break; } for (column = cs->start; (column != cs->end->next); column = column->next) { cd = &column->reqData; if (!cd->vis) continue; column->widthOfItems = MAX(column->widthOfItems, cd->req); } } } /* *---------------------------------------------------------------------- * * TreeColumn_WidthOfItems -- * * Calculate the maximum needed width of the styles in every * ReallyVisible() item for a particular column. The width will * only be recalculated if it is marked out-of-date. * * Results: * Pixel width. * * Side effects: * The size of elements and styles will be updated if they are * marked out-of-date. * *---------------------------------------------------------------------- */ int TreeColumn_WidthOfItems( TreeColumn column /* Column token. */ ) { TreeCtrl *tree = column->tree; TreeColumnPriv priv = tree->columnPriv; TreeColumn columnMin = NULL, columnMax = NULL; if (IS_TAIL(column)) return 0; if (priv->spansInvalid) { columnMin = tree->columns; columnMax = tree->columnLast; if (priv->freeSpans != NULL) priv->freeSpans->next = priv->spans; else priv->freeSpans = priv->spans; priv->spans = NULL; priv->spansCur = NULL; priv->allSpansAreOne = TRUE; } else if (column->reqData.spanMin->widthOfItems < 0) { ColumnSpan *cs; columnMin = column->reqData.spanMin; columnMax = column->reqData.spanMax; /* Gather all adjacent out-of-date columns into one group. */ /* Must also get any spans that overlap any spans that overlap this * column. */ while ((columnMin->prev != NULL) && ((columnMin->prev->reqData.spanMax->index >= columnMin->index) || (columnMin->prev->reqData.spanMin->widthOfItems < 0))) { columnMin = columnMin->prev->reqData.spanMin; } while ((columnMax->next != NULL) && ((columnMax->next->reqData.spanMin->index <= columnMax->index) || (columnMax->next->widthOfItems < 0))) { columnMax = columnMax->next->reqData.spanMax; } /* Build the list of span records touching the range of columns. */ priv->spansCur = NULL; for (cs = priv->spans; cs != NULL; cs = cs->next) { if (cs->start->index < columnMin->index || cs->end->index > columnMax->index) { continue; } cs->maxNeededWidth = 0; cs->nextCur = priv->spansCur; priv->spansCur = cs; } } if (columnMin != NULL) { TreeColumn column2; for (column2 = columnMin; column2 != columnMax->next; column2 = column2->next) { column2->widthOfItems = 0; column2->reqData.maxSingleSpanWidth = 0; column2->reqData.maxSingleHeaderWidth = 0; column2->reqData.maxSingleItemWidth = 0; column2->reqData.fat = TRUE; if (priv->spansInvalid) { column2->reqData.spanMin = column2->reqData.spanMax = column2; column2->reqData.spans.count = 0; } } #ifdef TREECTRL_DEBUG if (tree->debug.enable && tree->debug.span) dbwin("RequestWidthInColumns %s %d-%d allSpansAreOne=%d\n", Tk_PathName(tree->tkwin), columnMin->index, columnMax->index, priv->allSpansAreOne); #endif InitColumnReqData(tree); TreeHeaders_RequestWidthInColumns(tree, columnMin, columnMax); TreeItems_RequestWidthInColumns(tree, columnMin, columnMax); priv->spansInvalid = FALSE; /* Clear this *after* the above call. */ DistributeSpanWidthToColumns(columnMin, columnMax); TrimTheFat(columnMin, columnMax); } /* FOR COMPATIBILITY ONLY */ /* See the use of TreeColumn_WidthOfItems() by tkTreeDisplay.c. */ TreeColumns_UpdateCounts(tree); if (tree->columnCountVis == 1 && tree->columnVis == column) return column->reqData.maxSingleItemWidth; return column->widthOfItems; } /* *---------------------------------------------------------------------- * * TreeColumn_WidthOfHeaders -- * * Return the requested width of styles displayed in every visible * header for a single column. * * Results: * Pixel width. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColumn_WidthOfHeaders( TreeColumn column /* Column token. */ ) { TreeCtrl *tree = column->tree; int width = TreeColumn_WidthOfItems(column); /* FOR COMPATIBILITY ONLY */ /* See the use of TreeColumn_WidthOfItems() by tkTreeDisplay.c. */ if (tree->columnCountVis == 1 && tree->columnVis == column) return column->reqData.maxSingleHeaderWidth; return width; } /* *---------------------------------------------------------------------- * * TreeColumns_InvalidateSpans -- * * Marks the spanMin & spanMax fields of every column as * out-of-date. * Called when anything affects the spans of items or headers, * such as: * a) header and item deletion * b) header and item visibility changes, including expanding, * collapsing, or reparenting * d) [item span] or [header span] changed spans * e) column creation, deletion, reordering, or visibility * changes (handled by TreeItem_SpansInvalidate). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeColumns_InvalidateSpans( TreeCtrl *tree /* Widget info. */ ) { tree->columnPriv->spansInvalid = TRUE; } /* *---------------------------------------------------------------------- * * TreeColumns_InvalidateWidthOfItems -- * * Marks the width requested by items in zero or more columns * as out-of-date. * * Results: * None. * * Side effects: * Idle task may be scheduled. * *---------------------------------------------------------------------- */ void TreeColumns_InvalidateWidthOfItems( TreeCtrl *tree, /* Widget info. */ TreeColumn column /* Column to modify. NULL means * modify every column. */ ) { TreeColumnPriv priv = tree->columnPriv; /* FIXME: This gets called for both items and headers. If invalidating * header width, there is no need to invalidate widthOfItems unless the * column is covered by a span > 1 in one or more items. */ if (column == NULL) { column = tree->columns; while (column != NULL) { column->widthOfItems = -1; column = column->next; } } else if (!priv->spansInvalid && column->reqData.spanMin != NULL) { /* spanMin/Max can be NULL during creation when spansInvalid hasn't been set TRUE yet */ TreeColumn columnMin = column->reqData.spanMin; TreeColumn columnMax = column->reqData.spanMax; columnMin->widthOfItems = -1; /* Must recalculate the width of items in every span that overlaps * any of the spans that include this column. */ while ((columnMin->prev != NULL) && (columnMin->prev->reqData.spanMax->index >= columnMin->index)) { columnMin = columnMin->prev->reqData.spanMin; columnMin->widthOfItems = -1; } while ((columnMax->next != NULL) && (columnMax->next->reqData.spanMin->index <= columnMax->index)) { columnMax = columnMax->next->reqData.spanMax; columnMax->reqData.spanMin->widthOfItems = -1; } } TreeColumns_InvalidateWidth(tree); } /* *---------------------------------------------------------------------- * * TreeColumns_InvalidateWidth -- * * Marks the width of columns as out-of-date. * Schedules a redisplay to check the widths of columns which * will perform any relayout necessary. * * Results: * None. * * Side effects: * Idle task may be scheduled. * *---------------------------------------------------------------------- */ void TreeColumns_InvalidateWidth( TreeCtrl *tree /* Widget info. */ ) { tree->widthOfColumns = -1; tree->widthOfColumnsLeft = -1; tree->widthOfColumnsRight = -1; tree->columnPriv->reqInvalid = TRUE; Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH); } /* *-------------------------------------------------------------- * * TreeColumn_Bbox -- * * Return the bounding box for a column. * This used to be the function to call to get the bounding * box of a column header. * * Results: * Return value is -1 if the column is not visible. * * Side effects: * Column layout will be updated if needed. * *-------------------------------------------------------------- */ int TreeColumn_Bbox( TreeColumn column, /* Column token. */ int *x, int *y, /* Out: window coordinates. */ int *w, int *h /* Out: width and height. */ ) { TreeCtrl *tree = column->tree; int left = 0; if (!tree->showHeader || !TreeColumn_Visible(column)) return -1; *y = Tree_HeaderTop(tree); *h = Tree_HeaderHeight(tree); if (column == tree->columnTail) { *x = Tree_WidthOfColumns(tree) - tree->xOrigin; /* Canvas -> Window */ *w = 1; /* xxx */ return 0; } /* Get width (and update column layout) */ *w = TreeColumn_UseWidth(column); switch (TreeColumn_Lock(column)) { case COLUMN_LOCK_LEFT: left = Tree_BorderLeft(tree); break; case COLUMN_LOCK_NONE: left = 0 - Tree_GetOriginX(tree); /* Canvas -> Window */ break; case COLUMN_LOCK_RIGHT: left = Tree_ContentRight(tree); break; } *x = left + TreeColumn_Offset(column); return 0; } /* *---------------------------------------------------------------------- * * LayoutColumns -- * * Calculates the display width and horizontal offset of a range * of columns. * * Results: * The .useWidth and .offset fields of every column in the range * are updated. * The result is the sum of the widths of all visible columns in the * range. * * Side effects: * The size of elements and styles may be updated if they are * marked out-of-date. * *---------------------------------------------------------------------- */ static int LayoutColumns( TreeCtrl *tree, /* Widget info. */ TreeColumn first /* First column to update. All columns * with the same -lock value are updated. */ ) { TreeColumn column; int width, visWidth, totalWidth = 0; int numExpand = 0, numSqueeze = 0; #ifdef UNIFORM_GROUP Tcl_HashEntry *hPtr; Tcl_HashSearch search; UniformGroup *uniform; int uniformCount = 0; #endif #ifdef TREECTRL_DEBUG if (tree->debugCheck.inLayoutColumns) panic("recursive call to LayoutColumns"); #endif if (first == NULL) return 0; tree = first->tree; #ifdef TREECTRL_DEBUG tree->debugCheck.inLayoutColumns = TRUE; #endif #ifdef UNIFORM_GROUP /* Initialize the .minSize field of every uniform group. */ hPtr = Tcl_FirstHashEntry(&tree->uniformGroupHash, &search); while (hPtr != NULL) { uniform = (UniformGroup *) Tcl_GetHashValue(hPtr); uniform->minSize = 0; hPtr = Tcl_NextHashEntry(&search); } #endif /* * Determine the initial display width of each column. This will be: * a) the column's -width option (a fixed width), or * b) the maximum of: * 1) the width requested by the column's header * 2) the width requested by each item style in that column * For b) the width is clipped to -minwidth and -maxwidth. */ column = first; while (column != NULL && column->lock == first->lock) { if (column->visible) { if (column->widthObj != NULL) width = column->width; else { width = TreeColumn_WidthOfItems(column); width = MAX(width, TreeColumn_WidthOfHeaders(column)); width = MAX(width, TreeColumn_MinWidth(column)); if (TreeColumn_MaxWidth(column) != -1) width = MIN(width, TreeColumn_MaxWidth(column)); #ifdef UNIFORM_GROUP /* Track the maximum requested width of every column in this * column's uniform group considering -weight. */ if (column->uniform != NULL) { int weight = MAX(column->weight, 1); int minSize = (width + weight - 1) / weight; if (minSize > column->uniform->minSize) column->uniform->minSize = minSize; uniformCount++; } if (column->expand) numExpand += MAX(column->weight, 0); if (column->squeeze) numSqueeze += MAX(column->weight, 0); #else if (column->expand) numExpand++; if (column->squeeze) numSqueeze++; #endif } } else width = 0; column->useWidth = width; totalWidth += width; column = column->next; } #ifdef UNIFORM_GROUP /* Apply the -uniform and -weight options. */ if (uniformCount > 0) { column = first; while (column != NULL && column->lock == first->lock) { if (column->visible && column->widthObj == NULL && column->uniform != NULL) { int weight = MAX(column->weight, 1); width = column->uniform->minSize * weight; if (column->maxWidthObj != NULL) width = MIN(width, column->maxWidth); totalWidth -= column->useWidth; column->useWidth = width; totalWidth += width; } column = column->next; } } #endif /* UNIFORM_GROUP */ /* Locked columns don't squeeze or expand. */ if (first->lock != COLUMN_LOCK_NONE) goto doOffsets; visWidth = Tree_ContentWidth(tree); /* Hack */ visWidth -= tree->canvasPadX[PAD_TOP_LEFT] + tree->canvasPadX[PAD_BOTTOM_RIGHT]; if (visWidth <= 0) goto doOffsets; /* Squeeze columns */ if ((visWidth < totalWidth) && (numSqueeze > 0)) { int spaceRemaining = totalWidth - visWidth; while ((spaceRemaining > 0) && (numSqueeze > 0)) { int each = (spaceRemaining >= numSqueeze) ? spaceRemaining / numSqueeze : 1; numSqueeze = 0; column = first; while (column != NULL && column->lock == first->lock) { if (column->visible && column->squeeze && (column->widthObj == NULL)) { int min = MAX(0, TreeColumn_MinWidth(column)); if (column->useWidth > min) { int sub = MIN(each, column->useWidth - min); column->useWidth -= sub; spaceRemaining -= sub; if (!spaceRemaining) break; if (column->useWidth > min) numSqueeze++; } } column = column->next; } } } /* Expand columns */ if ((visWidth > totalWidth) && (numExpand > 0)) { int spaceRemaining = visWidth - totalWidth; while ((spaceRemaining > 0) && (numExpand > 0)) { int each = (spaceRemaining >= numExpand) ? spaceRemaining / numExpand : 1; numExpand = 0; column = first; while (column != NULL && column->lock == first->lock) { #ifdef UNIFORM_GROUP int weight = MAX(column->weight, 0); if (column->visible && column->expand && weight && (column->widthObj == NULL)) { int max = TreeColumn_MaxWidth(column); if ((max == -1) || (column->useWidth < max)) { int eachW = MIN(each * weight, spaceRemaining); int add = (max == -1) ? eachW : MIN(eachW, max - column->useWidth); column->useWidth += add; spaceRemaining -= add; if (!spaceRemaining) break; if ((max == -1) || (column->useWidth < max)) numExpand += weight; #else if (column->visible && column->expand && (column->widthObj == NULL)) { int max = TreeColumn_MaxWidth(column); if ((max == -1) || (column->useWidth < max)) { int add = (max == -1) ? each : MIN(each, max - column->useWidth); column->useWidth += add; spaceRemaining -= add; if (!spaceRemaining) break; if ((max == -1) || (column->useWidth < max)) numExpand++; #endif } } column = column->next; } } } doOffsets: /* Calculate the horizontal offset of each column in the range. * The total width is recalculated as well (needed anyway if any * columns were expanded or squeezed). */ totalWidth = 0; column = first; while (column != NULL && column->lock == first->lock) { column->offset = totalWidth; /* Hack */ if (column->lock == COLUMN_LOCK_NONE) column->offset += tree->canvasPadX[PAD_TOP_LEFT]; totalWidth += column->useWidth; column = column->next; } #ifdef TREECTRL_DEBUG tree->debugCheck.inLayoutColumns = FALSE; #endif return totalWidth; } /* *---------------------------------------------------------------------- * * Tree_WidthOfColumns -- * * Return the total display width of all non-locked columns (except * the tail). * The width is only recalculated if it is marked out-of-date. * Other fields of the TreeCtrl are updated to reflect the current * arrangement of columns. * * Results: * Pixel width. * * Side effects: * The size of elements and styles may be updated if they are * marked out-of-date. * *---------------------------------------------------------------------- */ int Tree_WidthOfColumns( TreeCtrl *tree /* Widget info. */ ) { /* Tree_WidthOfColumns used to update columnCountVis, but that is now * done in a separate function TreeColumns_UpdateCounts, because * TreeItem_ReallyVisible needs up-to-date counts (for header items) * and LayoutColumns may call TreeItem_ReallyVisible. */ TreeColumns_UpdateCounts(tree); /* This gets called when the layout of all columns needs to be current. * So update the layout of the left- and right-locked columns too. */ (void) Tree_WidthOfLeftColumns(tree); (void) Tree_WidthOfRightColumns(tree); if (tree->widthOfColumns >= 0) return tree->widthOfColumns; tree->widthOfColumns = LayoutColumns(tree, tree->columnLockNone); if (tree->columnTree != NULL && TreeColumn_Visible(tree->columnTree)) { tree->columnTreeLeft = tree->columnTree->offset; tree->columnTreeVis = TRUE; } else { tree->columnTreeLeft = 0; tree->columnTreeVis = FALSE; } /* I can't calculate the width of the tail column here because it * depends on Tree_FakeCanvasWidth which calls this function. */ tree->columnTail->offset = tree->canvasPadX[PAD_TOP_LEFT] + tree->widthOfColumns; tree->columnTail->useWidth = 0; /* hack */ return tree->widthOfColumns; } /* *---------------------------------------------------------------------- * * Tree_WidthOfLeftColumns -- * * Return the total display width of all left-locked columns. * The width is only recalculated if it is marked out-of-date. * Other fields of the TreeCtrl are updated to reflect the current * arrangement of columns. * * Results: * Pixel width. * * Side effects: * The size of elements and styles may be updated if they are * marked out-of-date. * *---------------------------------------------------------------------- */ int Tree_WidthOfLeftColumns( TreeCtrl *tree /* Widget info. */ ) { if (tree->widthOfColumnsLeft >= 0) return tree->widthOfColumnsLeft; if (!Tree_ShouldDisplayLockedColumns(tree)) { TreeColumn column = tree->columnLockLeft; while (column != NULL && column->lock == COLUMN_LOCK_LEFT) { column->useWidth = 0; column = column->next; } tree->columnCountVisLeft = 0; tree->widthOfColumnsLeft = 0; return 0; } tree->widthOfColumnsLeft = LayoutColumns(tree, tree->columnLockLeft); return tree->widthOfColumnsLeft; } /* *---------------------------------------------------------------------- * * Tree_WidthOfRightColumns -- * * Return the total display width of all right-locked columns. * The width is only recalculated if it is marked out-of-date. * Other fields of the TreeCtrl are updated to reflect the current * arrangement of columns. * * Results: * Pixel width. * * Side effects: * The size of elements and styles may be updated if they are * marked out-of-date. * *---------------------------------------------------------------------- */ int Tree_WidthOfRightColumns( TreeCtrl *tree /* Widget info. */ ) { if (tree->widthOfColumnsRight >= 0) return tree->widthOfColumnsRight; if (!Tree_ShouldDisplayLockedColumns(tree)) { TreeColumn column = tree->columnLockRight; while (column != NULL && column->lock == COLUMN_LOCK_RIGHT) { column->useWidth = 0; column = column->next; } tree->columnCountVisRight = 0; tree->widthOfColumnsRight = 0; return 0; } tree->widthOfColumnsRight = LayoutColumns(tree, tree->columnLockRight); return tree->widthOfColumnsRight; } /* *---------------------------------------------------------------------- * * UpdateColumnCounts -- * * Calculates the number of visible columns with the same -lock * value, and optionally returns the first visible column in the * group. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void UpdateColumnCounts( TreeCtrl *tree, /* Widget info. */ TreeColumn first, /* First column to check. All columns * with the same -lock value are checked. */ TreeColumn *visPtr, /* Out: first visible column. */ int *countVisPtr /* Out: number of visible columns. */ ) { TreeColumn column; if (visPtr != NULL) (*visPtr) = NULL; (*countVisPtr) = 0; for (column = first; column != NULL && column->lock == first->lock; column = column->next) { if (column->visible) { if (visPtr != NULL && (*visPtr) == NULL) (*visPtr) = column; (*countVisPtr)++; } } } /* *---------------------------------------------------------------------- * * TreeColumns_UpdateCounts -- * * Recalculates the number of visible columns and the first * visible non-locked column if needed. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeColumns_UpdateCounts( TreeCtrl *tree /* Widget info. */ ) { int displayLockedColumns = Tree_ShouldDisplayLockedColumns(tree); if (tree->displayLockedColumns != displayLockedColumns) { tree->columnCountVis = -1; tree->displayLockedColumns = displayLockedColumns; } if (tree->columnCountVis >= 0) return; UpdateColumnCounts(tree, tree->columnLockNone, &tree->columnVis, &tree->columnCountVis); if (displayLockedColumns) { UpdateColumnCounts(tree, tree->columnLockLeft, NULL, &tree->columnCountVisLeft); UpdateColumnCounts(tree, tree->columnLockRight, NULL, &tree->columnCountVisRight); } else { tree->columnCountVisLeft = 0; tree->columnCountVisRight = 0; } } /* *---------------------------------------------------------------------- * * TreeColumns_InvalidateCounts -- * * Marks the number of visible columns as out-of-date. * The number of visible columns changes when: * 1) creating a column * 2) deleting a column * 3) moving a column (affects tree->columnVis anyway) * 4) column option -visible changes * 5) column option -lock changes * 6) Tree_ShouldDisplayLockedColumns() changes * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeColumns_InvalidateCounts( TreeCtrl *tree /* Widget info. */ ) { tree->columnCountVis = -1; tree->columnCountVisLeft = -1; tree->columnCountVisRight = -1; } /* *---------------------------------------------------------------------- * * TreeColumn_InitWidget -- * * Perform column-related initialization when a new TreeCtrl is * created. * * Results: * A standard Tcl result. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ void TreeColumn_InitWidget( TreeCtrl *tree /* Widget info. */ ) { TreeColumn column; column = Column_Alloc(tree); column->id = -1; column->reqData.spanMin = column->reqData.spanMax = column; tree->columnTail = column; tree->nextColumnId = 0; tree->columnCount = 0; Column_Config(column, 0, NULL, TRUE); tree->columnDrag.optionTable = Tk_CreateOptionTable(tree->interp, dragSpecs); (void) Tk_InitOptions(tree->interp, (char *) tree, tree->columnDrag.optionTable, tree->tkwin); #ifdef UNIFORM_GROUP Tcl_InitHashTable(&tree->uniformGroupHash, TCL_STRING_KEYS); #endif tree->columnPriv = (TreeColumnPriv) ckalloc(sizeof(struct TreeColumnPriv_)); memset((char *) tree->columnPriv, 0, sizeof(struct TreeColumnPriv_)); } /* *---------------------------------------------------------------------- * * TreeColumn_FreeWidget -- * * Free column-related resources for a deleted TreeCtrl. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ void TreeColumn_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { TreeColumn column = tree->columns; struct TreeColumnPriv_ *priv = tree->columnPriv; while (column != NULL) { column = Column_Free(column); } Column_Free(tree->columnTail); tree->columnCount = 0; #ifdef UNIFORM_GROUP Tcl_DeleteHashTable(&tree->uniformGroupHash); #endif while (priv->spans != NULL) { ColumnSpan *cs = priv->spans; priv->spans = cs->next; if (cs->spansToRight.spans != NULL) ckfree((char *) cs->spansToRight.spans); ckfree((char *) cs); } while (priv->freeSpans != NULL) { ColumnSpan *cs = priv->freeSpans; priv->freeSpans = cs->next; if (cs->spansToRight.spans != NULL) ckfree((char *) cs->spansToRight.spans); ckfree((char *) cs); } ckfree((char *) priv); } /* *---------------------------------------------------------------------- * * TreeColumn_InitInterp -- * * Performs column-related initialization when the TkTreeCtrl * package is loaded into an interpreter. * * Results: * TCL_OK. * * Side effects: * Messes with the columnSpecs[] option array. * *---------------------------------------------------------------------- */ int TreeColumn_InitInterp( Tcl_Interp *interp /* Current interpreter. */ ) { StringTableCO_Init(columnSpecs, "-itemjustify", justifyStrings); TreeStyleCO_Init(columnSpecs, "-itemstyle", STATE_DOMAIN_ITEM); return TCL_OK; } tktreectrl-2.4.1/generic/tkTreeCtrl.c0000644000076400010400000040615511645124201020065 0ustar TimAdministrators/* * tkTreeCtrl.c -- * * This module implements treectrl widgets for the Tk toolkit. * * Copyright (c) 2002-2011 Tim Baker * Copyright (c) 2002-2003 Christian Krone * Copyright (c) 2003-2005 ActiveState, a division of Sophos */ #include "tkTreeCtrl.h" #ifdef WIN32 #include #endif #if defined(MAC_TK_CARBON) #include #endif #if defined(MAC_TK_COCOA) #import #endif /* * TIP #116 altered Tk_PhotoPutBlock API to add interp arg. * We need to remove that for compiling with 8.4. */ #if (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 5) #define TK_PHOTOPUTBLOCK(interp, hdl, blk, x, y, w, h, cr) \ Tk_PhotoPutBlock(hdl, blk, x, y, w, h, cr) #define TK_PHOTOPUTZOOMEDBLOCK(interp, hdl, blk, x, y, w, h, \ zx, zy, sx, sy, cr) \ Tk_PhotoPutZoomedBlock(hdl, blk, x, y, w, h, \ zx, zy, sx, sy, cr) #else #define TK_PHOTOPUTBLOCK Tk_PhotoPutBlock #define TK_PHOTOPUTZOOMEDBLOCK Tk_PhotoPutZoomedBlock #endif /* This structure is used for reference-counted images. */ typedef struct TreeImageRef { int count; /* Reference count. */ Tk_Image image; /* Image token. */ Tcl_HashEntry *hPtr; /* Entry in tree->imageNameHash. */ } TreeImageRef; static CONST char *bgModeST[] = { "column", "order", "ordervisible", "row", #ifdef DEPRECATED "index", "visindex", #endif (char *) NULL }; static CONST char *columnResizeModeST[] = { "proxy", "realtime", (char *) NULL }; static CONST char *doubleBufferST[] = { "none", "item", "window", (char *) NULL }; static CONST char *lineStyleST[] = { "dot", "solid", (char *) NULL }; static CONST char *orientStringTable[] = { "horizontal", "vertical", (char *) NULL }; static Tk_OptionSpec optionSpecs[] = { {TK_OPTION_BORDER, "-background", "background", "Background", "white", -1, Tk_Offset(TreeCtrl, border), 0, (ClientData) "white", TREE_CONF_REDISPLAY}, {TK_OPTION_STRING, "-backgroundimage", "backgroundImage", "BackgroundImage", (char *) NULL, -1, Tk_Offset(TreeCtrl, backgroundImageString), TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_BG_IMAGE | TREE_CONF_REDISPLAY}, {TK_OPTION_STRING_TABLE, "-backgroundmode", "backgroundMode", "BackgroundMode", "row", -1, Tk_Offset(TreeCtrl, backgroundMode), 0, (ClientData) bgModeST, TREE_CONF_REDISPLAY}, {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth"}, {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) "-background"}, {TK_OPTION_SYNONYM, "-bgimage", (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) "-backgroundimage"}, {TK_OPTION_ANCHOR, "-bgimageanchor", "bgImageAnchor", "BgImageAnchor", "nw", -1, Tk_Offset(TreeCtrl, bgImageAnchor), 0, (ClientData) NULL, TREE_CONF_BGIMGOPT | TREE_CONF_REDISPLAY}, {TK_OPTION_BOOLEAN, "-bgimageopaque", "bgImageOpaque", "BgImageOpaque", "1", -1, Tk_Offset(TreeCtrl, bgImageOpaque), 0, (ClientData) NULL, TREE_CONF_BGIMGOPT | TREE_CONF_REDISPLAY}, {TK_OPTION_STRING, "-bgimagescroll", "bgImageScroll", "BgImageScroll", "xy", Tk_Offset(TreeCtrl, bgImageScrollObj), -1, 0, (ClientData) NULL, TREE_CONF_BGIMGOPT | TREE_CONF_REDISPLAY}, {TK_OPTION_STRING, "-bgimagetile", "bgImageTile", "BgImageTile", "xy", Tk_Offset(TreeCtrl, bgImageTileObj), -1, 0, (ClientData) NULL, TREE_CONF_BGIMGOPT | TREE_CONF_REDISPLAY}, {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_LISTBOX_BORDER_WIDTH, Tk_Offset(TreeCtrl, borderWidthObj), Tk_Offset(TreeCtrl, borderWidth), 0, (ClientData) NULL, TREE_CONF_BORDERS | TREE_CONF_RELAYOUT}, {TK_OPTION_CUSTOM, "-buttonbitmap", "buttonBitmap", "ButtonBitmap", (char *) NULL, /* DEFAULT VALUE IS INITIALIZED LATER */ Tk_Offset(TreeCtrl, buttonBitmap.obj), Tk_Offset(TreeCtrl, buttonBitmap), TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_BUTTON | TREE_CONF_BUTBMP | TREE_CONF_RELAYOUT}, {TK_OPTION_COLOR, "-buttoncolor", "buttonColor", "ButtonColor", "#808080", -1, Tk_Offset(TreeCtrl, buttonColor), 0, (ClientData) NULL, TREE_CONF_BUTTON | TREE_CONF_REDISPLAY}, {TK_OPTION_CUSTOM, "-buttonimage", "buttonImage", "ButtonImage", (char *) NULL, /* DEFAULT VALUE IS INITIALIZED LATER */ Tk_Offset(TreeCtrl, buttonImage.obj), Tk_Offset(TreeCtrl, buttonImage), TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_BUTTON | TREE_CONF_BUTIMG | TREE_CONF_RELAYOUT}, {TK_OPTION_PIXELS, "-buttonsize", "buttonSize", "ButtonSize", "9", Tk_Offset(TreeCtrl, buttonSizeObj), Tk_Offset(TreeCtrl, buttonSize), 0, (ClientData) NULL, TREE_CONF_BUTTON | TREE_CONF_RELAYOUT}, {TK_OPTION_PIXELS, "-buttonthickness", "buttonThickness", "ButtonThickness", "1", Tk_Offset(TreeCtrl, buttonThicknessObj), Tk_Offset(TreeCtrl, buttonThickness), 0, (ClientData) NULL, TREE_CONF_BUTTON | TREE_CONF_REDISPLAY}, {TK_OPTION_BOOLEAN, "-buttontracking", "buttonTracking", "ButtonTracking", (char *) NULL, /* DEFAULT VALUE IS INITIALIZED LATER */ -1, Tk_Offset(TreeCtrl, buttonTracking), 0, (ClientData) NULL, 0}, {TK_OPTION_CUSTOM, "-canvaspadx", "canvasPadX", "CanvasPadX", "0", Tk_Offset(TreeCtrl, canvasPadXObj), Tk_Offset(TreeCtrl, canvasPadX), 0, (ClientData) &TreeCtrlCO_pad, TREE_CONF_RELAYOUT}, {TK_OPTION_CUSTOM, "-canvaspady", "canvasPadY", "CanvasPadY", "0", Tk_Offset(TreeCtrl, canvasPadYObj), Tk_Offset(TreeCtrl, canvasPadY), 0, (ClientData) &TreeCtrlCO_pad, TREE_CONF_RELAYOUT}, {TK_OPTION_STRING, "-columnprefix", "columnPrefix", "ColumnPrefix", "", -1, Tk_Offset(TreeCtrl, columnPrefix), 0, (ClientData) NULL, 0}, {TK_OPTION_PIXELS, "-columnproxy", "columnProxy", "ColumnProxy", (char *) NULL, Tk_Offset(TreeCtrl, columnProxy.xObj), Tk_Offset(TreeCtrl, columnProxy.x), TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_PROXY}, {TK_OPTION_STRING_TABLE, "-columnresizemode", "columnResizeMode", "ColumnResizeMode", "realtime", -1, Tk_Offset(TreeCtrl, columnResizeMode), 0, (ClientData) columnResizeModeST, 0}, {TK_OPTION_BOOLEAN, "-columntagexpr", "columnTagExpr", "ColumnTagExpr", "1", -1, Tk_Offset(TreeCtrl, columnTagExpr), 0, (ClientData) NULL, 0}, {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", (char *) NULL, -1, Tk_Offset(TreeCtrl, cursor), TK_OPTION_NULL_OK, (ClientData) NULL, 0}, #ifdef DEPRECATED {TK_OPTION_STRING, "-defaultstyle", "defaultStyle", "DefaultStyle", (char *) NULL, Tk_Offset(TreeCtrl, defaultStyle.stylesObj), -1, TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_DEFSTYLE}, {TK_OPTION_STRING_TABLE, "-doublebuffer", "doubleBuffer", "DoubleBuffer", "item", -1, Tk_Offset(TreeCtrl, doubleBuffer), 0, (ClientData) doubleBufferST, TREE_CONF_REDISPLAY}, #endif /* DEPRECATED */ {TK_OPTION_SYNONYM, "-fg", (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) "-foreground"}, {TK_OPTION_FONT, "-font", "font", "Font", DEF_LISTBOX_FONT, Tk_Offset(TreeCtrl, fontObj), Tk_Offset(TreeCtrl, tkfont), 0, (ClientData) NULL, TREE_CONF_FONT | TREE_CONF_RELAYOUT}, {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", DEF_LISTBOX_FG, Tk_Offset(TreeCtrl, fgObj), Tk_Offset(TreeCtrl, fgColorPtr), 0, (ClientData) NULL, TREE_CONF_FG | TREE_CONF_REDISPLAY}, {TK_OPTION_SYNONYM, "-headerfg", (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) "-headerforeground"}, {TK_OPTION_FONT, "-headerfont", "headerFont", "Font", (char *) NULL, /* DEFAULT VALUE IS INITIALIZED LATER */ Tk_Offset(TreeCtrl, headerFontObj), Tk_Offset(TreeCtrl, tkfontHeader), 0, (ClientData) NULL, TREE_CONF_FONT | TREE_CONF_RELAYOUT}, {TK_OPTION_COLOR, "-headerforeground", "headerForeground", "Foreground", DEF_BUTTON_FG, Tk_Offset(TreeCtrl, headerFgObj), Tk_Offset(TreeCtrl, defHeaderTextColor), 0, (ClientData) NULL, TREE_CONF_FG | TREE_CONF_REDISPLAY}, {TK_OPTION_PIXELS, "-height", "height", "Height", "200", Tk_Offset(TreeCtrl, heightObj), Tk_Offset(TreeCtrl, height), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_LISTBOX_HIGHLIGHT_BG, -1, Tk_Offset(TreeCtrl, highlightBgColorPtr), 0, (ClientData) NULL, TREE_CONF_REDISPLAY}, {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_LISTBOX_HIGHLIGHT, -1, Tk_Offset(TreeCtrl, highlightColorPtr), 0, (ClientData) NULL, TREE_CONF_REDISPLAY}, {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_LISTBOX_HIGHLIGHT_WIDTH, Tk_Offset(TreeCtrl, highlightWidthObj), Tk_Offset(TreeCtrl, highlightWidth), 0, (ClientData) NULL, TREE_CONF_BORDERS | TREE_CONF_RELAYOUT}, {TK_OPTION_PIXELS, "-indent", "indent", "Indent", "19", Tk_Offset(TreeCtrl, indentObj), Tk_Offset(TreeCtrl, indent), 0, (ClientData) NULL, TREE_CONF_INDENT | TREE_CONF_RELAYOUT}, {TK_OPTION_PIXELS, "-itemgapx", "itemGapX", "ItemGapX", "0", Tk_Offset(TreeCtrl, itemGapXObj), Tk_Offset(TreeCtrl, itemGapX), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_PIXELS, "-itemgapy", "itemGapY", "ItemGapY", "0", Tk_Offset(TreeCtrl, itemGapYObj), Tk_Offset(TreeCtrl, itemGapY), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_PIXELS, "-itemheight", "itemHeight", "ItemHeight", "0", Tk_Offset(TreeCtrl, itemHeightObj), Tk_Offset(TreeCtrl, itemHeight), 0, (ClientData) NULL, TREE_CONF_ITEMSIZE | TREE_CONF_RELAYOUT}, {TK_OPTION_STRING, "-itemprefix", "itemPrefix", "ItemPrefix", "", -1, Tk_Offset(TreeCtrl, itemPrefix), 0, (ClientData) NULL, 0}, {TK_OPTION_BOOLEAN, "-itemtagexpr", "itemTagExpr", "ItemTagExpr", "1", -1, Tk_Offset(TreeCtrl, itemTagExpr), 0, (ClientData) NULL, 0}, {TK_OPTION_PIXELS, "-itemwidth", "itemWidth", "ItemWidth", "", Tk_Offset(TreeCtrl, itemWidthObj), Tk_Offset(TreeCtrl, itemWidth), TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_ITEMSIZE | TREE_CONF_RELAYOUT}, {TK_OPTION_BOOLEAN, "-itemwidthequal", "itemWidthEqual", "ItemWidthEqual", "0", -1, Tk_Offset(TreeCtrl, itemWidthEqual), TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_ITEMSIZE | TREE_CONF_RELAYOUT}, {TK_OPTION_PIXELS, "-itemwidthmultiple", "itemWidthMultiple", "ItemWidthMultiple", "", Tk_Offset(TreeCtrl, itemWidMultObj), Tk_Offset(TreeCtrl, itemWidMult), TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_ITEMSIZE | TREE_CONF_RELAYOUT}, {TK_OPTION_COLOR, "-linecolor", "lineColor", "LineColor", "#808080", -1, Tk_Offset(TreeCtrl, lineColor), 0, (ClientData) NULL, TREE_CONF_LINE | TREE_CONF_REDISPLAY}, {TK_OPTION_STRING_TABLE, "-linestyle", "lineStyle", "LineStyle", "dot", -1, Tk_Offset(TreeCtrl, lineStyle), 0, (ClientData) lineStyleST, TREE_CONF_LINE | TREE_CONF_REDISPLAY}, {TK_OPTION_PIXELS, "-linethickness", "lineThickness", "LineThickness", "1", Tk_Offset(TreeCtrl, lineThicknessObj), Tk_Offset(TreeCtrl, lineThickness), 0, (ClientData) NULL, TREE_CONF_LINE | TREE_CONF_REDISPLAY}, {TK_OPTION_PIXELS, "-minitemheight", "minItemHeight", "MinItemHeight", "0", Tk_Offset(TreeCtrl, minItemHeightObj), Tk_Offset(TreeCtrl, minItemHeight), 0, (ClientData) NULL, TREE_CONF_ITEMSIZE | TREE_CONF_RELAYOUT}, {TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient", "vertical", -1, Tk_Offset(TreeCtrl, vertical), 0, (ClientData) orientStringTable, TREE_CONF_RELAYOUT}, {TK_OPTION_RELIEF, "-relief", "relief", "Relief", "sunken", -1, Tk_Offset(TreeCtrl, relief), 0, (ClientData) NULL, TREE_CONF_REDISPLAY}, {TK_OPTION_PIXELS, "-rowproxy", "rowProxy", "RowProxy", (char *) NULL, Tk_Offset(TreeCtrl, rowProxy.yObj), Tk_Offset(TreeCtrl, rowProxy.y), TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_PROXY}, {TK_OPTION_STRING, "-scrollmargin", "scrollMargin", "ScrollMargin", "0", Tk_Offset(TreeCtrl, scrollMargin), -1, 0, (ClientData) NULL, 0}, {TK_OPTION_STRING, "-selectmode", "selectMode", "SelectMode", DEF_LISTBOX_SELECT_MODE, -1, Tk_Offset(TreeCtrl, selectMode), TK_OPTION_NULL_OK, (ClientData) NULL, 0}, {TK_OPTION_BOOLEAN, "-showbuttons", "showButtons", "ShowButtons", "1", -1, Tk_Offset(TreeCtrl, showButtons), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_BOOLEAN, "-showheader", "showHeader", "ShowHeader", "1", -1, Tk_Offset(TreeCtrl, showHeader), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_BOOLEAN, "-showlines", "showLines", "ShowLines", (char *) NULL, /* DEFAULT VALUE IS INITIALIZED LATER */ -1, Tk_Offset(TreeCtrl, showLines), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_BOOLEAN, "-showroot", "showRoot", "ShowRoot", "1", -1, Tk_Offset(TreeCtrl, showRoot), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_BOOLEAN, "-showrootbutton", "showRootButton", "ShowRootButton", "0", -1, Tk_Offset(TreeCtrl, showRootButton), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_BOOLEAN, "-showrootchildbuttons", "showRootChildButtons", "ShowRootChildButtons", "1", -1, Tk_Offset(TreeCtrl, showRootChildButtons), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_BOOLEAN, "-showrootlines", "showRootLines", "ShowRootLines", "1", -1, Tk_Offset(TreeCtrl, showRootLines), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_LISTBOX_TAKE_FOCUS, -1, Tk_Offset(TreeCtrl, takeFocus), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_CUSTOM, "-treecolumn", "treeColumn", "TreeColumn", (char *) NULL, -1, Tk_Offset(TreeCtrl, columnTree), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_column_NOT_TAIL, TREE_CONF_RELAYOUT}, {TK_OPTION_BOOLEAN, "-usetheme", "useTheme", "UseTheme", "1", -1, Tk_Offset(TreeCtrl, useTheme), 0, (ClientData) NULL, TREE_CONF_THEME | TREE_CONF_RELAYOUT}, {TK_OPTION_PIXELS, "-width", "width", "Width", "200", Tk_Offset(TreeCtrl, widthObj), Tk_Offset(TreeCtrl, width), 0, (ClientData) NULL, TREE_CONF_RELAYOUT}, {TK_OPTION_STRING, "-wrap", "wrap", "Wrap", (char *) NULL, Tk_Offset(TreeCtrl, wrapObj), -1, TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_WRAP | TREE_CONF_RELAYOUT}, {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", (char *) NULL, -1, Tk_Offset(TreeCtrl, xScrollCmd), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING, "-xscrolldelay", "xScrollDelay", "ScrollDelay", "50", Tk_Offset(TreeCtrl, xScrollDelay), -1, TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_PIXELS, "-xscrollincrement", "xScrollIncrement", "ScrollIncrement", "0", -1, Tk_Offset(TreeCtrl, xScrollIncrement), 0, (ClientData) NULL, TREE_CONF_REDISPLAY}, {TK_OPTION_BOOLEAN, "-xscrollsmoothing", "xScrollSmoothing", "ScrollSmoothing", "0", -1, Tk_Offset(TreeCtrl, xScrollSmoothing), 0, (ClientData) NULL, TREE_CONF_REDISPLAY}, {TK_OPTION_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", (char *) NULL, -1, Tk_Offset(TreeCtrl, yScrollCmd), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_STRING, "-yscrolldelay", "yScrollDelay", "ScrollDelay", "50", Tk_Offset(TreeCtrl, yScrollDelay), -1, TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_PIXELS, "-yscrollincrement", "yScrollIncrement", "ScrollIncrement", "0", -1, Tk_Offset(TreeCtrl, yScrollIncrement), 0, (ClientData) NULL, TREE_CONF_REDISPLAY}, {TK_OPTION_BOOLEAN, "-yscrollsmoothing", "yScrollSmoothing", "ScrollSmoothing", "0", -1, Tk_Offset(TreeCtrl, yScrollSmoothing), 0, (ClientData) NULL, TREE_CONF_REDISPLAY}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, -1, -1, 0, (ClientData) NULL, 0} }; static Tk_OptionSpec debugSpecs[] = { {TK_OPTION_INT, "-displaydelay", (char *) NULL, (char *) NULL, "0", -1, Tk_Offset(TreeCtrl, debug.displayDelay), 0, (ClientData) NULL, 0}, {TK_OPTION_BOOLEAN, "-data", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeCtrl, debug.data), 0, (ClientData) NULL, 0}, {TK_OPTION_BOOLEAN, "-display", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeCtrl, debug.display), 0, (ClientData) NULL, 0}, {TK_OPTION_COLOR, "-drawcolor", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeCtrl, debug.drawColor), TK_OPTION_NULL_OK, (ClientData) NULL, 0}, {TK_OPTION_BOOLEAN, "-enable", (char *) NULL, (char *) NULL, "0", -1, Tk_Offset(TreeCtrl, debug.enable), 0, (ClientData) NULL, 0}, {TK_OPTION_COLOR, "-erasecolor", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeCtrl, debug.eraseColor), TK_OPTION_NULL_OK, (ClientData) NULL, 0}, {TK_OPTION_BOOLEAN, "-span", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeCtrl, debug.span), 0, (ClientData) NULL, 0}, {TK_OPTION_BOOLEAN, "-textlayout", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeCtrl, debug.textLayout), 0, (ClientData) NULL, 0}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, -1, -1, 0, (ClientData) NULL, 0} }; static int TreeWidgetCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int TreeConfigure(Tcl_Interp *interp, TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[], int createFlag); static void TreeEventProc(ClientData clientData, XEvent * eventPtr); static void TreeDestroy(char *memPtr); static void TreeCmdDeletedProc(ClientData clientData); static void TreeWorldChanged(ClientData instanceData); static void TreeComputeGeometry(TreeCtrl *tree); static int TreeIdentifyCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]); static int TreeSeeCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]); static int TreeSelectionCmd(Tcl_Interp *interp, TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]); static int TreeDebugCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static Tk_ClassProcs treectrlClass = { sizeof(Tk_ClassProcs), /* size */ TreeWorldChanged, /* worldChangedProc. */ NULL, /* createProc. */ NULL /* modalProc. */ }; /* *-------------------------------------------------------------- * * TreeObjCmd -- * * This procedure is invoked to process the [treectrl] Tcl * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int TreeObjCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree; Tk_Window tkwin; Tk_OptionTable optionTable; TreeStateDomain *domainPtr; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); return TCL_ERROR; } tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), Tcl_GetStringFromObj(objv[1], NULL), (char *) NULL); if (tkwin == NULL) { return TCL_ERROR; } optionTable = Tk_CreateOptionTable(interp, optionSpecs); tree = (TreeCtrl *) ckalloc(sizeof(TreeCtrl)); memset(tree, '\0', sizeof(TreeCtrl)); tree->tkwin = tkwin; tree->display = Tk_Display(tkwin); tree->interp = interp; tree->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(tree->tkwin), TreeWidgetCmd, (ClientData) tree, TreeCmdDeletedProc); tree->optionTable = optionTable; tree->relief = TK_RELIEF_SUNKEN; tree->prevWidth = Tk_Width(tkwin); tree->prevHeight = Tk_Height(tkwin); tree->updateIndex = 1; domainPtr = &tree->stateDomain[STATE_DOMAIN_ITEM]; domainPtr->name = "item"; domainPtr->stateNames[0] = "open"; domainPtr->stateNames[1] = "selected"; domainPtr->stateNames[2] = "enabled"; domainPtr->stateNames[3] = "active"; domainPtr->stateNames[4] = "focus"; domainPtr->staticCount = 5; domainPtr = &tree->stateDomain[STATE_DOMAIN_HEADER]; domainPtr->name = "header"; domainPtr->stateNames[0] = "background"; domainPtr->stateNames[1] = "focus"; domainPtr->stateNames[2] = "active"; domainPtr->stateNames[3] = "normal"; domainPtr->stateNames[4] = "pressed"; domainPtr->stateNames[5] = "up"; domainPtr->stateNames[6] = "down"; domainPtr->staticCount = 7; tree->configStateDomain = -1; Tcl_InitHashTable(&tree->selection, TCL_ONE_WORD_KEYS); /* Do this before Tree_InitColumns() which does Tk_InitOptions(), which * calls Tk_GetOption() which relies on the window class */ Tk_SetClass(tkwin, "TreeCtrl"); Tk_SetClassProcs(tkwin, &treectrlClass, (ClientData) tree); tree->debug.optionTable = Tk_CreateOptionTable(interp, debugSpecs); (void) Tk_InitOptions(interp, (char *) tree, tree->debug.optionTable, tkwin); Tcl_InitHashTable(&tree->itemHash, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&tree->itemSpansHash, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&tree->elementHash, TCL_STRING_KEYS); Tcl_InitHashTable(&tree->styleHash, TCL_STRING_KEYS); Tcl_InitHashTable(&tree->imageNameHash, TCL_STRING_KEYS); Tcl_InitHashTable(&tree->imageTokenHash, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&tree->gradientHash, TCL_STRING_KEYS); TreeItemList_Init(tree, &tree->preserveItemList, 0); #ifdef ALLOC_HAX tree->allocData = TreeAlloc_Init(); #endif TreeColumn_InitWidget(tree); TreeItem_InitWidget(tree); TreeNotify_InitWidget(tree); (void) TreeElement_InitWidget(tree); (void) TreeStyle_InitWidget(tree); TreeMarquee_InitWidget(tree); TreeDragImage_InitWidget(tree); TreeDisplay_InitWidget(tree); TreeGradient_InitWidget(tree); TreeHeader_InitWidget(tree); Tk_CreateEventHandler(tree->tkwin, #ifdef USE_TTK ExposureMask|StructureNotifyMask|FocusChangeMask|ActivateMask|VirtualEventMask, #else ExposureMask|StructureNotifyMask|FocusChangeMask|ActivateMask, #endif TreeEventProc, (ClientData) tree); /* Must do this on Unix because Tk_GCForColor() uses * Tk_WindowId(tree->tkwin) */ Tk_MakeWindowExist(tree->tkwin); /* Window must exist on Win32. */ TreeTheme_InitWidget(tree); /* * Keep a hold of the associated tkwin until we destroy the listbox, * otherwise Tk might free it while we still need it. */ Tcl_Preserve((ClientData) tkwin); if (Tree_InitOptions(tree, STATE_DOMAIN_ITEM, tree, optionTable) != TCL_OK) { Tk_DestroyWindow(tree->tkwin); return TCL_ERROR; } if (TreeConfigure(interp, tree, objc - 2, objv + 2, TRUE) != TCL_OK) { Tk_DestroyWindow(tree->tkwin); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(tree->tkwin), -1)); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeArea_FromObj -- * * Get a TREE_AREA_xxx constant from a Tcl_Obj string rep. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeArea_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *objPtr, /* Object whose string rep is used. */ int *areaPtr /* Returned TREE_AREA_xxx constant. */ ) { static CONST char *areaName[] = { "content", "header", "header.left", "header.none", "header.right", "left", "right", (char *) NULL }; static CONST int area[] = { TREE_AREA_CONTENT, TREE_AREA_HEADER, TREE_AREA_HEADER_LEFT, TREE_AREA_HEADER_NONE, TREE_AREA_HEADER_RIGHT, TREE_AREA_LEFT, TREE_AREA_RIGHT }; int index; if (Tcl_GetIndexFromObj(tree->interp, objPtr, areaName, "area", 0, &index) != TCL_OK) { return TCL_ERROR; } (*areaPtr) = area[index]; return TCL_OK; } #define W2Cx(x) ((x) + tree->xOrigin) #define C2Wx(x) ((x) - tree->xOrigin) #define C2Ox(x) ((x) - Tree_ContentLeft(tree)) #define W2Cy(y) ((y) + tree->yOrigin) #define C2Wy(y) ((y) - tree->yOrigin) #define C2Oy(y) ((y) - Tree_ContentTop(tree)) /* *-------------------------------------------------------------- * * TreeWidgetCmd -- * * This procedure is invoked to process the Tcl command * that corresponds to a 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. * *-------------------------------------------------------------- */ static int TreeWidgetCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; int result = TCL_OK; static CONST char *commandName[] = { "activate", "bbox", "canvasx", "canvasy", "cget", #ifdef DEPRECATED "collapse", #endif "column", #ifdef DEPRECATED "compare", #endif "configure", "contentbox", "debug", "depth", "dragimage", "element", #ifdef DEPRECATED "expand", #endif "gradient", "header", "identify", "index", "item", "marquee", "notify", #ifdef DEPRECATED "numcolumns", "numitems", #endif "orphans", #ifdef DEPRECATED "range", #endif "scan", "see", "selection", "state", "style", "theme", #ifdef DEPRECATED "toggle", #endif "xview", "yview", (char *) NULL }; enum { COMMAND_ACTIVATE, COMMAND_BBOX, COMMAND_CANVASX, COMMAND_CANVASY, COMMAND_CGET, #ifdef DEPRECATED COMMAND_COLLAPSE, #endif COMMAND_COLUMN, #ifdef DEPRECATED COMMAND_COMPARE, #endif COMMAND_CONFIGURE, COMMAND_CONTENTBOX, COMMAND_DEBUG, COMMAND_DEPTH, COMMAND_DRAGIMAGE, COMMAND_ELEMENT, #ifdef DEPRECATED COMMAND_EXPAND, #endif COMMAND_GRADIENT, COMMAND_HEADER, COMMAND_IDENTIFY, COMMAND_INDEX, COMMAND_ITEM, COMMAND_MARQUEE, COMMAND_NOTIFY, #ifdef DEPRECATED COMMAND_NUMCOLUMNS, COMMAND_NUMITEMS, #endif COMMAND_ORPHANS, #ifdef DEPRECATED COMMAND_RANGE, #endif COMMAND_SCAN, COMMAND_SEE, COMMAND_SELECTION, COMMAND_STATE, COMMAND_STYLE, COMMAND_THEME, #ifdef DEPRECATED COMMAND_TOGGLE, #endif COMMAND_XVIEW, COMMAND_YVIEW }; Tcl_Obj *resultObjPtr; int index; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], commandName, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } Tcl_Preserve((ClientData) tree); Tree_PreserveItems(tree); switch (index) { case COMMAND_ACTIVATE: { TreeItem active, item; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "item"); goto error; } if (TreeItem_FromObj(tree, objv[2], &item, IFO_NOT_NULL) != TCL_OK) { goto error; } if (item != tree->activeItem) { TreeRectangle tr; active = tree->activeItem; TreeItem_ChangeState(tree, active, STATE_ITEM_ACTIVE, 0); tree->activeItem = item; TreeItem_ChangeState(tree, tree->activeItem, 0, STATE_ITEM_ACTIVE); /* FIXME: is it onscreen? */ /* FIXME: what if only lock columns displayed? */ if (Tree_ItemBbox(tree, item, COLUMN_LOCK_NONE, &tr) >= 0) { Tk_SetCaretPos(tree->tkwin, tr.x - tree->xOrigin, tr.y - tree->yOrigin, tr.height); } TreeNotify_ActiveItem(tree, active, item); } break; } /* .t bbox ?area? */ case COMMAND_BBOX: { TreeRectangle tr; if (objc > 3) { Tcl_WrongNumArgs(interp, 2, objv, "?area?"); goto error; } if (objc == 3) { int area; if (TreeArea_FromObj(tree, objv[2], &area) != TCL_OK) { goto error; } if (!Tree_AreaBbox(tree, area, &tr)) break; } else { TreeRect_SetXYWH(tr, 0, 0, Tk_Width(tree->tkwin), Tk_Height(tree->tkwin)); } FormatResult(interp, "%d %d %d %d", TreeRect_Left(tr), TreeRect_Top(tr), TreeRect_Right(tr), TreeRect_Bottom(tr)); break; } case COMMAND_CANVASX: { int x; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "x"); goto error; } if (Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) goto error; Tcl_SetObjResult(interp, Tcl_NewIntObj(x + tree->xOrigin)); break; } case COMMAND_CANVASY: { int y; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "y"); goto error; } if (Tcl_GetIntFromObj(interp, objv[2], &y) != TCL_OK) goto error; Tcl_SetObjResult(interp, Tcl_NewIntObj(y + tree->yOrigin)); break; } case COMMAND_CGET: { if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "option"); goto error; } resultObjPtr = Tk_GetOptionValue(interp, (char *) tree, tree->optionTable, objv[2], tree->tkwin); if (resultObjPtr == NULL) { result = TCL_ERROR; } else { Tcl_SetObjResult(interp, resultObjPtr); } break; } case COMMAND_CONFIGURE: { resultObjPtr = NULL; if (objc <= 3) { resultObjPtr = Tk_GetOptionInfo(interp, (char *) tree, tree->optionTable, (objc == 2) ? (Tcl_Obj *) NULL : objv[2], tree->tkwin); if (resultObjPtr == NULL) { result = TCL_ERROR; } else { Tcl_SetObjResult(interp, resultObjPtr); } } else { result = TreeConfigure(interp, tree, objc - 2, objv + 2, FALSE); } break; } case COMMAND_CONTENTBOX: { TreeRectangle tr; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL); goto error; } if (Tree_AreaBbox(tree, TREE_AREA_CONTENT, &tr)) { FormatResult(interp, "%d %d %d %d", TreeRect_Left(tr), TreeRect_Top(tr), TreeRect_Right(tr), TreeRect_Bottom(tr)); } break; } #ifdef DEPRECATED /* T expand ?-recurse? I ... */ case COMMAND_COLLAPSE: case COMMAND_EXPAND: case COMMAND_TOGGLE: { char *s; int recurse = 0; int mode = 0; /* lint */ int i, j, count, len; TreeItemList items, item2s; TreeItem _item; ItemForEach iter; if (objc == 2) break; s = Tcl_GetStringFromObj(objv[2], &len); if (s[0] == '-') { if (strncmp(s, "-recurse", len)) { FormatResult(interp, "bad option \"%s\": must be -recurse", s); goto error; } if (objc == 3) break; recurse = 1; } switch (index) { case COMMAND_COLLAPSE: mode = 0; break; case COMMAND_EXPAND: mode = 1; break; case COMMAND_TOGGLE: mode = -1; break; } for (i = 2 + recurse; i < objc; i++) { if (TreeItemList_FromObj(tree, objv[i], &items, IFO_NOT_NULL) != TCL_OK) { goto error; } TreeItemList_Init(tree, &item2s, 0); ITEM_FOR_EACH(_item, &items, NULL, &iter) { TreeItemList_Append(&item2s, _item); if (!iter.all && recurse) { TreeItem_ListDescendants(tree, _item, &item2s); } } count = TreeItemList_Count(&item2s); for (j = 0; j < count; j++) { _item = TreeItemList_Nth(&item2s, j); TreeItem_OpenClose(tree, _item, mode); } TreeItemList_Free(&items); TreeItemList_Free(&item2s); } #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif break; } #endif /* DEPRECATED */ case COMMAND_COLUMN: { result = TreeColumnCmd(clientData, interp, objc, objv); break; } #ifdef DEPRECATED case COMMAND_COMPARE: { TreeItem item1, item2; static CONST char *opName[] = { "<", "<=", "==", ">=", ">", "!=", NULL }; int op, compare = 0, index1, index2; if (objc != 5) { Tcl_WrongNumArgs(interp, 2, objv, "item1 op item2"); goto error; } if (TreeItem_FromObj(tree, objv[2], &item1, IFO_NOT_NULL) != TCL_OK) goto error; if (Tcl_GetIndexFromObj(interp, objv[3], opName, "comparison operator", 0, &op) != TCL_OK) goto error; if (TreeItem_FromObj(tree, objv[4], &item2, IFO_NOT_NULL) != TCL_OK) goto error; if (TreeItem_RootAncestor(tree, item1) != TreeItem_RootAncestor(tree, item2)) { FormatResult(interp, "item %s%d and item %s%d don't share a common ancestor", tree->itemPrefix, TreeItem_GetID(tree, item1), tree->itemPrefix, TreeItem_GetID(tree, item2)); goto error; } TreeItem_ToIndex(tree, item1, &index1, NULL); TreeItem_ToIndex(tree, item2, &index2, NULL); switch (op) { case 0: compare = index1 < index2; break; case 1: compare = index1 <= index2; break; case 2: compare = index1 == index2; break; case 3: compare = index1 >= index2; break; case 4: compare = index1 > index2; break; case 5: compare = index1 != index2; break; } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(compare)); break; } #endif /* DEPRECATED */ case COMMAND_DEBUG: { result = TreeDebugCmd(clientData, interp, objc, objv); break; } case COMMAND_DEPTH: { TreeItem item; int depth; if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 2, objv, "?item?"); goto error; } if (objc == 3) { if (TreeItem_FromObj(tree, objv[2], &item, IFO_NOT_NULL) != TCL_OK) goto error; depth = TreeItem_GetDepth(tree, item); if (TreeItem_RootAncestor(tree, item) == tree->root) depth++; Tcl_SetObjResult(interp, Tcl_NewIntObj(depth)); break; } Tree_UpdateItemIndex(tree); Tcl_SetObjResult(interp, Tcl_NewIntObj(tree->depth + 1)); break; } case COMMAND_DRAGIMAGE: { result = TreeDragImageCmd(clientData, interp, objc, objv); break; } case COMMAND_ELEMENT: { result = TreeElementCmd(clientData, interp, objc, objv); break; } case COMMAND_GRADIENT: { result = TreeGradientCmd(clientData, interp, objc, objv); break; } case COMMAND_HEADER: { result = TreeHeaderCmd(clientData, interp, objc, objv); break; } case COMMAND_IDENTIFY: { result = TreeIdentifyCmd(tree, objc, objv); break; } #ifdef DEPRECATED case COMMAND_INDEX: { TreeItem item; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "item"); goto error; } if (TreeItem_FromObj(tree, objv[2], &item, 0) != TCL_OK) { goto error; } if (item != NULL) Tcl_SetObjResult(interp, TreeItem_ToObj(tree, item)); break; } #endif /* DEPRECATED */ case COMMAND_ITEM: { result = TreeItemCmd(clientData, interp, objc, objv); break; } case COMMAND_MARQUEE: { result = TreeMarqueeCmd(clientData, interp, objc, objv); break; } case COMMAND_NOTIFY: { result = TreeNotifyCmd(clientData, interp, objc, objv); break; } #ifdef DEPRECATED case COMMAND_NUMCOLUMNS: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL); goto error; } Tcl_SetObjResult(interp, Tcl_NewIntObj(tree->columnCount)); break; } case COMMAND_NUMITEMS: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL); goto error; } Tcl_SetObjResult(interp, Tcl_NewIntObj(tree->itemCount)); break; } #endif /* DEPRECATED */ case COMMAND_ORPHANS: { Tcl_HashEntry *hPtr; Tcl_HashSearch search; Tcl_Obj *listObj; TreeItem item; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL); goto error; } /* Pretty slow. Could keep a hash table of orphans */ listObj = Tcl_NewListObj(0, NULL); hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); if ((item != tree->root) && (TreeItem_GetParent(tree, item) == NULL)) { Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, item)); } hPtr = Tcl_NextHashEntry(&search); } Tcl_SetObjResult(interp, listObj); break; } #ifdef DEPRECATED case COMMAND_RANGE: { TreeItem item, itemFirst, itemLast; Tcl_Obj *listObj; if (objc != 4) { Tcl_WrongNumArgs(interp, 2, objv, "first last"); goto error; } if (TreeItem_FromObj(tree, objv[2], &itemFirst, IFO_NOT_NULL) != TCL_OK) goto error; if (TreeItem_FromObj(tree, objv[3], &itemLast, IFO_NOT_NULL) != TCL_OK) goto error; if (TreeItem_FirstAndLast(tree, &itemFirst, &itemLast) == 0) goto error; listObj = Tcl_NewListObj(0, NULL); item = itemFirst; while (item != NULL) { Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, item)); if (item == itemLast) break; item = TreeItem_Next(tree, item); } Tcl_SetObjResult(interp, listObj); break; } #endif /* DEPRECATED */ case COMMAND_SCAN: { static CONST char *optionName[] = { "dragto", "mark", (char *) NULL }; int x, y, gain = 10, xOrigin, yOrigin; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?"); goto error; } if (Tcl_GetIndexFromObj(interp, objv[2], optionName, "option", 2, &index) != TCL_OK) goto error; switch (index) { /* T scan dragto x y ?gain? */ case 0: if ((objc < 5) || (objc > 6)) { Tcl_WrongNumArgs(interp, 3, objv, "x y ?gain?"); goto error; } if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)) goto error; if (objc == 6) { if (Tcl_GetIntFromObj(interp, objv[5], &gain) != TCL_OK) goto error; } xOrigin = tree->scanXOrigin - gain * (x - tree->scanX); yOrigin = tree->scanYOrigin - gain * (y - tree->scanY); Tree_SetScrollSmoothingX(tree, TRUE); Tree_SetScrollSmoothingY(tree, TRUE); Tree_SetOriginX(tree, xOrigin); Tree_SetOriginY(tree, yOrigin); break; /* T scan mark x y ?gain? */ case 1: if (objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "x y"); goto error; } if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)) goto error; tree->scanX = x; tree->scanY = y; tree->scanXOrigin = tree->xOrigin; tree->scanYOrigin = tree->yOrigin; break; } break; } case COMMAND_SEE: { result = TreeSeeCmd(tree, objc, objv); break; } case COMMAND_SELECTION: { result = TreeSelectionCmd(interp, tree, objc, objv); break; } case COMMAND_STATE: { result = Tree_StateCmd(tree, STATE_DOMAIN_ITEM, objc, objv); break; } case COMMAND_STYLE: { result = TreeStyleCmd(clientData, interp, objc, objv); break; } case COMMAND_THEME: { result = TreeThemeCmd(tree, objc, objv); break; } case COMMAND_XVIEW: { result = TreeXviewCmd(tree, objc, objv); break; } case COMMAND_YVIEW: { result = TreeYviewCmd(tree, objc, objv); break; } } Tree_ReleaseItems(tree); Tcl_Release((ClientData) tree); return result; error: Tree_ReleaseItems(tree); Tcl_Release((ClientData) tree); return TCL_ERROR; } /* *-------------------------------------------------------------- * * TreeConfigure -- * * This procedure is called to process an argv/argc list, plus * the Tk option database, in order to configure (or reconfigure) * a treectrl widget. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then the interp's result contains an error message. * * Side effects: * Configuration information, such as colors, border width, * etc. get set for tree; old resources get freed, * if there were any. * *-------------------------------------------------------------- */ static int TreeConfigure( Tcl_Interp *interp, /* Current interpreter. */ TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int createFlag /* TRUE if the widget is being created. */ ) { int error; Tcl_Obj *errorResult = NULL; TreeCtrl saved; Tk_SavedOptions savedOptions; int oldShowRoot = tree->showRoot; int buttonWidth, buttonHeight; int mask, maskFree = 0; XGCValues gcValues; unsigned long gcMask; /* Init these to prevent compiler warnings */ saved.backgroundImage = NULL; #ifdef DEPRECATED saved.defaultStyle.styles = NULL; saved.defaultStyle.numStyles = 0; #endif saved.wrapMode = TREE_WRAP_NONE; saved.wrapArg = 0; saved.bgImageScroll = tree->bgImageScroll; saved.bgImageTile = tree->bgImageTile; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, STATE_DOMAIN_ITEM, tree, tree->optionTable, objc, objv, &savedOptions, &mask) != TCL_OK) { mask = 0; continue; } /* Wouldn't have to do this if Tk_InitOptions() would return * a mask of configured options like Tk_SetOptions() does. */ if (createFlag) { if (tree->backgroundImageString != NULL) mask |= TREE_CONF_BG_IMAGE; if (tree->buttonBitmap.obj != NULL) mask |= TREE_CONF_BUTBMP; if (tree->buttonImage.obj != NULL) mask |= TREE_CONF_BUTIMG; #ifdef DEPRECATED if (tree->defaultStyle.stylesObj != NULL) mask |= TREE_CONF_DEFSTYLE; #endif if (tree->wrapObj != NULL) mask |= TREE_CONF_WRAP; if (!ObjectIsEmpty(tree->itemWidthObj)) mask |= TREE_CONF_ITEMSIZE; if (!ObjectIsEmpty(tree->itemWidMultObj)) mask |= TREE_CONF_ITEMSIZE; mask |= TREE_CONF_BGIMGOPT; } /* * Step 1: Save old values */ if (mask & TREE_CONF_BG_IMAGE) saved.backgroundImage = tree->backgroundImage; #ifdef DEPRECATED if (mask & TREE_CONF_DEFSTYLE) { saved.defaultStyle.styles = tree->defaultStyle.styles; saved.defaultStyle.numStyles = tree->defaultStyle.numStyles; } #endif if (mask & TREE_CONF_WRAP) { saved.wrapMode = tree->wrapMode; saved.wrapArg = tree->wrapArg; } /* * Step 2: Process new values */ if (mask & TREE_CONF_BG_IMAGE) { if (tree->backgroundImageString == NULL) { tree->backgroundImage = NULL; } else { Tk_Image image = Tree_GetImage(tree, tree->backgroundImageString); if (image == NULL) continue; tree->backgroundImage = image; maskFree |= TREE_CONF_BG_IMAGE; } } if (mask & TREE_CONF_BGIMGOPT) { static const CharFlag scrollFlags[] = { { 'x', BGIMG_SCROLL_X }, { 'y', BGIMG_SCROLL_Y }, { 0, 0 } }; if (Tree_GetFlagsFromObj(tree, tree->bgImageScrollObj, "scroll value", scrollFlags, &tree->bgImageScroll) != TCL_OK) { continue; } } if (mask & TREE_CONF_BGIMGOPT) { static const CharFlag tileFlags[] = { { 'x', BGIMG_TILE_X }, { 'y', BGIMG_TILE_Y }, { 0, 0 } }; if (Tree_GetFlagsFromObj(tree, tree->bgImageTileObj, "tile value", tileFlags, &tree->bgImageTile) != TCL_OK) { continue; } } #ifdef DEPRECATED if (mask & TREE_CONF_DEFSTYLE) { if (tree->defaultStyle.stylesObj == NULL) { tree->defaultStyle.styles = NULL; tree->defaultStyle.numStyles = 0; } else { int i, listObjc; Tcl_Obj **listObjv; TreeStyle style; if ((Tcl_ListObjGetElements(interp, tree->defaultStyle.stylesObj, &listObjc, &listObjv) != TCL_OK)) continue; tree->defaultStyle.styles = (TreeStyle *) ckalloc(sizeof(TreeStyle) * listObjc); tree->defaultStyle.numStyles = listObjc; for (i = 0; i < listObjc; i++) { if (ObjectIsEmpty(listObjv[i])) { style = NULL; } else { if (TreeStyle_FromObj(tree, listObjv[i], &style) != TCL_OK) { ckfree((char *) tree->defaultStyle.styles); break; } if (TreeStyle_GetStateDomain(tree, style) != STATE_DOMAIN_ITEM) { FormatResult(interp, "expected state domain \"item\" but got \"%s\"", tree->stateDomain[TreeStyle_GetStateDomain(tree, style)].name); ckfree((char *) tree->defaultStyle.styles); break; } } tree->defaultStyle.styles[i] = style; } if (i < listObjc) continue; maskFree |= TREE_CONF_DEFSTYLE; } } #endif /* DEPRECATED */ /* Parse -wrap string into wrapMode and wrapArg */ if (mask & TREE_CONF_WRAP) { int listObjc; Tcl_Obj **listObjv; if (tree->wrapObj == NULL) { tree->wrapMode = TREE_WRAP_NONE; tree->wrapArg = 0; } else { int len0, len1; char *s0, *s1, ch0, ch1; if ((Tcl_ListObjGetElements(interp, tree->wrapObj, &listObjc, &listObjv) != TCL_OK) || (listObjc > 2)) { badWrap: FormatResult(interp, "bad wrap \"%s\"", Tcl_GetString(tree->wrapObj)); continue; } if (listObjc == 1) { s0 = Tcl_GetStringFromObj(listObjv[0], &len0); ch0 = s0[0]; if ((ch0 == 'w') && !strncmp(s0, "window", len0)) { tree->wrapMode = TREE_WRAP_WINDOW; tree->wrapArg = 0; } else goto badWrap; } else { s1 = Tcl_GetStringFromObj(listObjv[1], &len1); ch1 = s1[0]; if ((ch1 == 'i') && !strncmp(s1, "items", len1)) { int n; if ((Tcl_GetIntFromObj(interp, listObjv[0], &n) != TCL_OK) || (n < 0)) { goto badWrap; } tree->wrapMode = TREE_WRAP_ITEMS; tree->wrapArg = n; } else if ((ch1 == 'p') && !strncmp(s1, "pixels", len1)) { int n; if (Tk_GetPixelsFromObj(interp, tree->tkwin, listObjv[0], &n) != TCL_OK) { goto badWrap; } tree->wrapMode = TREE_WRAP_PIXELS; tree->wrapArg = n; } else goto badWrap; } } } /* * Step 3: Free saved values */ if (mask & TREE_CONF_BG_IMAGE) { if (saved.backgroundImage != NULL) Tree_FreeImage(tree, saved.backgroundImage); } #ifdef DEPRECATED if (mask & TREE_CONF_DEFSTYLE) { if (saved.defaultStyle.styles != NULL) ckfree((char *) saved.defaultStyle.styles); } #endif Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); /* * Free new values. */ if (maskFree & TREE_CONF_BG_IMAGE) Tree_FreeImage(tree, tree->backgroundImage); #ifdef DEPRECATED if (maskFree & TREE_CONF_DEFSTYLE) ckfree((char *) tree->defaultStyle.styles); #endif /* * Restore old values. */ if (mask & TREE_CONF_BG_IMAGE) { tree->backgroundImage = saved.backgroundImage; } #ifdef DEPRECATED if (mask & TREE_CONF_DEFSTYLE) { tree->defaultStyle.styles = saved.defaultStyle.styles; tree->defaultStyle.numStyles = saved.defaultStyle.numStyles; } #endif if (mask & TREE_CONF_WRAP) { tree->wrapMode = saved.wrapMode; tree->wrapArg = saved.wrapArg; } if (mask & TREE_CONF_BGIMGOPT) { tree->bgImageScroll = saved.bgImageScroll; tree->bgImageTile = saved.bgImageTile; } Tcl_SetObjResult(interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } tree->itemPrefixLen = (int) strlen(tree->itemPrefix); tree->columnPrefixLen = (int) strlen(tree->columnPrefix); Tk_SetWindowBackground(tree->tkwin, Tk_3DBorderColor(tree->border)->pixel); if (createFlag) mask |= TREE_CONF_FONT | TREE_CONF_RELAYOUT; if (mask & (TREE_CONF_FONT | TREE_CONF_FG)) { /* * Should be blended into TreeWorldChanged. */ gcValues.font = Tk_FontId(tree->tkfont); gcValues.foreground = tree->fgColorPtr->pixel; gcValues.graphics_exposures = False; gcMask = GCForeground | GCFont | GCGraphicsExposures; if (tree->textGC != None) Tk_FreeGC(tree->display, tree->textGC); tree->textGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues); gcValues.font = Tk_FontId(tree->tkfontHeader); gcValues.foreground = tree->defHeaderTextColor->pixel; gcValues.graphics_exposures = False; gcMask = GCForeground | GCFont | GCGraphicsExposures; if (tree->headerTextGC != None) Tk_FreeGC(tree->display, tree->headerTextGC); tree->headerTextGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues); } if (tree->copyGC == None) { gcValues.function = GXcopy; gcValues.graphics_exposures = False; gcMask = GCFunction | GCGraphicsExposures; tree->copyGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues); } if (createFlag) mask |= TREE_CONF_BUTTON; if (mask & TREE_CONF_BUTTON) { if (tree->buttonGC != None) Tk_FreeGC(tree->display, tree->buttonGC); gcValues.foreground = tree->buttonColor->pixel; gcValues.line_width = tree->buttonThickness; gcMask = GCForeground | GCLineWidth; tree->buttonGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues); } if (createFlag) mask |= TREE_CONF_LINE; if (mask & TREE_CONF_LINE) { if (tree->lineGC[0] != None) Tk_FreeGC(tree->display, tree->lineGC[0]); if (tree->lineGC[1] != None) Tk_FreeGC(tree->display, tree->lineGC[1]); if (tree->lineStyle == LINE_STYLE_DOT) { gcValues.foreground = tree->lineColor->pixel; gcValues.line_style = LineOnOffDash; gcValues.line_width = 1; gcValues.dash_offset = 0; gcValues.dashes = 1; gcMask = GCForeground | GCLineWidth | GCLineStyle | GCDashList | GCDashOffset; tree->lineGC[0] = Tk_GetGC(tree->tkwin, gcMask, &gcValues); gcValues.dash_offset = 1; tree->lineGC[1] = Tk_GetGC(tree->tkwin, gcMask, &gcValues); } else { gcValues.foreground = tree->lineColor->pixel; gcValues.line_width = tree->lineThickness; gcMask = GCForeground | GCLineWidth; tree->lineGC[0] = Tk_GetGC(tree->tkwin, gcMask, &gcValues); tree->lineGC[1] = None; } } if (mask & TREE_CONF_PROXY) { TreeColumnProxy_Undisplay(tree); TreeColumnProxy_Display(tree); TreeRowProxy_Undisplay(tree); TreeRowProxy_Display(tree); } Tree_ButtonMaxSize(tree, &buttonWidth, &buttonHeight); tree->useIndent = MAX(tree->indent, buttonWidth); tree->buttonHeightMax = buttonHeight; if (createFlag) mask |= TREE_CONF_BORDERS; if (mask & TREE_CONF_BORDERS) { if (tree->highlightWidth < 0) tree->highlightWidth = 0; if (tree->useTheme && TreeTheme_SetBorders(tree) == TCL_OK) { /* nothing */ } else { tree->inset.left = tree->inset.top = tree->inset.right = tree->inset.bottom = tree->highlightWidth + tree->borderWidth; } } if (oldShowRoot != tree->showRoot) { TreeItem_InvalidateHeight(tree, tree->root); tree->updateIndex = 1; } TreeStyle_TreeChanged(tree, mask); TreeHeader_TreeChanged(tree, mask); if ((tree->scrollSmoothing & SMOOTHING_X) && !tree->xScrollSmoothing) Tree_SetScrollSmoothingX(tree, FALSE); if ((tree->scrollSmoothing & SMOOTHING_Y) && !tree->yScrollSmoothing) Tree_SetScrollSmoothingY(tree, FALSE); if (mask & TREE_CONF_RELAYOUT) { TreeComputeGeometry(tree); TreeColumns_InvalidateWidthOfItems(tree, NULL); Tree_RelayoutWindow(tree); } else if (mask & TREE_CONF_REDISPLAY) { Tree_RelayoutWindow(tree); } return TCL_OK; } /* *--------------------------------------------------------------------------- * * TreeWorldChanged -- * * This procedure is called when the world has changed in some * way and the widget needs to recompute all its graphics contexts * and determine its new geometry. * * Results: * None. * * Side effects: * Widget will be relayed out and redisplayed. * *--------------------------------------------------------------------------- */ static void TreeWorldChanged( ClientData instanceData /* Widget info. */ ) { TreeCtrl *tree = (TreeCtrl *) instanceData; XGCValues gcValues; unsigned long gcMask; gcValues.font = Tk_FontId(tree->tkfont); gcValues.foreground = tree->fgColorPtr->pixel; gcValues.graphics_exposures = False; gcMask = GCForeground | GCFont | GCGraphicsExposures; if (tree->textGC != None) Tk_FreeGC(tree->display, tree->textGC); tree->textGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues); gcValues.font = Tk_FontId(tree->tkfontHeader); gcValues.foreground = tree->defHeaderTextColor->pixel; gcValues.graphics_exposures = False; gcMask = GCForeground | GCFont | GCGraphicsExposures; if (tree->headerTextGC != None) Tk_FreeGC(tree->display, tree->headerTextGC); tree->headerTextGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues); TreeStyle_TreeChanged(tree, TREE_CONF_FONT | TREE_CONF_RELAYOUT); TreeHeader_TreeChanged(tree, TREE_CONF_FONT | TREE_CONF_RELAYOUT); TreeComputeGeometry(tree); TreeColumns_InvalidateWidthOfItems(tree, NULL); Tree_RelayoutWindow(tree); } /* *-------------------------------------------------------------- * * TreeEventProc -- * * This procedure is invoked by the Tk dispatcher for various * events on the widget. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get * cleaned up. When it gets exposed, it is redisplayed. * *-------------------------------------------------------------- */ static void TreeEventProc( ClientData clientData, /* Widget info. */ XEvent *eventPtr /* Event info. */ ) { TreeCtrl *tree = clientData; switch (eventPtr->type) { case Expose: { int x = eventPtr->xexpose.x; int y = eventPtr->xexpose.y; Tree_ExposeArea(tree, x, y, x + eventPtr->xexpose.width, y + eventPtr->xexpose.height); break; } case ConfigureNotify: { if ((tree->prevWidth != Tk_Width(tree->tkwin)) || (tree->prevHeight != Tk_Height(tree->tkwin))) { TreeColumns_InvalidateWidth(tree); tree->headerHeight = -1; Tree_RelayoutWindow(tree); tree->prevWidth = Tk_Width(tree->tkwin); tree->prevHeight = Tk_Height(tree->tkwin); } break; } case FocusIn: /* Handle focus as Tile does */ if ( eventPtr->xfocus.detail == NotifyInferior || eventPtr->xfocus.detail == NotifyAncestor || eventPtr->xfocus.detail == NotifyNonlinear) { Tree_FocusChanged(tree, 1); } break; case FocusOut: /* Handle focus as Tile does */ if ( eventPtr->xfocus.detail == NotifyInferior || eventPtr->xfocus.detail == NotifyAncestor || eventPtr->xfocus.detail == NotifyNonlinear) { Tree_FocusChanged(tree, 0); } break; case ActivateNotify: Tree_Activate(tree, 1); break; case DeactivateNotify: Tree_Activate(tree, 0); break; case DestroyNotify: if (!tree->deleted) { tree->deleted = 1; Tcl_DeleteCommandFromToken(tree->interp, tree->widgetCmd); Tcl_EventuallyFree((ClientData) tree, TreeDestroy); } break; #ifdef USE_TTK case VirtualEvent: if (!strcmp("ThemeChanged", ((XVirtualEvent *)(eventPtr))->name)) { TreeTheme_ThemeChanged(tree); TreeColumns_InvalidateWidth(tree); Tree_RelayoutWindow(tree); } break; #endif } } /* *---------------------------------------------------------------------- * * TreeCmdDeletedProc -- * * This procedure is invoked when a widget command is deleted. If * the widget isn't already in the process of being destroyed, * this command destroys it. * * Results: * None. * * Side effects: * The widget is destroyed. * *---------------------------------------------------------------------- */ static void TreeCmdDeletedProc( ClientData clientData /* Widget info. */ ) { TreeCtrl *tree = clientData; if (!tree->deleted) { Tk_DestroyWindow(tree->tkwin); } } /* *---------------------------------------------------------------------- * * TreeDestroy -- * * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release * to clean up the internal structure of a widget at a safe time * (when no-one is using it anymore). * * Results: * None. * * Side effects: * Everything associated with the widget is freed up. * *---------------------------------------------------------------------- */ static void TreeDestroy( char *memPtr /* Widget info. */ ) { TreeCtrl *tree = (TreeCtrl *) memPtr; TreeItem item; Tcl_HashEntry *hPtr; Tcl_HashSearch search; TreeStateDomain *domainPtr; int i, count; hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); TreeItem_FreeResources(tree, item); hPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&tree->itemHash); TreeHeader_FreeWidget(tree); Tcl_DeleteHashTable(&tree->itemSpansHash); count = TreeItemList_Count(&tree->preserveItemList); for (i = 0; i < count; i++) { item = TreeItemList_Nth(&tree->preserveItemList, i); TreeItem_Release(tree, item); } TreeItemList_Free(&tree->preserveItemList); TreeItem_FreeWidget(tree); TreeStyle_FreeWidget(tree); TreeElement_FreeWidget(tree); TreeDragImage_FreeWidget(tree); TreeMarquee_FreeWidget(tree); TreeDisplay_FreeWidget(tree); TreeTheme_FreeWidget(tree); if (tree->copyGC != None) Tk_FreeGC(tree->display, tree->copyGC); if (tree->textGC != None) Tk_FreeGC(tree->display, tree->textGC); if (tree->headerTextGC != None) Tk_FreeGC(tree->display, tree->headerTextGC); if (tree->buttonGC != None) Tk_FreeGC(tree->display, tree->buttonGC); if (tree->lineGC[0] != None) Tk_FreeGC(tree->display, tree->lineGC[0]); if (tree->lineGC[1] != None) Tk_FreeGC(tree->display, tree->lineGC[1]); Tree_FreeAllGC(tree); TreeColumn_FreeWidget(tree); while (tree->regionStackLen > 0) TkDestroyRegion(tree->regionStack[--tree->regionStackLen]); QE_DeleteBindingTable(tree->bindingTable); domainPtr = &tree->stateDomain[STATE_DOMAIN_ITEM]; for (i = domainPtr->staticCount; i < 32; i++) { if (domainPtr->stateNames[i] != NULL) ckfree(domainPtr->stateNames[i]); } domainPtr = &tree->stateDomain[STATE_DOMAIN_HEADER]; for (i = domainPtr->staticCount; i < 32; i++) { if (domainPtr->stateNames[i] != NULL) ckfree(domainPtr->stateNames[i]); } Tk_FreeConfigOptions((char *) tree, tree->debug.optionTable, tree->tkwin); Tk_FreeConfigOptions((char *) tree, tree->optionTable, tree->tkwin); hPtr = Tcl_FirstHashEntry(&tree->imageNameHash, &search); while (hPtr != NULL) { TreeImageRef *ref = (TreeImageRef *) Tcl_GetHashValue(hPtr); Tk_FreeImage(ref->image); ckfree((char *) ref); hPtr = Tcl_NextHashEntry(&search); } Tcl_DeleteHashTable(&tree->imageNameHash); Tcl_DeleteHashTable(&tree->imageTokenHash); Tcl_DeleteHashTable(&tree->selection); /* Must be done after all gradient users are freed */ TreeGradient_FreeWidget(tree); #ifdef DEPRECATED if (tree->defaultStyle.styles != NULL) ckfree((char *) tree->defaultStyle.styles); #endif #ifdef ALLOC_HAX TreeAlloc_Finalize(tree->allocData); #endif Tcl_Release(tree->tkwin); WFREE(tree, TreeCtrl); } /* *---------------------------------------------------------------------- * * Tree_UpdateScrollbarX -- * * This procedure is invoked whenever information has changed in * a widget in a way that would invalidate a scrollbar display. * * A event is generated. * * If there is an associated scrollbar, then this procedure updates * it by invoking a Tcl command. * * Results: * None. * * Side effects: * A Tcl command is invoked, and an additional command may be * invoked to process errors in the command. * *---------------------------------------------------------------------- */ void Tree_UpdateScrollbarX( TreeCtrl *tree /* Widget info. */ ) { Tcl_Interp *interp = tree->interp; int result; double fractions[2]; char buf1[TCL_DOUBLE_SPACE+1]; char buf2[TCL_DOUBLE_SPACE+1]; char *xScrollCmd; Tree_GetScrollFractionsX(tree, fractions); TreeNotify_Scroll(tree, fractions, FALSE); if (tree->xScrollCmd == NULL) return; Tcl_Preserve((ClientData) interp); Tcl_Preserve((ClientData) tree); xScrollCmd = tree->xScrollCmd; Tcl_Preserve((ClientData) xScrollCmd); buf1[0] = buf2[0] = ' '; Tcl_PrintDouble(NULL, fractions[0], buf1+1); Tcl_PrintDouble(NULL, fractions[1], buf2+1); result = Tcl_VarEval(interp, xScrollCmd, buf1, buf2, (char *) NULL); if (result != TCL_OK) Tcl_BackgroundError(interp); Tcl_ResetResult(interp); Tcl_Release((ClientData) xScrollCmd); Tcl_Release((ClientData) tree); Tcl_Release((ClientData) interp); } /* *---------------------------------------------------------------------- * * Tree_UpdateScrollbarY -- * * This procedure is invoked whenever information has changed in * a widget in a way that would invalidate a scrollbar display. * * A event is generated. * * If there is an associated scrollbar, then this procedure updates * it by invoking a Tcl command. * * Results: * None. * * Side effects: * A Tcl command is invoked, and an additional command may be * invoked to process errors in the command. * *---------------------------------------------------------------------- */ void Tree_UpdateScrollbarY( TreeCtrl *tree /* Widget info. */ ) { Tcl_Interp *interp = tree->interp; int result; double fractions[2]; char buf1[TCL_DOUBLE_SPACE+1]; char buf2[TCL_DOUBLE_SPACE+1]; char *yScrollCmd; Tree_GetScrollFractionsY(tree, fractions); TreeNotify_Scroll(tree, fractions, TRUE); if (tree->yScrollCmd == NULL) return; Tcl_Preserve((ClientData) interp); Tcl_Preserve((ClientData) tree); yScrollCmd = tree->yScrollCmd; Tcl_Preserve((ClientData) yScrollCmd); buf1[0] = buf2[0] = ' '; Tcl_PrintDouble(NULL, fractions[0], buf1+1); Tcl_PrintDouble(NULL, fractions[1], buf2+1); result = Tcl_VarEval(interp, yScrollCmd, buf1, buf2, (char *) NULL); if (result != TCL_OK) Tcl_BackgroundError(interp); Tcl_ResetResult(interp); Tcl_Release((ClientData) yScrollCmd); Tcl_Release((ClientData) tree); Tcl_Release((ClientData) interp); } /* *---------------------------------------------------------------------- * * TreeComputeGeometry -- * * This procedure is invoked to compute the requested size for the * window. * * Results: * None. * * Side effects: * Tk_GeometryRequest is called to register the desired dimensions * for the window. * *---------------------------------------------------------------------- */ static void TreeComputeGeometry( TreeCtrl *tree /* Widget info. */ ) { Tk_SetInternalBorderEx(tree->tkwin, tree->inset.left, tree->inset.right, tree->inset.top, tree->inset.bottom); Tk_GeometryRequest(tree->tkwin, tree->width + tree->inset.left + tree->inset.right, tree->height + tree->inset.top + tree->inset.bottom); } /* *---------------------------------------------------------------------- * * Tree_AddItem -- * * Add an item to the hash table of items. Also set the unique item * id and increment the number of items. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_AddItem( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item that was created. */ ) { Tcl_HashEntry *hPtr; int id, isNew; id = TreeItem_SetID(tree, item, tree->nextItemId++); hPtr = Tcl_CreateHashEntry(&tree->itemHash, (char *) INT2PTR(id), &isNew); Tcl_SetHashValue(hPtr, item); tree->itemCount++; } /* *---------------------------------------------------------------------- * * Tree_RemoveItem -- * * Remove an item from the selection, if selected. * Remove an item from the hash table of items. * Decrement the number of items. * Reset the unique item id allocator if the last item is removed. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_RemoveItem( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item to remove. */ ) { Tcl_HashEntry *hPtr; if (TreeItem_GetSelected(tree, item)) Tree_RemoveFromSelection(tree, item); hPtr = Tcl_FindHashEntry(&tree->itemSpansHash, (char *) item); if (hPtr != NULL) Tcl_DeleteHashEntry(hPtr); hPtr = Tcl_FindHashEntry(&tree->itemHash, (char *) INT2PTR(TreeItem_GetID(tree, item))); Tcl_DeleteHashEntry(hPtr); tree->itemCount--; if (tree->itemCount == 1) tree->nextItemId = TreeItem_GetID(tree, tree->root) + 1; } /* *---------------------------------------------------------------------- * * Tree_AddHeader -- * * Add a header to the hash table of headers. Also set the unique * header id and increment the number of headers. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_AddHeader( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Header that was created. */ ) { Tcl_HashEntry *hPtr; int id, isNew; id = TreeItem_SetID(tree, item, tree->nextHeaderId++); hPtr = Tcl_CreateHashEntry(&tree->headerHash, (char *) INT2PTR(id), &isNew); Tcl_SetHashValue(hPtr, item); tree->headerCount++; } /* *---------------------------------------------------------------------- * * Tree_RemoveHeader -- * * Remove a header from the hash table of headers. * Decrement the number of headers. * Reset the unique header id allocator if the last header is removed. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_RemoveHeader( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Header to remove. */ ) { Tcl_HashEntry *hPtr; hPtr = Tcl_FindHashEntry(&tree->itemSpansHash, (char *) item); if (hPtr != NULL) Tcl_DeleteHashEntry(hPtr); hPtr = Tcl_FindHashEntry(&tree->headerHash, (char *) INT2PTR(TreeItem_GetID(tree, item))); Tcl_DeleteHashEntry(hPtr); tree->headerCount--; if (tree->headerCount == 1) tree->nextHeaderId = TreeItem_GetID(tree, tree->headerItems) + 1; } /* *---------------------------------------------------------------------- * * ImageChangedProc -- * * This procedure is invoked by the image code whenever the manager * for an image does something that affects the image's size or * how it is displayed. * * Results: * None. * * Side effects: * Arranges for the widget to get redisplayed. * *---------------------------------------------------------------------- */ static void ImageChangedProc( ClientData clientData, /* Widget info. */ int x, int y, /* Upper left pixel (within image) * that must be redisplayed. */ int width, int height, /* Dimensions of area to redisplay * (may be <= 0). */ int imageWidth, int imageHeight /* New dimensions of image. */ ) { /* I would like to know the image was deleted... */ TreeCtrl *tree = clientData; /* FIXME: any image elements need to have their size invalidated * and items relayout'd accordingly. */ /* FIXME: this is used for the background image, but whitespace * is not redrawn if the background image is modified. */ Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_OUT_OF_DATE); } /* *---------------------------------------------------------------------- * * Tree_GetImage -- * * Wrapper around Tk_GetImage(). If the requested image does not yet * exist it is created. Otherwise an existing instance is returned. * * The purpose of this procedure is to save memory. We may expect * the same image to be used hundreds of times (a folder image for * example) and want to avoid allocating an instance for every usage. * * For each call to this function, there must be a matching call * to Tree_FreeImage. * * Results: * Token for the image instance. If an error occurs the result is * NULL and a message is left in the interpreter's result. * * Side effects: * A new image instance may be created. * *---------------------------------------------------------------------- */ Tk_Image Tree_GetImage( TreeCtrl *tree, /* Widget info. */ char *imageName /* Name of an existing image. */ ) { Tcl_HashEntry *hPtr, *h2Ptr; TreeImageRef *ref; Tk_Image image; int isNew; hPtr = Tcl_CreateHashEntry(&tree->imageNameHash, imageName, &isNew); if (isNew) { image = Tk_GetImage(tree->interp, tree->tkwin, imageName, ImageChangedProc, (ClientData) tree); if (image == NULL) { Tcl_DeleteHashEntry(hPtr); return NULL; } ref = (TreeImageRef *) ckalloc(sizeof(TreeImageRef)); ref->count = 0; ref->image = image; ref->hPtr = hPtr; Tcl_SetHashValue(hPtr, ref); h2Ptr = Tcl_CreateHashEntry(&tree->imageTokenHash, (char *) image, &isNew); Tcl_SetHashValue(h2Ptr, ref); } ref = (TreeImageRef *) Tcl_GetHashValue(hPtr); ref->count++; return ref->image; } /* *---------------------------------------------------------------------- * * Tree_FreeImage -- * * Decrement the reference count on an image. * * Results: * If the reference count hits zero, frees the image instance and * hash table entries. * * Side effects: * Memory may be freed. * *---------------------------------------------------------------------- */ void Tree_FreeImage( TreeCtrl *tree, /* Widget info. */ Tk_Image image /* Image token. */ ) { Tcl_HashEntry *hPtr; TreeImageRef *ref; hPtr = Tcl_FindHashEntry(&tree->imageTokenHash, (char *) image); #ifdef TREECTRL_DEBUG if (hPtr == NULL) panic("Tree_FreeImage called with an image not in the hash table"); #endif if (hPtr != NULL) { ref = (TreeImageRef *) Tcl_GetHashValue(hPtr); if (--ref->count == 0) { Tcl_DeleteHashEntry(ref->hPtr); /* imageNameHash */ Tcl_DeleteHashEntry(hPtr); Tk_FreeImage(ref->image); ckfree((char *) ref); } } } /* *-------------------------------------------------------------- * * TreeIdentifyCmd -- * * This procedure is invoked to process the [identify] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int TreeIdentifyCmd( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tcl_Interp *interp = tree->interp; int x, y, depth; TreeItem item; Tcl_Obj *listObj; TreeRectangle tr; int i, lock, columnTreeLeft; CONST char *arrayName = NULL; struct { char *where; int area; TreeHeader header; TreeItem item; TreeColumn column; TreeElement elem; int button; TreeItem line; char *side; } id; /* set id [$tree identify $x $y] "item I column C" : mouse is in column C of item I "item I column C elem E" : mouse is in element E in column C of item I "item I button" : mouse is in button-area of item I "item I line J" : mouse is near line coming from item J "header C ?left|right?" : mouse is in header column C "" : mouse is not in any item */ if (objc < 4) { Tcl_WrongNumArgs(interp, 2, objv, "?switches? x y"); return TCL_ERROR; } if (objc > 4) { for (i = 2; i < objc - 2; i += 2) { static CONST char *opName[] = { "-array", NULL }; int index; if (Tcl_GetIndexFromObj(interp, objv[i], opName, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } if (i + 1 == objc - 2) { FormatResult(interp, "missing value for \"%s\" option", opName[index]); return TCL_ERROR; } switch (index) { case 0: arrayName = Tcl_GetString(objv[i + 1]); break; } } } if (Tk_GetPixelsFromObj(interp, tree->tkwin, objv[objc - 2], &x) != TCL_OK) return TCL_ERROR; if (Tk_GetPixelsFromObj(interp, tree->tkwin, objv[objc - 1], &y) != TCL_OK) return TCL_ERROR; id.where = ""; id.header = NULL; id.item = NULL; id.area = Tree_HitTest(tree, x, y); /* Require point inside borders */ if (id.area == TREE_AREA_NONE) goto finish; if (id.area == TREE_AREA_HEADER) { int wx = x; item = Tree_HeaderUnderPoint(tree, &x, &y, &lock); if (item == NULL) /* impossible */ panic("[identify] point is in TREE_AREA_HEADER but header == NULL"); id.where = "header"; id.header = TreeItem_GetHeader(tree, item); TreeItem_Identify(tree, item, lock, x, y, &id.column, &id.elem); if (id.column == NULL) id.column = tree->columnTail; /* should never happen */ id.side = ""; if (TreeItem_GetRects(tree, item, id.column, 0, NULL, &tr) == 1) { if (W2Cx(wx) < TreeRect_Left(tr) + 4) id.side = "left"; else if (id.column != tree->columnTail && W2Cx(wx) >= TreeRect_Right(tr) - 4) id.side = "right"; } goto finish; } item = Tree_ItemUnderPoint(tree, &x, &y, &lock, FALSE); if (item == NULL) goto finish; id.where = "item"; id.item = item; depth = TreeItem_GetDepth(tree, item); if (item == tree->root) depth = (tree->showButtons && tree->showRootButton) ? 1 : 0; else if (tree->showRoot) { depth++; if (tree->showButtons && tree->showRootButton) depth++; } else if (tree->showButtons && tree->showRootChildButtons) depth += 1; else if (tree->showLines && tree->showRootLines) depth += 1; columnTreeLeft = tree->columnTreeLeft; /* canvas coords */ if (id.area == TREE_AREA_CONTENT) columnTreeLeft -= tree->canvasPadX[PAD_TOP_LEFT]; /* item coords */ id.button = FALSE; id.line = NULL; /* Point is not over the style */ if (tree->columnTreeVis && (TreeColumn_Lock(tree->columnTree) == lock) && (x >= columnTreeLeft) && (x < columnTreeLeft + TreeColumn_UseWidth(tree->columnTree)) && (x < columnTreeLeft + depth * tree->useIndent)) { int column = (x - columnTreeLeft) / tree->useIndent + 1; if (column == depth) { if (TreeItem_IsPointInButton(tree, item, x, y)) id.button = TRUE; } else if (tree->showLines) { TreeItem sibling; do { item = TreeItem_GetParent(tree, item); } while (++column < depth); sibling = TreeItem_NextSiblingVisible(tree, item); if ((sibling != NULL) && ((TreeItem_GetParent(tree, sibling) != tree->root) || tree->showRootLines)) { id.line = item; } } if (arrayName == NULL) id.column = NULL; else id.column = tree->columnTree; id.elem = NULL; /* Point is over the style */ } else { TreeItem_Identify(tree, item, lock, x, y, &id.column, &id.elem); } finish: /* New method: Set an array variable with the result. */ if (arrayName != NULL) { if (Tcl_SetVar2Ex(interp, arrayName, "where", Tcl_NewStringObj(id.where, -1), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } /* Point in a header*/ if (id.header != NULL) { if (Tcl_SetVar2Ex(interp, arrayName, "header", TreeHeader_ToObj(id.header), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } if (Tcl_SetVar2Ex(interp, arrayName, "column", TreeColumn_ToObj(tree, id.column), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } if (Tcl_SetVar2Ex(interp, arrayName, "element", id.elem ? TreeElement_ToObj(id.elem) : Tcl_NewObj(), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } if (Tcl_SetVar2Ex(interp, arrayName, "side", Tcl_NewStringObj(id.side, -1), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } /* Point in an item */ } else if (id.item != NULL) { if (Tcl_SetVar2Ex(interp, arrayName, "item", TreeItem_ToObj(tree, id.item), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } if (Tcl_SetVar2Ex(interp, arrayName, "button", Tcl_NewStringObj(id.button ? "yes" : "no", -1), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } if (Tcl_SetVar2Ex(interp, arrayName, "line", id.line ? TreeItem_ToObj(tree, id.line) : Tcl_NewObj(), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } if (Tcl_SetVar2Ex(interp, arrayName, "column", id.column ? TreeColumn_ToObj(tree, id.column) : Tcl_NewObj(), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } if (Tcl_SetVar2Ex(interp, arrayName, "element", id.elem ? TreeElement_ToObj(id.elem) : Tcl_NewObj(), TCL_LEAVE_ERR_MSG) == NULL) { return TCL_ERROR; } } /* Old method: Return a list. */ } else { /* Point in a header*/ if (id.header != NULL) { listObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("header", -1)); if (tree->headerCount > 1) { Tcl_ListObjAppendElement(interp, listObj, TreeHeader_ToObj(id.header)); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("column", -1)); } Tcl_ListObjAppendElement(interp, listObj, TreeColumn_ToObj(tree, id.column)); if (id.elem != NULL) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("elem", -1)); Tcl_ListObjAppendElement(interp, listObj, TreeElement_ToObj(id.elem)); } if (id.side[0]) Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(id.side, -1)); Tcl_SetObjResult(interp, listObj); /* Point in an item */ } else if (id.item != NULL) { listObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("item", -1)); Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, id.item)); if (id.button) Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("button", -1)); else if (id.line) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("line", -1)); Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, id.line)); } else { if (id.column != NULL) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("column", -1)); Tcl_ListObjAppendElement(interp, listObj, TreeColumn_ToObj(tree, id.column)); } if (id.elem != NULL) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("elem", -1)); Tcl_ListObjAppendElement(interp, listObj, TreeElement_ToObj(id.elem)); } } Tcl_SetObjResult(interp, listObj); } } return TCL_OK; } /* *-------------------------------------------------------------- * * TreeSeeCmd -- * * This procedure is invoked to process the [see] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int TreeSeeCmd( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tcl_Interp *interp = tree->interp; TreeItem item; TreeColumn treeColumn = NULL; TreeRectangle tr; int x, y, w, h; int visWidth = Tree_ContentWidth(tree); int visHeight = Tree_ContentHeight(tree); int xOrigin = Tree_GetOriginX(tree); int yOrigin = Tree_GetOriginY(tree); int minX = Tree_ContentLeft(tree); int minY = Tree_ContentTop(tree); int maxX = Tree_ContentRight(tree); int maxY = Tree_ContentBottom(tree); int index, offset; int centerX = 0, centerY = 0; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "item ?column? ?option value ...?"); return TCL_ERROR; } if (TreeItem_FromObj(tree, objv[2], &item, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; if (objc > 3) { int i, len, firstOption = 3; char *s = Tcl_GetStringFromObj(objv[3], &len); if (s[0] != '-') { if (TreeColumn_FromObj(tree, objv[3], &treeColumn, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) return TCL_ERROR; firstOption = 4; } for (i = firstOption; i < objc; i += 2) { static CONST char *optionNames[] = { "-center", (char *) NULL }; if (Tcl_GetIndexFromObj(interp, objv[i], optionNames, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } if (i + 1 == objc) { FormatResult(interp, "missing value for \"%s\" option", optionNames[index]); return TCL_ERROR; } switch (index) { case 0: { /* -center */ static const CharFlag centerFlags[] = { { 'x', 0x01 }, { 'y', 0x02 }, { 0, 0 } }; int flags = 0; if (Tree_GetFlagsFromObj(tree, objv[i+1], "-center value", centerFlags, &flags) != TCL_OK) { return TCL_ERROR; } centerX = (flags & 0x01) != 0; centerY = (flags & 0x02) != 0; break; } } } } if (visWidth < 1 || visHeight < 1) return TCL_OK; /* Get the item bounds in canvas coords. */ if (Tree_ItemBbox(tree, item, COLUMN_LOCK_NONE, &tr) < 0) return TCL_OK; TreeRect_XYWH(tr, &x, &y, &w, &h); if (treeColumn != NULL) { x += TreeColumn_Offset(treeColumn); w = TreeColumn_UseWidth(treeColumn); } Tree_SetScrollSmoothingX(tree, TRUE); Tree_SetScrollSmoothingY(tree, TRUE); /* No horizontal scrolling for locked columns. */ if ((treeColumn != NULL) && (TreeColumn_Lock(treeColumn) != COLUMN_LOCK_NONE)) { /* nothing */ /* Center the item or column horizontally. */ } else if (centerX) { index = Increment_FindX(tree, x + w/2 - visWidth/2); offset = Increment_ToOffsetX(tree, index); if (offset < x + w/2 - visWidth/2) { index++; offset = Increment_ToOffsetX(tree, index); } xOrigin = C2Ox(offset); /* Scroll horizontally a minimal amount. */ } else if ((C2Wx(x) > maxX) || (C2Wx(x + w) <= minX) || (w <= visWidth)) { if ((C2Wx(x) < minX) || (w > visWidth)) { index = Increment_FindX(tree, x); offset = Increment_ToOffsetX(tree, index); xOrigin = C2Ox(offset); } else if (C2Wx(x + w) > maxX) { index = Increment_FindX(tree, x + w - visWidth); offset = Increment_ToOffsetX(tree, index); if (offset < x + w - visWidth) { index++; offset = Increment_ToOffsetX(tree, index); } xOrigin = C2Ox(offset); } } /* Center the item or column vertically. */ if (centerY) { index = Increment_FindY(tree, y + h/2 - visHeight/2); offset = Increment_ToOffsetY(tree, index); if (offset < y + h/2 - visHeight/2) { index++; offset = Increment_ToOffsetY(tree, index); } yOrigin = C2Oy(offset); /* Scroll vertically a minimal amount. */ } else if ((C2Wy(y) > maxY) || (C2Wy(y + h) <= minY) || (h <= visHeight)) { if ((C2Wy(y) < minY) || (h > visHeight)) { index = Increment_FindY(tree, y); offset = Increment_ToOffsetY(tree, index); yOrigin = C2Oy(offset); } else if (C2Wy(y + h) > maxY) { index = Increment_FindY(tree, y + h - visHeight); offset = Increment_ToOffsetY(tree, index); if (offset < y + h - visHeight) { index++; offset = Increment_ToOffsetY(tree, index); } yOrigin = C2Oy(offset); } } Tree_SetOriginX(tree, xOrigin); Tree_SetOriginY(tree, yOrigin); return TCL_OK; } /* *---------------------------------------------------------------------- * * Tree_StateFromObj -- * * Parse a Tcl_Obj containing a state name (with optional modifers) * into a STATE_xxx flag, and modify an existing array of state * flags accordingly. * * If the object contains "foo", then the state "foo" is set on. * If the object contains "!foo", then the state "foo" is set off. * If the object contains "~foo", then the state "foo" is toggled. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tree_StateFromObj( TreeCtrl *tree, /* Widget info. */ int domain, /* STATE_DOMAIN_XXX index. */ Tcl_Obj *obj, /* String rep of the state. */ int states[3], /* Initialized state flags, indexed by the * STATE_OP_xxx contants. A single flag * may be turned on or off in each value. */ int *indexPtr, /* Returned index of the STATE_xxx flag. * May be NULL. */ int flags /* SFO_xxx flags. */ ) { Tcl_Interp *interp = tree->interp; TreeStateDomain *domainPtr = &tree->stateDomain[domain]; int i, op = STATE_OP_ON, op2, op3, length, state = 0; char ch0, *string; string = Tcl_GetStringFromObj(obj, &length); if (length == 0) goto unknown; ch0 = string[0]; if (ch0 == '!') { if (flags & SFO_NOT_OFF) { FormatResult(interp, "can't specify '!' for this command"); return TCL_ERROR; } op = STATE_OP_OFF; ++string; ch0 = string[0]; } else if (ch0 == '~') { if (flags & SFO_NOT_TOGGLE) { FormatResult(interp, "can't specify '~' for this command"); return TCL_ERROR; } op = STATE_OP_TOGGLE; ++string; ch0 = string[0]; } for (i = 0; i < 32; i++) { if (domainPtr->stateNames[i] == NULL) continue; if ((ch0 == domainPtr->stateNames[i][0]) && (strcmp(string, domainPtr->stateNames[i]) == 0)) { if ((i < domainPtr->staticCount) && (flags & SFO_NOT_STATIC)) { FormatResult(interp, "can't specify state \"%s\" for this command", domainPtr->stateNames[i]); return TCL_ERROR; } state = 1L << i; break; } } if (state == 0) goto unknown; if (states != NULL) { if (op == STATE_OP_ON) { op2 = STATE_OP_OFF; op3 = STATE_OP_TOGGLE; } else if (op == STATE_OP_OFF) { op2 = STATE_OP_ON; op3 = STATE_OP_TOGGLE; } else { op2 = STATE_OP_ON; op3 = STATE_OP_OFF; } states[op2] &= ~state; states[op3] &= ~state; states[op] |= state; } if (indexPtr != NULL) (*indexPtr) = i; return TCL_OK; unknown: FormatResult(interp, "unknown state \"%s\"", string); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Tree_StateFromListObj -- * * Call Tree_StateFromObj for a Tcl_Obj list object. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tree_StateFromListObj( TreeCtrl *tree, /* Widget info. */ int domain, /* STATE_DOMAIN_XXX index. */ Tcl_Obj *obj, /* List of states. */ int states[3], /* Uninitialized state flags, indexed by the * STATE_OP_xxx contants. A single flag * may be turned on or off in each value. */ int flags /* SFO_xxx flags. */ ) { Tcl_Interp *interp = tree->interp; int i, listObjc; Tcl_Obj **listObjv; states[0] = states[1] = states[2] = 0; if (Tcl_ListObjGetElements(interp, obj, &listObjc, &listObjv) != TCL_OK) return TCL_ERROR; for (i = 0; i < listObjc; i++) { if (Tree_StateFromObj(tree, domain, listObjv[i], states, NULL, flags) != TCL_OK) return TCL_ERROR; } return TCL_OK; } /* *-------------------------------------------------------------- * * TreeStateCmd -- * * This procedure is invoked to process the [state] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ int Tree_StateCmd( TreeCtrl *tree, /* Widget info. */ int domain, /* STATE_DOMAIN_XXX index. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tcl_Interp *interp = tree->interp; TreeStateDomain *domainPtr = &tree->stateDomain[domain]; static CONST char *commandName[] = { "define", "linkage", "names", "undefine", (char *) NULL }; enum { COMMAND_DEFINE, COMMAND_LINKAGE, COMMAND_NAMES, COMMAND_UNDEFINE }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandName, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case COMMAND_DEFINE: { char *string; int i, length, slot = -1; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "stateName"); return TCL_ERROR; } string = Tcl_GetStringFromObj(objv[3], &length); if (!length || (*string == '~') || (*string == '!')) { FormatResult(interp, "invalid state name \"%s\"", string); return TCL_ERROR; } for (i = 0; i < 32; i++) { if (domainPtr->stateNames[i] == NULL) { if (slot == -1) slot = i; continue; } if (strcmp(domainPtr->stateNames[i], string) == 0) { FormatResult(interp, "state \"%s\" already defined", string); return TCL_ERROR; } } if (slot == -1) { FormatResult(interp, "cannot define any more states"); return TCL_ERROR; } domainPtr->stateNames[slot] = ckalloc(length + 1); strcpy(domainPtr->stateNames[slot], string); break; } case COMMAND_LINKAGE: { int index; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "state"); return TCL_ERROR; } if (Tree_StateFromObj(tree, domain, objv[3], NULL, &index, SFO_NOT_OFF | SFO_NOT_TOGGLE) != TCL_OK) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewStringObj( (index < domainPtr->staticCount) ? "static" : "dynamic", -1)); break; } case COMMAND_NAMES: { Tcl_Obj *listObj; int i; if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL); return TCL_ERROR; } listObj = Tcl_NewListObj(0, NULL); for (i = domainPtr->staticCount; i < 32; i++) { if (domainPtr->stateNames[i] != NULL) Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(domainPtr->stateNames[i], -1)); } Tcl_SetObjResult(interp, listObj); break; } case COMMAND_UNDEFINE: { int i, index; for (i = 3; i < objc; i++) { if (Tree_StateFromObj(tree, domain, objv[i], NULL, &index, SFO_NOT_STATIC | SFO_NOT_OFF | SFO_NOT_TOGGLE) != TCL_OK) return TCL_ERROR; Tree_UndefineState(tree, domain, 1L << index); PerStateInfo_Undefine(tree, &pstBitmap, &tree->buttonBitmap, domain, 1L << index); PerStateInfo_Undefine(tree, &pstImage, &tree->buttonImage, domain, 1L << index); ckfree(domainPtr->stateNames[index]); domainPtr->stateNames[index] = NULL; } break; } } return TCL_OK; } /* *-------------------------------------------------------------- * * Tree_AddToSelection -- * * Add an item to the hash table of selected items. Turn on the * STATE_ITEM_SELECTED state for the item. * * Results: * None. * * Side effects: * The widget may be redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_AddToSelection( TreeCtrl *tree, /* Widget info */ TreeItem item /* Item to add to the selection. */ ) { Tcl_HashEntry *hPtr; int isNew; #ifdef SELECTION_VISIBLE if (!TreeItem_ReallyVisible(tree, item)) panic("Tree_AddToSelection: item %d not ReallyVisible", TreeItem_GetID(tree, item)); #endif if (TreeItem_GetSelected(tree, item)) panic("Tree_AddToSelection: item %d already selected", TreeItem_GetID(tree, item)); if (!TreeItem_GetEnabled(tree, item)) panic("Tree_AddToSelection: item %d not enabled", TreeItem_GetID(tree, item)); TreeItem_ChangeState(tree, item, 0, STATE_ITEM_SELECTED); hPtr = Tcl_CreateHashEntry(&tree->selection, (char *) item, &isNew); if (!isNew) panic("Tree_AddToSelection: item %d already in selection hash table", TreeItem_GetID(tree, item)); tree->selectCount++; } /* *-------------------------------------------------------------- * * Tree_RemoveFromSelection -- * * Remove an item from the hash table of selected items. Turn off the * STATE_ITEM_SELECTED state for the item. * * Results: * None. * * Side effects: * The widget may be redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_RemoveFromSelection( TreeCtrl *tree, /* Widget info */ TreeItem item /* Item to remove from the selection. */ ) { Tcl_HashEntry *hPtr; if (!TreeItem_GetSelected(tree, item)) panic("Tree_RemoveFromSelection: item %d isn't selected", TreeItem_GetID(tree, item)); TreeItem_ChangeState(tree, item, STATE_ITEM_SELECTED, 0); hPtr = Tcl_FindHashEntry(&tree->selection, (char *) item); if (hPtr == NULL) panic("Tree_RemoveFromSelection: item %d not found in selection hash table", TreeItem_GetID(tree, item)); Tcl_DeleteHashEntry(hPtr); tree->selectCount--; } /* *-------------------------------------------------------------- * * TreeSelectionCmd -- * * This procedure is invoked to process the [selection] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int TreeSelectionCmd( Tcl_Interp *interp, /* Current interpreter. */ TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { static CONST char *commandName[] = { "add", "anchor", "clear", "count", "get", "includes", "modify", NULL }; enum { COMMAND_ADD, COMMAND_ANCHOR, COMMAND_CLEAR, COMMAND_COUNT, COMMAND_GET, COMMAND_INCLUDES, COMMAND_MODIFY }; int index; TreeItemList itemsFirst, itemsLast; TreeItem item, itemFirst, itemLast; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandName, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case COMMAND_ADD: { int i, count; TreeItemList items; Tcl_HashEntry *hPtr; Tcl_HashSearch search; if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 3, objv, "first ?last?"); return TCL_ERROR; } if (TreeItemList_FromObj(tree, objv[3], &itemsFirst, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; itemFirst = TreeItemList_Nth(&itemsFirst, 0); itemLast = NULL; if (objc == 5) { if (TreeItemList_FromObj(tree, objv[4], &itemsLast, IFO_NOT_NULL) != TCL_OK) { TreeItemList_Free(&itemsFirst); return TCL_ERROR; } itemLast = TreeItemList_Nth(&itemsLast, 0); } if ((itemFirst == ITEM_ALL) || (itemLast == ITEM_ALL)) { if (objc == 5) TreeItemList_Free(&itemsLast); TreeItemList_Init(tree, &items, tree->itemCount - tree->selectCount); /* Include orphans. */ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); if (TreeItem_CanAddToSelection(tree, item)) { Tree_AddToSelection(tree, item); TreeItemList_Append(&items, item); } hPtr = Tcl_NextHashEntry(&search); } goto doneADD; } if (objc == 5) { TreeItemList_Free(&itemsFirst); TreeItemList_Free(&itemsLast); count = TreeItem_FirstAndLast(tree, &itemFirst, &itemLast); if (count == 0) return TCL_ERROR; TreeItemList_Init(tree, &items, count); while (1) { if (TreeItem_CanAddToSelection(tree, itemFirst)) { Tree_AddToSelection(tree, itemFirst); TreeItemList_Append(&items, itemFirst); } if (itemFirst == itemLast) break; itemFirst = TreeItem_Next(tree, itemFirst); } goto doneADD; } count = TreeItemList_Count(&itemsFirst); TreeItemList_Init(tree, &items, count); for (i = 0; i < count; i++) { item = TreeItemList_Nth(&itemsFirst, i); if (TreeItem_CanAddToSelection(tree, item)) { Tree_AddToSelection(tree, item); TreeItemList_Append(&items, item); } } doneADD: if (TreeItemList_Count(&items)) { TreeNotify_Selection(tree, &items, NULL); } TreeItemList_Free(&items); TreeItemList_Free(&itemsFirst); break; } case COMMAND_ANCHOR: { if (objc != 3 && objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "?item?"); return TCL_ERROR; } if (objc == 4) { if (TreeItem_FromObj(tree, objv[3], &item, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } tree->anchorItem = item; } Tcl_SetObjResult(interp, TreeItem_ToObj(tree, tree->anchorItem)); break; } case COMMAND_CLEAR: { int i, count; TreeItemList items; Tcl_HashEntry *hPtr; Tcl_HashSearch search; if (objc > 5) { Tcl_WrongNumArgs(interp, 3, objv, "?first? ?last?"); return TCL_ERROR; } itemFirst = itemLast = NULL; if (objc >= 4) { if (TreeItemList_FromObj(tree, objv[3], &itemsFirst, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; itemFirst = TreeItemList_Nth(&itemsFirst, 0); } if (objc == 5) { if (TreeItemList_FromObj(tree, objv[4], &itemsLast, IFO_NOT_NULL) != TCL_OK) { TreeItemList_Free(&itemsFirst); return TCL_ERROR; } itemLast = TreeItemList_Nth(&itemsLast, 0); } if (tree->selectCount < 1) { if (objc >= 4) TreeItemList_Free(&itemsFirst); if (objc == 5) TreeItemList_Free(&itemsLast); break; } if ((objc == 3) || (itemFirst == ITEM_ALL) || (itemLast == ITEM_ALL)) { if (objc >= 4) TreeItemList_Free(&itemsFirst); if (objc == 5) TreeItemList_Free(&itemsLast); TreeItemList_Init(tree, &items, tree->selectCount); hPtr = Tcl_FirstHashEntry(&tree->selection, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashKey(&tree->selection, hPtr); TreeItemList_Append(&items, item); hPtr = Tcl_NextHashEntry(&search); } count = TreeItemList_Count(&items); for (i = 0; i < count; i++) Tree_RemoveFromSelection(tree, TreeItemList_Nth(&items, i)); goto doneCLEAR; } if (objc == 5) { TreeItemList_Free(&itemsFirst); TreeItemList_Free(&itemsLast); count = TreeItem_FirstAndLast(tree, &itemFirst, &itemLast); if (count == 0) return TCL_ERROR; TreeItemList_Init(tree, &items, count); while (1) { if (TreeItem_GetSelected(tree, itemFirst)) { Tree_RemoveFromSelection(tree, itemFirst); TreeItemList_Append(&items, itemFirst); } if (itemFirst == itemLast) break; itemFirst = TreeItem_Next(tree, itemFirst); } goto doneCLEAR; } count = TreeItemList_Count(&itemsFirst); TreeItemList_Init(tree, &items, count); for (i = 0; i < count; i++) { item = TreeItemList_Nth(&itemsFirst, i); if (TreeItem_GetSelected(tree, item)) { Tree_RemoveFromSelection(tree, item); TreeItemList_Append(&items, item); } } TreeItemList_Free(&itemsFirst); doneCLEAR: if (TreeItemList_Count(&items)) { TreeNotify_Selection(tree, NULL, &items); } TreeItemList_Free(&items); break; } case COMMAND_COUNT: { if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(tree->selectCount)); break; } case COMMAND_GET: { TreeItem item; Tcl_Obj *listObj; Tcl_HashEntry *hPtr; Tcl_HashSearch search; #ifdef SELECTION_VISIBLE if (objc < 3 || objc > 5) { Tcl_WrongNumArgs(interp, 3, objv, "?first? ?last?"); return TCL_ERROR; } if (objc > 3) { int first, last; TreeItemList items; if (TclGetIntForIndex(interp, objv[3], tree->selectCount - 1, &first) != TCL_OK) { return TCL_ERROR; } if (first < 0) first = 0; last = first; if (objc == 5) { if (TclGetIntForIndex(interp, objv[4], tree->selectCount - 1, &last) != TCL_OK) { return TCL_ERROR; } } if (last >= tree->selectCount) last = tree->selectCount - 1; if (first > last) break; /* Build a list of selected items. */ TreeItemList_Init(tree, &items, tree->selectCount); hPtr = Tcl_FirstHashEntry(&tree->selection, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashKey(&tree->selection, hPtr); TreeItemList_Append(&items, item); hPtr = Tcl_NextHashEntry(&search); } /* Sort it. */ TreeItemList_Sort(&items); if (first == last) { item = TreeItemList_Nth(&items, first); Tcl_SetObjResult(interp, TreeItem_ToObj(tree, item)); } else { listObj = Tcl_NewListObj(0, NULL); for (index = first; index <= last; index++) { item = TreeItemList_Nth(&items, index); Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, item)); } Tcl_SetObjResult(interp, listObj); } TreeItemList_Free(&items); break; } #else /* SELECTION_VISIBLE */ /* If any item may be selected, including orphans, then getting * a sorted list of selected items is impossible. */ if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL); return TCL_ERROR; } #endif /* SELECTION_VISIBLE */ if (tree->selectCount < 1) break; listObj = Tcl_NewListObj(0, NULL); hPtr = Tcl_FirstHashEntry(&tree->selection, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashKey(&tree->selection, hPtr); Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, item)); hPtr = Tcl_NextHashEntry(&search); } Tcl_SetObjResult(interp, listObj); break; } case COMMAND_INCLUDES: { if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "item"); return TCL_ERROR; } if (TreeItem_FromObj(tree, objv[3], &item, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewBooleanObj( TreeItem_GetSelected(tree, item))); break; } case COMMAND_MODIFY: { int i, j, k, objcS, objcD; Tcl_Obj **objvS, **objvD; Tcl_HashEntry *hPtr; Tcl_HashSearch search; TreeItem item; TreeItemList items; TreeItemList itemS, itemD, newS, newD; int allS = FALSE, allD = FALSE; if (objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "select deselect"); return TCL_ERROR; } if (Tcl_ListObjGetElements(interp, objv[3], &objcS, &objvS) != TCL_OK) return TCL_ERROR; if (Tcl_ListObjGetElements(interp, objv[4], &objcD, &objvD) != TCL_OK) return TCL_ERROR; /* No change */ if (!objcS && !objcD) break; /* Some of these may get double-initialized. */ TreeItemList_Init(tree, &itemS, 0); TreeItemList_Init(tree, &itemD, 0); TreeItemList_Init(tree, &newS, 0); TreeItemList_Init(tree, &newD, 0); /* List of items to select */ for (i = 0; i < objcS; i++) { if (TreeItemList_FromObj(tree, objvS[i], &items, IFO_NOT_NULL) != TCL_OK) { TreeItemList_Free(&itemS); return TCL_ERROR; } /* Add unique items to itemS */ for (k = 0; k < TreeItemList_Count(&items); k++) { item = TreeItemList_Nth(&items, k); if (item == ITEM_ALL) { allS = TRUE; break; } for (j = 0; j < TreeItemList_Count(&itemS); j++) { if (TreeItemList_Nth(&itemS, j) == item) break; } if (j == TreeItemList_Count(&itemS)) { TreeItemList_Append(&itemS, item); } } TreeItemList_Free(&items); if (allS) break; } /* List of items to deselect */ for (i = 0; i < objcD; i++) { if (TreeItemList_FromObj(tree, objvD[i], &items, IFO_NOT_NULL) != TCL_OK) { TreeItemList_Free(&itemS); TreeItemList_Free(&itemD); return TCL_ERROR; } /* Add unique items to itemD */ for (k = 0; k < TreeItemList_Count(&items); k++) { item = TreeItemList_Nth(&items, k); if (item == ITEM_ALL) { allD = TRUE; break; } for (j = 0; j < TreeItemList_Count(&itemD); j++) { if (TreeItemList_Nth(&itemD, j) == item) break; } if (j == TreeItemList_Count(&itemD)) { TreeItemList_Append(&itemD, item); } } TreeItemList_Free(&items); if (allD) break; } /* Select all */ if (allS) { TreeItemList_Init(tree, &newS, tree->itemCount - tree->selectCount); #ifdef SELECTION_VISIBLE item = tree->root; if (!TreeItem_ReallyVisible(tree, item)) item = TreeItem_NextVisible(tree, item); while (item != NULL) { if (TreeItem_CanAddToSelection(tree, item)) { TreeItemList_Append(&newS, item); } item = TreeItem_NextVisible(tree, item); } #else /* Include detached items */ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); if (TreeItem_CanAddToSelection(tree, item)) { TreeItemList_Append(&newS, item); } hPtr = Tcl_NextHashEntry(&search); } #endif /* Ignore the deselect list. */ goto modifyDONE; } /* Select some */ if (objcS > 0) { TreeItemList_Init(tree, &newS, objcS); for (i = 0; i < TreeItemList_Count(&itemS); i++) { item = TreeItemList_Nth(&itemS, i); if (TreeItem_CanAddToSelection(tree, item)) { TreeItemList_Append(&newS, item); } } } /* Deselect all */ if (allD) { TreeItemList_Init(tree, &newD, tree->selectCount); hPtr = Tcl_FirstHashEntry(&tree->selection, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashKey(&tree->selection, hPtr); /* Don't deselect an item in the select list */ for (j = 0; j < TreeItemList_Count(&itemS); j++) { if (item == TreeItemList_Nth(&itemS, j)) break; } if (j == TreeItemList_Count(&itemS)) { TreeItemList_Append(&newD, item); } hPtr = Tcl_NextHashEntry(&search); } } /* Deselect some */ if ((objcD > 0) && !allD) { TreeItemList_Init(tree, &newD, objcD); for (i = 0; i < TreeItemList_Count(&itemD); i++) { item = TreeItemList_Nth(&itemD, i); if (!TreeItem_GetSelected(tree, item)) continue; /* Don't deselect an item in the select list */ for (j = 0; j < TreeItemList_Count(&itemS); j++) { if (item == TreeItemList_Nth(&itemS, j)) break; } if (j == TreeItemList_Count(&itemS)) { TreeItemList_Append(&newD, item); } } } modifyDONE: for (i = 0; i < TreeItemList_Count(&newS); i++) Tree_AddToSelection(tree, TreeItemList_Nth(&newS, i)); for (i = 0; i < TreeItemList_Count(&newD); i++) Tree_RemoveFromSelection(tree, TreeItemList_Nth(&newD, i)); if (TreeItemList_Count(&newS) || TreeItemList_Count(&newD)) { TreeNotify_Selection(tree, &newS, &newD); } TreeItemList_Free(&newS); TreeItemList_Free(&itemS); TreeItemList_Free(&newD); TreeItemList_Free(&itemD); break; } } return TCL_OK; } void Tree_Debug( TreeCtrl *tree /* Widget info. */ ) { if (TreeItem_Debug(tree, tree->root) != TCL_OK) { dbwin("Tree_Debug: %s\n", Tcl_GetStringResult(tree->interp)); Tcl_BackgroundError(tree->interp); } } /* *-------------------------------------------------------------- * * TreeDebugCmd -- * * This procedure is invoked to process the [debug] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ static int TreeDebugCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; static CONST char *commandNames[] = { "alloc", "cget", "configure", "dinfo", "expose", (char *) NULL }; enum { COMMAND_ALLOC, COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DINFO, COMMAND_EXPOSE }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { /* T debug alloc */ case COMMAND_ALLOC: { #ifdef ALLOC_HAX #ifdef TREECTRL_DEBUG TreeAlloc_Stats(interp, tree->allocData); #else FormatResult(interp, "TREECTRL_DEBUG is not defined"); #endif #else FormatResult(interp, "ALLOC_HAX is not defined"); #endif break; } /* T debug cget option */ case COMMAND_CGET: { Tcl_Obj *resultObjPtr; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "option"); return TCL_ERROR; } resultObjPtr = Tk_GetOptionValue(interp, (char *) tree, tree->debug.optionTable, objv[3], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } /* T debug configure ?option? ?value? ?option value ...? */ case COMMAND_CONFIGURE: { Tcl_Obj *resultObjPtr; Tk_SavedOptions savedOptions; int mask, result; if (objc < 3) { Tcl_WrongNumArgs(interp, 3, objv, "?option? ?value?"); return TCL_ERROR; } if (objc <= 4) { resultObjPtr = Tk_GetOptionInfo(interp, (char *) tree, tree->debug.optionTable, (objc == 3) ? (Tcl_Obj *) NULL : objv[3], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } result = Tk_SetOptions(interp, (char *) tree, tree->debug.optionTable, objc - 3, objv + 3, tree->tkwin, &savedOptions, &mask); if (result != TCL_OK) { Tk_RestoreSavedOptions(&savedOptions); return TCL_ERROR; } Tk_FreeSavedOptions(&savedOptions); if (tree->debug.eraseColor != NULL) { tree->debug.gcErase = Tk_GCForColor(tree->debug.eraseColor, Tk_WindowId(tree->tkwin)); } if (tree->debug.drawColor != NULL) { tree->debug.gcDraw = Tk_GCForColor(tree->debug.drawColor, Tk_WindowId(tree->tkwin)); } break; } case COMMAND_DINFO: { return Tree_DumpDInfo(tree, objc, objv); } /* T debug expose x1 y1 x2 y2 */ case COMMAND_EXPOSE: { int x1, y1, x2, y2; if (objc != 7) { Tcl_WrongNumArgs(interp, 3, objv, "x1 y1 x2 y2"); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[3], &x1) != TCL_OK) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[4], &y1) != TCL_OK) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[5], &x2) != TCL_OK) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[6], &y2) != TCL_OK) return TCL_ERROR; Tree_RedrawArea(tree, MIN(x1, x2), MIN(y1, y2), MAX(x1, x2), MAX(y1, y2)); break; } } return TCL_OK; } /* *-------------------------------------------------------------- * * Tree_PreserveItems -- * * Increment tree->preserveItemRefCnt. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void Tree_PreserveItems( TreeCtrl *tree ) { tree->preserveItemRefCnt++; } /* *-------------------------------------------------------------- * * Tree_ReleaseItems -- * * Decrement tree->preserveItemRefCnt. If it reaches zero, * release the storage of items marked as deleted. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void Tree_ReleaseItems( TreeCtrl *tree ) { int i, count; TreeItem item; if (tree->preserveItemRefCnt == 0) panic("mismatched calls to Tree_PreserveItems/Tree_ReleaseItems"); if (--tree->preserveItemRefCnt > 0) return; count = TreeItemList_Count(&tree->preserveItemList); for (i = 0; i < count; i++) { item = TreeItemList_Nth(&tree->preserveItemList, i); TreeItem_Release(tree, item); } TreeItemList_Free(&tree->preserveItemList); } /* *-------------------------------------------------------------- * * TextLayoutCmd -- * * This procedure is invoked to process the [textlayout] Tcl * command. The command is used by the library scripts to place * the text-edit Entry or Text widget. * * Results: * A standard Tcl result. * * Side effects: * None. * *-------------------------------------------------------------- */ /* textlayout $font $text -width pixels -wrap word|char -justify left|center|right -ignoretabs boolean -ignorenewlines boolean */ static int TextLayoutCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tk_Font tkfont; Tk_Window tkwin = Tk_MainWindow(interp); char *text; int flags = 0; Tk_Justify justify = TK_JUSTIFY_LEFT; Tk_TextLayout layout; int width = 0, height; int result = TCL_OK; int i; if (objc < 3) { Tcl_WrongNumArgs(interp, 1, objv, "font text ?options ...?"); return TCL_ERROR; } tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[1]); if (tkfont == NULL) return TCL_ERROR; text = Tcl_GetString(objv[2]); for (i = 3; i < objc; i += 2) { static CONST char *optionNames[] = { "-ignoretabs", "-ignorenewlines", "-justify", "-width", (char *) NULL }; enum { OPT_IGNORETABS, OPT_IGNORENEWLINES, OPT_JUSTIFY, OPT_WIDTH }; int index; if (Tcl_GetIndexFromObj(interp, objv[i], optionNames, "option", 0, &index) != TCL_OK) { result = TCL_ERROR; goto done; } if (i + 1 == objc) { FormatResult(interp, "missing value for \"%s\" option", optionNames[index]); goto done; } switch (index) { case OPT_IGNORENEWLINES: { int v; if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &v) != TCL_OK) { result = TCL_ERROR; goto done; } if (v) flags |= TK_IGNORE_NEWLINES; else flags &= ~TK_IGNORE_NEWLINES; break; } case OPT_IGNORETABS: { int v; if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &v) != TCL_OK) { result = TCL_ERROR; goto done; } if (v) flags |= TK_IGNORE_TABS; else flags &= ~TK_IGNORE_TABS; break; } case OPT_JUSTIFY: { if (Tk_GetJustifyFromObj(interp, objv[i + 1], &justify) != TCL_OK) { result = TCL_ERROR; goto done; } break; } case OPT_WIDTH: { if (Tk_GetPixelsFromObj(interp, tkwin, objv[i + 1], &width) != TCL_OK) { result = TCL_ERROR; goto done; } break; } } } layout = Tk_ComputeTextLayout(tkfont, text, -1, width, justify, flags, &width, &height); FormatResult(interp, "%d %d", width, height); Tk_FreeTextLayout(layout); done: Tk_FreeFont(tkfont); return result; } /* *-------------------------------------------------------------- * * ImageTintCmd -- * * This procedure is invoked to process the [imagetint] Tcl * command. The command may be used to apply a highlight to an * existing photo image. It is used by the demos to produce a * selected version of an image. * * Results: * A standard Tcl result. * * Side effects: * A photo image is modified. * *-------------------------------------------------------------- */ static int ImageTintCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { char *imageName; Tk_PhotoHandle photoH; Tk_PhotoImageBlock photoBlock; XColor *xColor; unsigned char *pixelPtr, *photoPix; int x, y, alpha, imgW, imgH, pitch; if (objc != 4) { Tcl_WrongNumArgs(interp, 1, objv, "imageName color alpha"); return TCL_ERROR; } imageName = Tcl_GetStringFromObj(objv[1], NULL); photoH = Tk_FindPhoto(interp, imageName); if (photoH == NULL) { Tcl_AppendResult(interp, "image \"", imageName, "\" doesn't exist or is not a photo image", (char *) NULL); return TCL_ERROR; } xColor = Tk_AllocColorFromObj(interp, Tk_MainWindow(interp), objv[2]); if (xColor == NULL) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[3], &alpha) != TCL_OK) return TCL_ERROR; if (alpha < 0) alpha = 0; if (alpha > 255) alpha = 255; Tk_PhotoGetImage(photoH, &photoBlock); photoPix = photoBlock.pixelPtr; imgW = photoBlock.width; imgH = photoBlock.height; pitch = photoBlock.pitch; pixelPtr = (unsigned char *) Tcl_Alloc(imgW * 4); photoBlock.pixelPtr = pixelPtr; photoBlock.width = imgW; photoBlock.height = 1; photoBlock.pitch = imgW * 4; photoBlock.pixelSize = 4; photoBlock.offset[0] = 0; photoBlock.offset[1] = 1; photoBlock.offset[2] = 2; photoBlock.offset[3] = 3; for (x = 0; x < imgW; x++) { pixelPtr[x*4 + 0] = UCHAR(((double) xColor->red / USHRT_MAX) * 255); pixelPtr[x*4 + 1] = UCHAR(((double) xColor->green / USHRT_MAX) * 255); pixelPtr[x*4 + 2] = UCHAR(((double) xColor->blue / USHRT_MAX) * 255); } for (y = 0; y < imgH; y++) { for (x = 0; x < imgW; x++) { if (photoPix[x * 4 + 3]) { pixelPtr[x * 4 + 3] = alpha; } else { pixelPtr[x * 4 + 3] = 0; } } TK_PHOTOPUTBLOCK(interp, photoH, &photoBlock, 0, y, imgW, 1, TK_PHOTO_COMPOSITE_OVERLAY); photoPix += pitch; } Tcl_Free((char *) photoBlock.pixelPtr); return TCL_OK; } /* *-------------------------------------------------------------- * * LoupeCmd -- * * This procedure is invoked to process the [loupe] Tcl * command. The command is used to perform a screen grab on the * root window and place a magnified version of the screen grab * into an existing photo image. The command is used to check those * dotted lines and make sure they line up properly. * * Results: * A standard Tcl result. * * Side effects: * A photo image is modified. * *-------------------------------------------------------------- */ static int LoupeCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tk_Window tkwin = Tk_MainWindow(interp); Display *display = Tk_Display(tkwin); int screenNum = Tk_ScreenNumber(tkwin); int displayW = DisplayWidth(display, screenNum); int displayH = DisplayHeight(display, screenNum); char *imageName; Tk_PhotoHandle photoH; Tk_PhotoImageBlock photoBlock; unsigned char *pixelPtr; int x, y, w, h, zoom; int grabX, grabY, grabW, grabH; int minx = 0, miny = 0; #ifdef WIN32 int xx, yy; HWND hwnd; HDC hdc; #define WIN7 #ifdef WIN7 HDC hdcCopy; HBITMAP hBitmap, hBitmapSave; #endif /* WIN7 */ #elif defined(MAC_OSX_TK) #else Visual *visual = Tk_Visual(tkwin); Window rootWindow = RootWindow(display, screenNum); XImage *ximage; XColor *xcolors; unsigned long red_shift, green_shift, blue_shift; int i, ncolors; int separated = 0; #endif /* * x && y are points on screen to snap from * w && h are size of image to grab (default to image size) * zoom is the integer zoom factor to grab */ if ((objc != 4) && (objc != 6) && (objc != 7)) { Tcl_WrongNumArgs(interp, 1, objv, "imageName x y ?w h? ?zoom?"); return TCL_ERROR; } imageName = Tcl_GetStringFromObj(objv[1], NULL); photoH = Tk_FindPhoto(interp, imageName); if (photoH == NULL) { Tcl_AppendResult(interp, "image \"", imageName, "\" doesn't exist or is not a photo image", (char *) NULL); return TCL_ERROR; } if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) { return TCL_ERROR; } if (objc >= 6) { if ((Tcl_GetIntFromObj(interp, objv[4], &w) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[5], &h) != TCL_OK)) { return TCL_ERROR; } } else { /* * Get dimensions from image */ Tk_PhotoGetSize(photoH, &w, &h); } if (objc == 7) { if (Tcl_GetIntFromObj(interp, objv[6], &zoom) != TCL_OK) { return TCL_ERROR; } } else { zoom = 1; } #ifdef WIN32 /* * Windows multiple monitors can have negative coords */ minx = GetSystemMetrics(SM_XVIRTUALSCREEN); miny = GetSystemMetrics(SM_YVIRTUALSCREEN); displayW = GetSystemMetrics(SM_CXVIRTUALSCREEN); displayH = GetSystemMetrics(SM_CYVIRTUALSCREEN); #elif defined(MAC_OSX_TK) /* * OS X multiple monitors can have negative coords * FIX: must be implemented * Probably with CGDisplayPixelsWide & CGDisplayPixelsHigh, * may need to iterate existing displays */ #else /* * Does X11 allow for negative screen coords? */ #endif grabX = x - (w / zoom / 2); grabY = y - (h / zoom / 2); grabW = w / zoom; grabH = h / zoom; if (grabW * zoom < w) ++grabW; if (grabH * zoom < h) ++grabH; if (grabW > displayW) grabW = displayW; if (grabH > displayH) grabH = displayH; if (grabX < minx) grabX = minx; if (grabY < miny) grabY = miny; if (grabX + grabW > displayW) grabX = displayW - grabW; if (grabY + grabH > displayH) grabY = displayH - grabH; if ((grabW <= 0) || (grabH <= 0)) { return TCL_OK; } #ifdef WIN32 hwnd = GetDesktopWindow(); hdc = GetWindowDC(hwnd); #ifdef WIN7 /* Doing GetPixel() on the desktop DC under Windows 7 (Aero) is buggy * and *very* slow. So BitBlt() from the desktop DC to an in-memory * bitmap and run GetPixel() on that. */ hdcCopy = CreateCompatibleDC(hdc); hBitmap = CreateCompatibleBitmap(hdc, grabW, grabH); hBitmapSave = SelectObject(hdcCopy, hBitmap); BitBlt(hdcCopy, 0, 0, grabW, grabH, hdc, grabX, grabY, SRCCOPY | CAPTUREBLT); #endif /* WIN7 */ /* XImage -> Tk_Image */ pixelPtr = (unsigned char *) Tcl_Alloc(grabW * grabH * 4); memset(pixelPtr, 0, (grabW * grabH * 4)); photoBlock.pixelPtr = pixelPtr; photoBlock.width = grabW; photoBlock.height = grabH; photoBlock.pitch = grabW * 4; photoBlock.pixelSize = 4; photoBlock.offset[0] = 0; photoBlock.offset[1] = 1; photoBlock.offset[2] = 2; photoBlock.offset[3] = 3; /* * We could do a BitBlt for bulk copying, but then we'd have to * do screen size consistency checks and possibly pixel conversion. */ for (yy = 0; yy < grabH; yy++) { COLORREF pixel; unsigned long stepDest = yy * photoBlock.pitch; for (xx = 0; xx < grabW; xx++) { #ifdef WIN7 pixel = GetPixel(hdcCopy, xx, yy); #else /* WIN7 */ pixel = GetPixel(hdc, grabX + xx, grabY + yy); #endif /* WIN7 */ if (pixel == CLR_INVALID) { /* * Skip just this pixel, as others will be valid depending on * what corner we are in. */ continue; } pixelPtr[stepDest + xx * 4 + 0] = GetRValue(pixel); pixelPtr[stepDest + xx * 4 + 1] = GetGValue(pixel); pixelPtr[stepDest + xx * 4 + 2] = GetBValue(pixel); pixelPtr[stepDest + xx * 4 + 3] = 255; } } #ifdef WIN7 SelectObject(hdcCopy, hBitmapSave); DeleteObject(hBitmap); DeleteDC(hdcCopy); #endif /* WIN7 */ ReleaseDC(hwnd, hdc); #elif defined(MAC_OSX_TK) /* * Adapted from John Anon's ScreenController demo code. */ { int xx, yy; unsigned char *screenBytes; int bPerPixel, byPerRow, byPerPixel; /* Gets all the screen info: */ CGDisplayHideCursor(kCGDirectMainDisplay); bPerPixel = CGDisplayBitsPerPixel(kCGDirectMainDisplay); byPerRow = CGDisplayBytesPerRow(kCGDirectMainDisplay); byPerPixel = bPerPixel / 8; screenBytes = (unsigned char *)CGDisplayBaseAddress(kCGDirectMainDisplay); pixelPtr = (unsigned char *) Tcl_Alloc(grabW * grabH * 4); memset(pixelPtr, 0, (grabW * grabH * 4)); photoBlock.pixelPtr = pixelPtr; photoBlock.width = grabW; photoBlock.height = grabH; photoBlock.pitch = grabW * 4; photoBlock.pixelSize = 4; photoBlock.offset[0] = 0; photoBlock.offset[1] = 1; photoBlock.offset[2] = 2; photoBlock.offset[3] = 3; for (yy = 0; yy < grabH; yy++) { unsigned long newPixel = 0; unsigned long stepSrc = (grabY + yy) * byPerRow; unsigned long stepDest = yy * photoBlock.pitch; for (xx = 0; xx < grabW; xx++) { if (bPerPixel == 16) { unsigned short thisPixel; thisPixel = *((unsigned short*)(screenBytes + stepSrc + ((grabX + xx) * byPerPixel))); #ifdef WORDS_BIGENDIAN /* Transform from 0xARGB (1555) to 0xR0G0B0A0 (4444) */ newPixel = (((thisPixel & 0x8000) >> 15) * 0xF8) | /* A */ ((thisPixel & 0x7C00) << 17) | /* R */ ((thisPixel & 0x03E0) << 14) | /* G */ ((thisPixel & 0x001F) << 11); /* B */ #else /* Transform from 0xARGB (1555) to 0xB0G0R0A0 (4444) */ newPixel = (((thisPixel & 0x8000) >> 15) * 0xF8) | /* A */ ((thisPixel & 0x7C00) << 11) | /* R */ ((thisPixel & 0x03E0) << 14) | /* G */ ((thisPixel & 0x001F) << 17); /* B */ #endif } else if (bPerPixel == 32) { unsigned long thisPixel; thisPixel = *((unsigned long*)(screenBytes + stepSrc + ((grabX + xx) * byPerPixel))); #ifdef WORDS_BIGENDIAN /* Transformation is from 0xAARRGGBB to 0xRRGGBBAA */ newPixel = ((thisPixel & 0xFF000000) >> 24) | ((thisPixel & 0x00FFFFFF) << 8); #else /* Transformation is from 0xAARRGGBB to 0xBBGGRRAA */ newPixel = (thisPixel & 0xFF00FF00) | ((thisPixel & 0x00FF0000) >> 16) | ((thisPixel & 0x000000FF) << 16); #endif } *((unsigned int *)(pixelPtr + stepDest + xx * 4)) = newPixel; } } CGDisplayShowCursor(kCGDirectMainDisplay); } #else ximage = XGetImage(display, rootWindow, grabX, grabY, grabW, grabH, AllPlanes, ZPixmap); if (ximage == NULL) { FormatResult(interp, "XGetImage() failed"); return TCL_ERROR; } /* See TkPostscriptImage */ ncolors = visual->map_entries; xcolors = (XColor *) ckalloc(sizeof(XColor) * ncolors); if ((visual->class == DirectColor) || (visual->class == TrueColor)) { separated = 1; red_shift = green_shift = blue_shift = 0; while ((0x0001 & (ximage->red_mask >> red_shift)) == 0) red_shift++; while ((0x0001 & (ximage->green_mask >> green_shift)) == 0) green_shift++; while ((0x0001 & (ximage->blue_mask >> blue_shift)) == 0) blue_shift++; for (i = 0; i < ncolors; i++) { xcolors[i].pixel = ((i << red_shift) & ximage->red_mask) | ((i << green_shift) & ximage->green_mask) | ((i << blue_shift) & ximage->blue_mask); } } else { for (i = 0; i < ncolors; i++) xcolors[i].pixel = i; red_shift = green_shift = blue_shift = 0; /* compiler warning */ } XQueryColors(display, Tk_Colormap(tkwin), xcolors, ncolors); /* XImage -> Tk_Image */ pixelPtr = (unsigned char *) Tcl_Alloc(ximage->width * ximage->height * 4); photoBlock.pixelPtr = pixelPtr; photoBlock.width = ximage->width; photoBlock.height = ximage->height; photoBlock.pitch = ximage->width * 4; photoBlock.pixelSize = 4; photoBlock.offset[0] = 0; photoBlock.offset[1] = 1; photoBlock.offset[2] = 2; photoBlock.offset[3] = 3; for (y = 0; y < ximage->height; y++) { for (x = 0; x < ximage->width; x++) { int r, g, b; unsigned long pixel; pixel = XGetPixel(ximage, x, y); if (separated) { r = (pixel & ximage->red_mask) >> red_shift; g = (pixel & ximage->green_mask) >> green_shift; b = (pixel & ximage->blue_mask) >> blue_shift; r = ((double) xcolors[r].red / USHRT_MAX) * 255; g = ((double) xcolors[g].green / USHRT_MAX) * 255; b = ((double) xcolors[b].blue / USHRT_MAX) * 255; } else { r = ((double) xcolors[pixel].red / USHRT_MAX) * 255; g = ((double) xcolors[pixel].green / USHRT_MAX) * 255; b = ((double) xcolors[pixel].blue / USHRT_MAX) * 255; } pixelPtr[y * photoBlock.pitch + x * 4 + 0] = r; pixelPtr[y * photoBlock.pitch + x * 4 + 1] = g; pixelPtr[y * photoBlock.pitch + x * 4 + 2] = b; pixelPtr[y * photoBlock.pitch + x * 4 + 3] = 255; } } #endif TK_PHOTOPUTZOOMEDBLOCK(interp, photoH, &photoBlock, 0, 0, w, h, zoom, zoom, 1, 1, TK_PHOTO_COMPOSITE_SET); Tcl_Free((char *) pixelPtr); #if !defined(WIN32) && !defined(MAC_OSX_TK) ckfree((char *) xcolors); XDestroyImage(ximage); #endif return TCL_OK; } #ifndef USE_TTK /* *-------------------------------------------------------------- * * RecomputeWidgets -- * * This procedure is called when the system theme changes on platforms * that support theming. The worldChangedProc of all treectrl widgets * is called to relayout and redisplay the widgets. * * Taken from tkFont.c. * * Results: * None. * * Side effects: * All treectrl widgets will be redisplayed at idle time. * *-------------------------------------------------------------- */ static void RecomputeWidgets( TkWindow *winPtr /* Window info. */ ) { Tk_ClassWorldChangedProc *proc; /* Clomp! Stomp! All over the internals */ proc = Tk_GetClassProc(winPtr->classProcsPtr, worldChangedProc); if (proc == TreeWorldChanged) { TreeTheme_ThemeChanged((TreeCtrl *) winPtr->instanceData); TreeWorldChanged(winPtr->instanceData); } for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) { RecomputeWidgets(winPtr); } } /* *-------------------------------------------------------------- * * Tree_TheWorldHasChanged -- * * This procedure is called when the system theme changes on platforms * that support theming. The worldChangedProc of all treectrl widgets * is called to relayout and redisplay the widgets. * * Results: * None. * * Side effects: * All treectrl widgets will be redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_TheWorldHasChanged( Tcl_Interp *interp /* Current interpreter. */ ) { /* Could send a <> event to every window like Tile does. */ /* Could keep a list of treectrl widgets. */ TkWindow *winPtr = (TkWindow *) Tk_MainWindow(interp); RecomputeWidgets(winPtr); } #endif /* !USE_TTK */ /* * In order to find treectrl.tcl during initialization, the following script * is invoked. */ static char initScript[] = "if {![llength [info proc ::TreeCtrl::Init]]} {\n\ namespace eval ::TreeCtrl {}\n\ proc ::TreeCtrl::Init {} {\n\ global treectrl_library\n\ tcl_findLibrary treectrl " PACKAGE_PATCHLEVEL " " PACKAGE_PATCHLEVEL " treectrl.tcl TREECTRL_LIBRARY treectrl_library\n\ }\n\ }\n\ ::TreeCtrl::Init"; /* *-------------------------------------------------------------- * * Treectrl_Init -- * * This procedure initializes the TreeCtrl package and related * commands. * * Results: * A standard Tcl result. * * Side effects: * Memory is allocated. New Tcl commands are created. * *-------------------------------------------------------------- */ DLLEXPORT int Treectrl_Init( Tcl_Interp *interp /* Interpreter the package is loading into. */ ) { #ifdef USE_TTK static CONST char *tcl_version = "8.5"; #else static CONST char *tcl_version = "8.4"; #endif Tk_OptionSpec *specPtr; #ifdef TREECTRL_DEBUG Tk_OptionSpec *prevSpecPtr = NULL; #endif #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, tcl_version, 0) == NULL) { return TCL_ERROR; } #endif #ifdef USE_TK_STUBS #if (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 5) if (Tk_InitStubs(interp, (char*)tcl_version, 0) == NULL) { #else if (Tk_InitStubs(interp, tcl_version, 0) == NULL) { #endif return TCL_ERROR; } #endif dbwin_add_interp(interp); #ifdef TREECTRL_DEBUG for (specPtr = optionSpecs; specPtr->type != TK_OPTION_END; specPtr++) { if (prevSpecPtr != NULL && strcmp(prevSpecPtr->optionName, specPtr->optionName) >= 0) { panic("Treectrl_Init option table ordering %s >= %s", prevSpecPtr->optionName, specPtr->optionName); } prevSpecPtr = specPtr; } #endif PerStateCO_Init(optionSpecs, "-buttonbitmap", &pstBitmap, TreeStateFromObj); PerStateCO_Init(optionSpecs, "-buttonimage", &pstImage, TreeStateFromObj); /* Try to create TkHeadingFont. If it exists, an error is returned, in * which case we will use it as the default value of -headerfont. * If TkHeadingFont doesn't exist (as in Tk 8.4), no error is returned, * in which case the new font is deleted and the default value of * -headerfont is set to DEF_LISTBOX_FONT. */ /* Would be nice if there was an API to test for named font existence. */ /* FIXME: this is only done on the first interpreter we are loaded into. * What if TkHeadingFont isn't in another interpreter? */ specPtr = Tree_FindOptionSpec(optionSpecs, "-headerfont"); if (specPtr->defValue == NULL) { if (Tcl_GlobalEval(interp, "font create TkHeadingFont") != TCL_OK) { Tcl_ResetResult(interp); specPtr->defValue = "TkHeadingFont"; } else { Tcl_GlobalEval(interp, "font delete TkHeadingFont"); specPtr->defValue = DEF_LISTBOX_FONT; } } if (TreeElement_InitInterp(interp) != TCL_OK) return TCL_ERROR; (void) TreeDraw_InitInterp(interp); /* We don't care if this fails. */ (void) TreeTheme_InitInterp(interp); if (TreeColumn_InitInterp(interp) != TCL_OK) return TCL_ERROR; /* Set the default value of some options. */ /* Do this *after* the system theme is initialized. */ TreeTheme_SetOptionDefault( Tree_FindOptionSpec(optionSpecs, "-buttontracking")); TreeTheme_SetOptionDefault( Tree_FindOptionSpec(optionSpecs, "-showlines")); /* Hack for editing a text Element. */ Tcl_CreateObjCommand(interp, "textlayout", TextLayoutCmd, NULL, NULL); /* Hack for colorizing an image (like Win98 explorer). */ Tcl_CreateObjCommand(interp, "imagetint", ImageTintCmd, NULL, NULL); /* Screen magnifier to check those dotted lines. */ Tcl_CreateObjCommand(interp, "loupe", LoupeCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "treectrl", TreeObjCmd, NULL, NULL); if (Tcl_PkgProvide(interp, PACKAGE_NAME, PACKAGE_PATCHLEVEL) != TCL_OK) { return TCL_ERROR; } return Tcl_EvalEx(interp, initScript, -1, TCL_EVAL_GLOBAL); } /* *-------------------------------------------------------------- * * Treectrl_SafeInit -- * * This procedure initializes the TreeCtrl package and related * commands. * * Results: * A standard Tcl result. * * Side effects: * Memory is allocated. New Tcl commands are created. * *-------------------------------------------------------------- */ DLLEXPORT int Treectrl_SafeInit( Tcl_Interp *interp /* Interpreter the package is loading into. */ ) { return Treectrl_Init(interp); } tktreectrl-2.4.1/generic/tkTreeCtrl.h0000644000076400010400000023270311573760373020106 0ustar TimAdministrators/* * tkTreeCtrl.h -- * * This module is the header for treectrl widgets for the Tk toolkit. * * Copyright (c) 2002-2011 Tim Baker * Copyright (c) 2002-2003 Christian Krone * Copyright (c) 2003 ActiveState Corporation */ #include "tkPort.h" #include "default.h" #include "tclInt.h" #include "tkInt.h" #include "qebind.h" /* * Used to tag functions that are only to be visible within the module being * built and not outside it (where this is supported by the linker). */ #ifndef MODULE_SCOPE # ifdef __cplusplus # define MODULE_SCOPE extern "C" # else # define MODULE_SCOPE extern # endif #endif /* * Macros used to cast between pointers and integers (e.g. when storing an int * in ClientData), on 64-bit architectures they avoid gcc warning about "cast * to/from pointer from/to integer of different size". */ #if !defined(INT2PTR) && !defined(PTR2INT) # if defined(HAVE_INTPTR_T) || defined(intptr_t) # define INT2PTR(p) ((void *)(intptr_t)(p)) # define PTR2INT(p) ((int)(intptr_t)(p)) # else # define INT2PTR(p) ((void *)(p)) # define PTR2INT(p) ((int)(p)) # endif #endif #ifdef PLATFORM_SDL #undef WIN32 #endif #define dbwin TreeCtrl_dbwin #define dbwin_add_interp TreeCtrl_dbwin_add_interp MODULE_SCOPE void dbwin(char *fmt, ...); MODULE_SCOPE void dbwin_add_interp(Tcl_Interp *interp); #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifdef WIN32 #define vsnprintf _vsnprintf #endif #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif #define SELECTION_VISIBLE #define ALLOC_HAX #define DEPRECATED /* #define DRAG_PIXMAP */ /* #define DRAGIMAGE_STYLE */ /* Use an item style as the dragimage instead of XOR rectangles. */ #define USE_ITEM_PIXMAP 1 #define COLUMNGRID 1 typedef struct TreeCtrl TreeCtrl; typedef struct TreeColumn_ *TreeColumn; typedef struct TreeColumnPriv_ *TreeColumnPriv; typedef struct TreeColumnDInfo_ *TreeColumnDInfo; typedef struct TreeDInfo_ *TreeDInfo; typedef struct TreeDragImage_ *TreeDragImage; typedef struct TreeItem_ *TreeItem; typedef struct TreeItemColumn_ *TreeItemColumn; typedef struct TreeItemDInfo_ *TreeItemDInfo; typedef struct TreeMarquee_ *TreeMarquee; typedef struct TreeItemRInfo_ *TreeItemRInfo; typedef struct TreeStyle_ *TreeStyle; typedef struct TreeElement_ *TreeElement; typedef struct TreeThemeData_ *TreeThemeData; typedef struct TreeGradient_ *TreeGradient; typedef struct TreeHeader_ *TreeHeader; typedef struct TreeHeaderColumn_ *TreeHeaderColumn; typedef struct StyleDrawArgs StyleDrawArgs; typedef struct TagInfo TagInfo; /*****/ typedef struct PerStateInfo PerStateInfo; typedef struct PerStateData PerStateData; typedef struct PerStateType PerStateType; /* A structure of the following type is kept for each {value stateList} pair * for a single per-state option. */ struct PerStateData { int stateOff; /* States that must be off. */ int stateOn; /* States that must be on. */ /* Type-specific fields go here. */ /* See PerStateDataBorder, PerStateDataFont, etc. */ }; /* A structure of the following type represents the value of a per-state * option. */ struct PerStateInfo { #ifdef TREECTRL_DEBUG PerStateType *type; #endif Tcl_Obj *obj; /* The configured option value, a list object * of the form {value stateList ...}. * Each 'value' is a font, color etc. * Each 'stateList' is a list of state names * possibly preceded by "!". */ int count; /* The number of entries in 'data'. */ PerStateData *data; /* malloc'd array parsed from 'obj'. */ }; typedef int (*PerStateType_FromObjProc)(TreeCtrl *, Tcl_Obj *, PerStateData *); typedef void (*PerStateType_FreeProc)(TreeCtrl *, PerStateData *); /* A structure of the following type is kept for each per-state data type. */ struct PerStateType { CONST char *name; /* Name for debugging purposes. */ int size; /* Size of PerStateData + type-specific * fields. */ PerStateType_FromObjProc fromObjProc; /* Convert a Tcl_Obj to this type's * PerStateData internal representation, * a Tk_Font, XColor, etc. */ PerStateType_FreeProc freeProc; /* Free the internal representation. */ }; /*****/ typedef struct { XColor *color; #if 0 double opacity; #endif TreeGradient gradient; } TreeColor; #define TREECOLOR_CMP2(a,b) (((a)->color!=(b)->color)||((a)->gradient!=(b)->gradient)) #define TREECOLOR_CMP(a,b) ((!(a)!=!(b))||(((a)&&(b))&&TREECOLOR_CMP2(a,b))) /* A structure of the following type is used to remember a drawable and its * dimensions. Some drawing operations must be clipped to the actual bounds * of a drawable (on X11 only?). */ typedef struct { Drawable drawable; int width; int height; } TreeDrawable; /* A structure of the following type represents a rectangle. XRectangle * uses short integers which often aren't large enough. */ typedef struct { int x, y; int width, height; } TreeRectangle; #define TreeRect_Left(tr) ((tr).x) #define TreeRect_Top(tr) ((tr).y) #define TreeRect_Right(tr) ((tr).x + (tr).width) #define TreeRect_Bottom(tr) ((tr).y + (tr).height) #define TreeRect_Width(tr) ((tr).width) #define TreeRect_Height(tr) ((tr).height) #define TreeRect_XYWH(tr,X,Y,W,H) ((*X)=TreeRect_Left(tr),(*Y)=TreeRect_Top(tr),\ (*W)=TreeRect_Width(tr),(*H)=TreeRect_Height(tr)) #define TreeRect_SetXYWH(tr,X,Y,W,H) ((tr).x=(X),(tr).y=(Y),\ (tr).width=(W),(tr).height=(H)) #define TreeRect_XYXY(tr,X1,Y1,X2,Y2) ((*X1)=TreeRect_Left(tr),(*Y1)=TreeRect_Top(tr),\ (*X2)=TreeRect_Right(tr),(*Y2)=TreeRect_Bottom(tr)) #define TreeRect_SetXYXY(tr,X1,Y1,X2,Y2) ((tr).x=(X1),(tr).y=(Y1),\ (tr).width=(X2)-(X1),(tr).height=(Y2)-(Y1)) #define TreeRect_ClipPoint(tr,XP,YP) \ do { \ if ((*XP) < (tr).x) (*XP)=(tr).x; \ if ((*XP) >= TreeRect_Right(tr)) (*XP) = TreeRect_Right(tr) - 1; \ if ((*YP) < (tr).y) (*YP)=(tr).y; \ if ((*YP) >= TreeRect_Bottom(tr)) (*YP) = TreeRect_Bottom(tr) - 1; \ } while (0) #define TreeRect_FromXRect(xr,trp) ((trp)->x=(xr).x, (trp)->y=(xr).y, \ (trp)->width=(xr).width, (trp)->height=(xr).height) #define TreeRect_ToXRect(tr,xrp) ((xrp)->x=(tr).x, (xrp)->y=(tr).y, \ (xrp)->width=(tr).width, (xrp)->height=(tr).height) typedef struct GCCache GCCache; struct GCCache { unsigned long mask; XGCValues gcValues; GC gc; GCCache *next; }; /* * A TreePtrList is used for dynamically-growing lists of ClientData pointers. * A TreePtrList is NULL-terminated. * Based on Tcl_DString code. */ #define TIL_STATIC_SPACE 128 typedef struct TreePtrList TreePtrList; typedef TreePtrList TreeItemList; typedef TreePtrList TreeColumnList; struct TreePtrList { #ifdef TREECTRL_DEBUG char magic[4]; #endif TreeCtrl *tree; ClientData *pointers; /* NULL-terminated list of pointers. */ int count; /* Number of items. */ int space; /* Number of slots pointed to by pointers[]. */ ClientData pointerSpace[TIL_STATIC_SPACE]; /* Space to use in common case * where the list is small. */ }; enum { LEFT, TOP, RIGHT, BOTTOM }; /* A structure of the following type is kept for each TreeCtrl to hold the * values of debug-related configuration options and other related fields. */ struct TreeCtrlDebug { Tk_OptionTable optionTable; int enable; /* Turn all debugging on/off */ int data; /* Debug data structures */ int display; /* Debug display routines */ int span; /* Debug column spanning */ int textLayout; /* Debug text layout */ int displayDelay; /* Delay between copy/draw operations */ XColor *eraseColor; /* Erase "invalidated" areas */ GC gcErase; /* for eraseColor */ XColor *drawColor; /* Erase about-to-be-drawn areas */ GC gcDraw; /* for eraseColor */ }; /* A structure of the following type is kept for each TreeCtrl to hold the * values of header drag-and-drop configuration options and other related * fields. */ struct TreeCtrlColumnDrag { Tk_OptionTable optionTable; int enable; /* -enable */ TreeColumn column; /* -imagecolumn */ Tcl_Obj *offsetObj; /* -imageoffset */ int offset; /* -imageoffset */ XColor *color; /* -imagecolor */ int alpha; /* -imagealpha */ int span; /* -imagespan */ TreeColumn indColumn; /* -indicatorcolumn */ XColor *indColor; /* -indicatorcolor */ int indSide; /* -indicatorside */ int indSpan; /* -indicatorspan */ int imageEpoch; }; /* A structure of the following type is kept for each TreeCtrl to hold the * names of static and dynamic states in each STATE_DOMAIN_XXX. */ typedef struct TreeStateDomain TreeStateDomain; struct TreeStateDomain { CONST char *name; /* Human-readable name of this domain. */ char *stateNames[32]; /* Sparse array of state names. */ int staticCount; /* Number of static states. */ }; /* A structure of the following type represents a unique signature for each * TreeStyle that is managed privately for use in column headers. A different * header style is needed to for some header configuration options, such as * -justify, but not for others, such as -arrow which are handled by the * 'header' element type. */ typedef struct HeaderStyleParams HeaderStyleParams; struct HeaderStyleParams { Tk_Justify justify; /* -justify */ int bitmap; /* 1 if -bitmap is specified, 0 if -bitmap * is unspecified or -image is specified. */ int image; /* 1 if -image is specified. */ int imagePadX[2]; /* -imagepadx */ int imagePadY[2]; /* -imagepady */ int text; /* 1 if -text is specified, 0 otherwise. */ int textPadX[2]; /* -textpadx */ int textPadY[2]; /* -textpady */ }; /* A structure of the following type is kept for each TreeStyle that is * managed privately for use in column headers. */ typedef struct HeaderStyle HeaderStyle; struct HeaderStyle { TreeStyle style; /* A master style for use in a column * header. */ HeaderStyleParams params; /* Unique signature for this style. */ HeaderStyle *next; /* Linked list of all header styles. */ }; /* A structure of the following type is kept for each treectrl widget. */ struct TreeCtrl { /* Standard stuff */ Tk_Window tkwin; Display *display; Tcl_Interp *interp; Tcl_Command widgetCmd; Tk_OptionTable optionTable; /* Configuration options */ Tcl_Obj *fgObj; /* -foreground */ XColor *fgColorPtr; /* -foreground */ Tcl_Obj *borderWidthObj; /* -borderwidth */ int borderWidth; /* -borderwidth */ Tk_3DBorder border; /* -background */ Tk_Cursor cursor; /* Current cursor for window, or None. */ int relief; /* -relief */ Tcl_Obj *highlightWidthObj; /* -highlightthickness */ int highlightWidth; /* -highlightthickness */ XColor *highlightBgColorPtr; /* -highlightbackground */ XColor *highlightColorPtr; /* -highlightcolor */ char *xScrollCmd; /* -xscrollcommand */ char *yScrollCmd; /* -yscrollcommand */ Tcl_Obj *xScrollDelay; /* -xscrolldelay: used by scripts */ Tcl_Obj *yScrollDelay; /* -yscrolldelay: used by scripts */ int xScrollIncrement; /* -xscrollincrement */ int yScrollIncrement; /* -yscrollincrement */ int xScrollSmoothing; /* -xscrollsmoothing */ int yScrollSmoothing; /* -yscrollsmoothing */ #define SMOOTHING_X 0x01 #define SMOOTHING_Y 0x02 int scrollSmoothing; /* */ Tcl_Obj *scrollMargin; /* -scrollmargin: used by scripts */ char *takeFocus; /* -takfocus */ Tcl_Obj *fontObj; /* -font */ Tk_Font tkfont; /* -font */ Tcl_Obj *headerFontObj; /* -headerfont */ Tk_Font tkfontHeader; /* -headerfont */ int showButtons; /* boolean: Draw expand/collapse buttons */ int showLines; /* boolean: Draw lines connecting parent to * child */ int showRootLines; /* boolean: Draw lines connecting children * of the root item */ int showRoot; /* boolean: Draw the unique root item */ int showRootButton; /* boolean: Draw expand/collapse button for * root item */ int showRootChildButtons; /* boolean: Draw expand/collapse buttons for * children of the root item */ int showHeader; /* boolean: show column titles */ Tcl_Obj *indentObj; /* pixels: offset of child relative to * parent */ int indent; /* pixels: offset of child relative to * parent */ char *selectMode; /* -selectmode: used by scripts only */ Tcl_Obj *itemHeightObj; /* -itemheight: Fixed height for all items (unless overridden) */ int itemHeight; /* -itemheight */ Tcl_Obj *minItemHeightObj; /* -minitemheight: Minimum height for all items */ int minItemHeight; /* -minitemheight */ Tcl_Obj *itemWidthObj; /* -itemwidth */ int itemWidth; /* -itemwidth */ int itemWidthEqual; /* -itemwidthequal */ Tcl_Obj *itemWidMultObj; /* -itemwidthmultiple */ int itemWidMult; /* -itemwidthmultiple */ Tcl_Obj *widthObj; /* -width */ int width; /* -width */ Tcl_Obj *heightObj; /* -height */ int height; /* -height */ TreeColumn columnTree; /* column where buttons/lines are drawn */ #define DOUBLEBUFFER_NONE 0 #define DOUBLEBUFFER_ITEM 1 #define DOUBLEBUFFER_WINDOW 2 int doubleBuffer; /* -doublebuffer */ XColor *buttonColor; /* -buttoncolor */ Tcl_Obj *buttonSizeObj; /* -buttonSize */ int buttonSize; /* -buttonsize */ Tcl_Obj *buttonThicknessObj;/* -buttonthickness */ int buttonThickness; /* -buttonthickness */ int buttonTracking; /* -buttontracking */ XColor *lineColor; /* -linecolor */ Tcl_Obj *lineThicknessObj; /* -linethickness */ int lineThickness; /* -linethickness */ #define LINE_STYLE_DOT 0 #define LINE_STYLE_SOLID 1 int lineStyle; /* -linestyle */ int vertical; /* -orient */ Tcl_Obj *wrapObj; /* -wrap */ PerStateInfo buttonImage; /* -buttonimage */ PerStateInfo buttonBitmap; /* -buttonbitmap */ char *backgroundImageString; /* -backgroundimage */ Tk_Anchor bgImageAnchor; /* -bgimageanchor */ int bgImageOpaque; /* -bgimageopaque */ #define BGIMG_SCROLL_X 0x01 #define BGIMG_SCROLL_Y 0x02 Tcl_Obj *bgImageScrollObj; /* -bgimagescroll */ int bgImageScroll; /* -bgimagescroll */ #define BGIMG_TILE_X 0x01 #define BGIMG_TILE_Y 0x02 Tcl_Obj *bgImageTileObj; /* -bgimagetile */ int bgImageTile; /* -bgimagetile */ int useIndent; /* MAX of open/closed button width and * indent */ int buttonHeightMax; /* Maximum height of a button in any state. */ #define BG_MODE_COLUMN 0 #define BG_MODE_ORDER 1 #define BG_MODE_ORDERVIS 2 #define BG_MODE_ROW 3 #ifdef DEPRECATED #define BG_MODE_INDEX 4 /* compatibility */ #define BG_MODE_VISINDEX 5 /* compatibility */ #endif /* DEPRECATED */ int backgroundMode; /* -backgroundmode */ int columnResizeMode; /* -columnresizemode */ int *canvasPadX; /* -canvaspadx */ Tcl_Obj *canvasPadXObj; /* -canvaspadx */ int *canvasPadY; /* -canvaspady */ Tcl_Obj *canvasPadYObj; /* -canvaspady */ int itemGapX; /* -itemgapx */ Tcl_Obj *itemGapXObj; /* -itemgapx */ int itemGapY; /* -itemgapy */ Tcl_Obj *itemGapYObj; /* -itemgapy */ struct TreeCtrlDebug debug; struct TreeCtrlColumnDrag columnDrag; /* Other stuff */ int gotFocus; /* flag */ int deleted; /* flag */ int updateIndex; /* flag */ int isActive; /* flag: mac & win "active" toplevel */ struct { int left; int top; int right; int bottom; } inset; /* borderWidth + highlightWidth */ int xOrigin; /* offset from content x=0 to window x=0 */ int yOrigin; /* offset from content y=0 to window y=0 */ GC copyGC; GC textGC; GC headerTextGC; GC buttonGC; GC lineGC[2]; Tk_Image backgroundImage; /* -backgroundimage */ int useTheme; /* -usetheme */ char *itemPrefix; /* -itemprefix */ char *columnPrefix; /* -columnprefix */ int prevWidth; int prevHeight; int drawableXOrigin; int drawableYOrigin; TreeColumn columns; /* List of columns */ TreeColumn columnLast; /* Last in list of columns */ TreeColumn columnTail; /* Last infinitely-wide column */ TreeColumn columnVis; /* First visible non-locked column */ int columnCount; /* Number of columns */ int columnCountVis; /* Number of visible columns */ int headerHeight; /* Height of column titles */ int themeHeaderHeight; /* Fixed theme height of column titles */ int widthOfColumns; /* Sum of column widths */ int columnTreeLeft; /* left of column where buttons/lines are * drawn */ int columnTreeVis; /* TRUE if columnTree is visible */ int columnBgCnt; /* Max -itembackground colors */ #if COLUMNGRID == 1 int columnsWithGridLines; /* # visible columns with grid lines. */ #endif #define COLUMN_LOCK_LEFT 0 #define COLUMN_LOCK_NONE 1 #define COLUMN_LOCK_RIGHT 2 TreeColumn columnLockLeft; /* First left-locked column */ TreeColumn columnLockNone; /* First unlocked column */ TreeColumn columnLockRight; /* First right-locked column */ int widthOfColumnsLeft; /* Sum of left-locked column widths */ int widthOfColumnsRight; /* Sum of right-locked column widths */ int columnCountVisLeft; /* Number of visible left-locked columns */ int columnCountVisRight; /* Number of visible right-locked columns */ int displayLockedColumns; /* Last seen value of * Tree_ShouldDisplayLockedColumns() */ #define UNIFORM_GROUP #ifdef UNIFORM_GROUP Tcl_HashTable uniformGroupHash; /* -uniform -> UniformGroup */ #endif Tcl_Obj *headerFgObj; /* -headerforeground */ XColor *defHeaderTextColor; /* Default column header text color when * the column's -textcolor option * is not specified and the system theme * doesn't specify a color. */ TreeItem root; TreeItem activeItem; TreeItem anchorItem; int nextItemId; int nextColumnId; Tcl_HashTable itemHash; /* TreeItem.id -> TreeItem */ Tcl_HashTable itemSpansHash; /* TreeItem -> nothing */ Tcl_HashTable elementHash; /* Element.name -> Element */ Tcl_HashTable styleHash; /* Style.name -> Style */ Tcl_HashTable imageNameHash; /* image name -> TreeImageRef */ Tcl_HashTable imageTokenHash; /* Tk_Image -> TreeImageRef */ int depth; /* max depth of items under root */ int itemCount; /* Total number of items */ int itemVisCount; /* Total number of ReallyVisible() items */ int itemWrapCount; /* ReallyVisible() items with -wrap=true */ QE_BindingTable bindingTable; TreeDragImage dragImage; TreeMarquee marquee; TreeDInfo dInfo; int selectCount; /* Number of selected items */ Tcl_HashTable selection; /* Selected items */ #define TREE_WRAP_NONE 0 #define TREE_WRAP_ITEMS 1 #define TREE_WRAP_PIXELS 2 #define TREE_WRAP_WINDOW 3 int wrapMode; /* TREE_WRAP_xxx */ int wrapArg; /* Number of items, number of pixels */ int totalWidth; /* Max/Sum of all TreeRanges */ int totalHeight; /* Max/Sum of all TreeRanges */ struct { Tcl_Obj *xObj; int x; /* Window coords */ int sx; /* Window coords */ int onScreen; } columnProxy; #define STATE_DOMAIN_ITEM 0 #define STATE_DOMAIN_HEADER 1 TreeStateDomain stateDomain[2]; int configStateDomain; int scanX; /* [scan mark] and [scan dragto] */ int scanY; int scanXOrigin; int scanYOrigin; Tk_OptionTable styleOptionTable; #ifdef DEPRECATED struct { Tcl_Obj *stylesObj; TreeStyle *styles; int numStyles; } defaultStyle; #endif /* DEPRECATED */ Tk_OptionTable itemOptionTable; int itemPrefixLen; /* -itemprefix */ int columnPrefixLen; /* -columnprefix */ #ifdef ALLOC_HAX ClientData allocData; #endif int preserveItemRefCnt; /* Ref count so items-in-use aren't freed. */ TreeItemList preserveItemList; /* List of items to be deleted when * preserveItemRefCnt==0. */ struct { Tcl_Obj *yObj; int y; /* Window coords */ int sy; /* Window coords */ int onScreen; } rowProxy; char *optionHax[64]; /* Used by OptionHax_xxx */ int optionHaxCnt; /* Used by OptionHax_xxx */ TreeThemeData themeData; GCCache *gcCache; /* Graphics contexts for elements. */ TkRegion regionStack[8]; /* Temp region stack. */ int regionStackLen; /* Number of unused regions in regionStack. */ int itemTagExpr; /* Enable/disable operators in item tags */ int columnTagExpr; /* Enable/disable operators in column tags */ Tk_OptionTable gradientOptionTable; Tcl_HashTable gradientHash; /* TreeGradient.name -> TreeGradient */ int nativeGradients; /* Preference, not availability. */ Tk_OptionTable headerOptionTable; Tk_OptionTable headerColumnOptionTable; Tk_OptionTable headerDragOptionTable; TreeItem headerItems; int headerCount; int nextHeaderId; Tcl_HashTable headerHash; /* TreeItem.id -> TreeItem */ int tailExtend; /* This is the distance the tail column * extends past the right edge of the * content area. */ struct { int nextId; /* Next unique id number for a header style. */ HeaderStyle *first; /* First in linked list of header styles. */ TreeElement headerElem; /* Master element used by header styles. */ TreeElement bitmapElem; /* Master element used by header styles. */ TreeElement imageElem; /* Master element used by header styles. */ TreeElement textElem; /* Master element used by header styles. */ } headerStyle; /* These two options contain "-image" and "-text". * They are used by the [item image] and [item text] commands. * Originally these were static globals but that isn't thread safe. */ Tcl_Obj *imageOptionNameObj; Tcl_Obj *textOptionNameObj; /* Originally these were static globals but that isn't thread safe. */ Tcl_Obj *formatFloatObj; /* %g */ Tcl_Obj *formatIntObj; /* %d */ Tcl_Obj *formatLongObj; /* %ld */ Tcl_Obj *formatStringObj; /* %s */ Tcl_Obj *stringClockObj; /* clock */ Tcl_Obj *stringFormatObj; /* format */ Tcl_Obj *optionFormatObj; /* -format */ TreeColumnPriv columnPriv; ClientData itemSpanPriv; #ifdef TREECTRL_DEBUG struct { int inLayoutColumns; } debugCheck; #endif }; #define TREE_CONF_FONT 0x0001 #define TREE_CONF_ITEMSIZE 0x0002 #define TREE_CONF_INDENT 0x0004 #define TREE_CONF_WRAP 0x0008 #define TREE_CONF_BUTIMG 0x0010 #define TREE_CONF_BUTBMP 0x0020 #define TREE_CONF_BORDERS 0x0040 #define TREE_CONF_BGIMGOPT 0x0080 #define TREE_CONF_RELAYOUT 0x0100 #define TREE_CONF_REDISPLAY 0x0200 #define TREE_CONF_FG 0x0400 #define TREE_CONF_PROXY 0x0800 #define TREE_CONF_BUTTON 0x1000 #define TREE_CONF_LINE 0x2000 #define TREE_CONF_DEFSTYLE 0x4000 #define TREE_CONF_BG_IMAGE 0x8000 #define TREE_CONF_THEME 0x00010000 MODULE_SCOPE void Tree_AddItem(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void Tree_RemoveItem(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void Tree_AddHeader(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void Tree_RemoveHeader(TreeCtrl *tree, TreeItem item); MODULE_SCOPE Tk_Image Tree_GetImage(TreeCtrl *tree, char *imageName); MODULE_SCOPE void Tree_FreeImage(TreeCtrl *tree, Tk_Image image); MODULE_SCOPE void Tree_UpdateScrollbarX(TreeCtrl *tree); MODULE_SCOPE void Tree_UpdateScrollbarY(TreeCtrl *tree); MODULE_SCOPE void Tree_AddToSelection(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void Tree_RemoveFromSelection(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void Tree_PreserveItems(TreeCtrl *tree); MODULE_SCOPE void Tree_ReleaseItems(TreeCtrl *tree); MODULE_SCOPE int TreeArea_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, int *areaPtr); #define STATE_OP_ON 0 #define STATE_OP_OFF 1 #define STATE_OP_TOGGLE 2 #define SFO_NOT_OFF 0x0001 #define SFO_NOT_TOGGLE 0x0002 #define SFO_NOT_STATIC 0x0004 MODULE_SCOPE int Tree_StateFromObj(TreeCtrl *tree, int domain, Tcl_Obj *obj, int states[3], int *indexPtr, int flags); MODULE_SCOPE int Tree_StateFromListObj(TreeCtrl *tree, int domain, Tcl_Obj *obj, int states[3], int flags); MODULE_SCOPE int Tree_StateCmd(TreeCtrl *tree, int domain, int objc, Tcl_Obj *CONST objv[]); #define Tree_BorderLeft(tree) \ tree->inset.left #define Tree_BorderTop(tree) \ tree->inset.top #define Tree_BorderRight(tree) \ (Tk_Width(tree->tkwin) - tree->inset.right) #define Tree_BorderBottom(tree) \ (Tk_Height(tree->tkwin) - tree->inset.bottom) #define Tree_HeaderLeft(tree) \ Tree_BorderLeft(tree) #define Tree_HeaderTop(tree) \ Tree_BorderTop(tree) #define Tree_HeaderRight(tree) \ Tree_BorderRight(tree) #define Tree_HeaderBottom(tree) \ (Tree_BorderTop(tree) + Tree_HeaderHeight(tree)) #define Tree_HeaderWidth(tree) \ (Tree_HeaderRight(tree) - Tree_HeaderLeft(tree)) #define Tree_ContentLeft(tree) \ (Tree_BorderLeft(tree) + Tree_WidthOfLeftColumns(tree)) #define Tree_ContentTop(tree) \ (Tree_BorderTop(tree) + Tree_HeaderHeight(tree)) #define Tree_ContentRight(tree) \ (Tree_BorderRight(tree) - Tree_WidthOfRightColumns(tree)) #define Tree_ContentBottom(tree) \ Tree_BorderBottom(tree) #define Tree_ContentWidth(tree) \ (Tree_ContentRight(tree) - Tree_ContentLeft(tree)) #define Tree_ContentHeight(tree) \ (Tree_ContentBottom(tree) - Tree_ContentTop(tree)) /* tkTreeHeader.c */ MODULE_SCOPE int TreeHeader_InitWidget(TreeCtrl *tree); MODULE_SCOPE void TreeHeader_FreeWidget(TreeCtrl *tree); MODULE_SCOPE int TreeHeaderCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int TreeHeaderList_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeItemList *items, int flags); MODULE_SCOPE void TreeHeader_TreeChanged(TreeCtrl *tree, int flagT); MODULE_SCOPE int TreeHeader_ColumnDragOrder(TreeHeader header, TreeColumn column, int index); MODULE_SCOPE int TreeHeader_IsDraggedColumn(TreeHeader header, TreeColumn column); MODULE_SCOPE int TreeHeader_GetDraggedColumns(TreeHeader header, int lock, TreeColumn *first, TreeColumn *last); MODULE_SCOPE int TreeHeaderColumn_NeededHeight(TreeHeader header, TreeHeaderColumn column, int fixedWidth); MODULE_SCOPE void TreeHeaders_RequestWidthInColumns(TreeCtrl *tree, TreeColumn columnMin, TreeColumn columnMax); MODULE_SCOPE int Tree_HeaderHeight(TreeCtrl *tree); MODULE_SCOPE TreeItem TreeHeader_GetItem(TreeHeader header); MODULE_SCOPE void TreeHeader_ColumnDeleted(TreeCtrl *tree, TreeColumn treeColumn); MODULE_SCOPE Tcl_Obj *TreeHeaderColumn_GetImageOrText(TreeHeader header, TreeHeaderColumn column, int isImage); MODULE_SCOPE int TreeHeaderColumn_SetImageOrText(TreeHeader header, TreeHeaderColumn column, TreeColumn treeColumn, Tcl_Obj *valueObj, int isImage); MODULE_SCOPE int TreeHeaderColumn_EnsureStyleExists(TreeHeader header, TreeHeaderColumn column, TreeColumn treeColumn); MODULE_SCOPE int TreeHeader_ConsumeColumnCget(TreeCtrl *tree, TreeColumn treeColumn, Tcl_Obj *objPtr); MODULE_SCOPE int TreeHeader_ConsumeColumnConfig(TreeCtrl *tree, TreeColumn treeColumn, int objc, Tcl_Obj *CONST objv[], int createFlag); MODULE_SCOPE Tcl_Obj *TreeHeader_ConsumeColumnOptionInfo(TreeCtrl *tree, TreeColumn treeColumn, Tcl_Obj *objPtr); MODULE_SCOPE TreeHeader TreeHeader_CreateWithItem(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void TreeHeader_FreeResources(TreeHeader header); MODULE_SCOPE TreeHeaderColumn TreeHeaderColumn_CreateWithItemColumn( TreeHeader header, TreeItemColumn itemColumn); MODULE_SCOPE void TreeHeaderColumn_FreeResources(TreeCtrl *tree, TreeHeaderColumn column); MODULE_SCOPE int TreeHeaderColumn_StateChanged(TreeHeader header, TreeHeaderColumn column, TreeColumn treeColumn, int state1, int state2); MODULE_SCOPE int TreeHeaderColumn_DragBounds(TreeHeader header, TreeHeaderColumn column, StyleDrawArgs *drawArgs, int dragPosition); MODULE_SCOPE void TreeHeaderColumn_Draw(TreeHeader header, TreeHeaderColumn column, int visIndex, StyleDrawArgs *drawArgs, int dragPosition); MODULE_SCOPE int TreeHeaderColumn_NeededWidth(TreeHeader header, TreeHeaderColumn column); MODULE_SCOPE TreeItem Tree_HeaderUnderPoint(TreeCtrl *tree, int *x_, int *y_, int *lock); MODULE_SCOPE int TreeHeader_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeHeader *headerPtr); MODULE_SCOPE Tcl_Obj* TreeHeader_ToObj(TreeHeader header); MODULE_SCOPE Tk_Justify TreeHeaderColumn_Justify(TreeHeader header, TreeHeaderColumn column); MODULE_SCOPE Tk_ObjCustomOption TreeCtrlCO_header; /* tkTreeItem.c */ #define ITEM_ALL ((TreeItem) -1) #define IFO_NOT_MANY 0x0001 /* ItemFromObj flag: > 1 item is not ok */ #define IFO_NOT_NULL 0x0002 /* ItemFromObj flag: can't be NULL */ #define IFO_NOT_ROOT 0x0004 /* ItemFromObj flag: "root" is forbidden */ #define IFO_NOT_ORPHAN 0x0008 /* ItemFromObj flag: item must have a parent */ #define IFO_LIST_ALL 0x0010 /* ItemFromObj flag: return "all" as list */ MODULE_SCOPE int TreeItemList_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeItemList *items, int flags); MODULE_SCOPE int TreeItem_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeItem *itemPtr, int flags); typedef struct ItemForEach ItemForEach; struct ItemForEach { TreeCtrl *tree; int error; int all; Tcl_HashSearch search; TreeItem last; TreeItem item; TreeItemList *items; int index; }; MODULE_SCOPE TreeItem TreeItemForEach_Start(TreeItemList *items, TreeItemList *item2s, ItemForEach *iter); MODULE_SCOPE TreeItem TreeItemForEach_Next(ItemForEach *iter); #define ITEM_FOR_EACH(item, items, item2s, iter) \ for (item = TreeItemForEach_Start(items, item2s, iter); \ item != NULL; \ item = TreeItemForEach_Next(iter)) #ifdef TREECTRL_DEBUG #define BreakIntoDebugger() TreeCtrl_BreakIntoDebugger(__FILE__, __LINE__) MODULE_SCOPE void TreeCtrl_BreakIntoDebugger(const char *file, int line); #endif #define FormatResult TreeCtrl_FormatResult MODULE_SCOPE void FormatResult(Tcl_Interp *interp, char *fmt, ...); #define DStringAppendf TreeCtrl_DStringAppendf MODULE_SCOPE void DStringAppendf(Tcl_DString *dString, char *fmt, ...); MODULE_SCOPE void Tree_Debug(TreeCtrl *tree); MODULE_SCOPE int TreeItem_InitWidget(TreeCtrl *tree); MODULE_SCOPE void TreeItem_FreeWidget(TreeCtrl *tree); MODULE_SCOPE int TreeItem_Debug(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void TreeItem_OpenClose(TreeCtrl *tree, TreeItem item, int mode); MODULE_SCOPE void TreeItem_Delete(TreeCtrl *tree, TreeItem item); MODULE_SCOPE int TreeItem_Deleted(TreeCtrl *tree, TreeItem item); #define STATE_ITEM_OPEN 0x0001 #define STATE_ITEM_SELECTED 0x0002 #define STATE_ITEM_ENABLED 0x0004 #define STATE_ITEM_ACTIVE 0x0008 #define STATE_ITEM_FOCUS 0x0010 #define STATE_HEADER_BG 0x0001 #define STATE_HEADER_FOCUS 0x0002 #define STATE_HEADER_ACTIVE 0x0004 #define STATE_HEADER_NORMAL 0x0008 #define STATE_HEADER_PRESSED 0x0010 #define STATE_HEADER_SORT_UP 0x0020 #define STATE_HEADER_SORT_DOWN 0x0040 MODULE_SCOPE int TreeItem_GetState(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE int TreeItemColumn_GetState(TreeCtrl *tree, TreeItemColumn itemColumn); /* State flags for button state, needed by themes */ /* FIXME: These may conflict with [state define] states */ #define BUTTON_STATE_ACTIVE (1<<30) #define BUTTON_STATE_PRESSED (1<<31) #define CS_DISPLAY 0x01 #define CS_LAYOUT 0x02 MODULE_SCOPE int TreeItem_ChangeState(TreeCtrl *tree, TreeItem item_, int stateOff, int stateOn); MODULE_SCOPE int TreeItemColumn_ChangeState(TreeCtrl *tree, TreeItem item, TreeItemColumn column_, TreeColumn treeColumn, int stateOff, int stateOn); MODULE_SCOPE void TreeItem_UndefineState(TreeCtrl *tree, TreeItem item_, int state); MODULE_SCOPE int TreeItem_HasButton(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE int TreeItem_IsPointInButton(TreeCtrl *tree, TreeItem item_, int x, int y); MODULE_SCOPE int TreeItem_GetDepth(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE int TreeItem_GetID(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE int TreeItem_SetID(TreeCtrl *tree, TreeItem item_, int id); MODULE_SCOPE int TreeItem_GetEnabled(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE int TreeItem_GetSelected(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE int TreeItem_CanAddToSelection(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE int TreeItem_GetWrap(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE TreeItem TreeItem_GetParent(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem TreeItem_GetNextSibling(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem TreeItem_NextSiblingVisible(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void TreeItem_SetDInfo(TreeCtrl *tree, TreeItem item, TreeItemDInfo dInfo); MODULE_SCOPE TreeItemDInfo TreeItem_GetDInfo(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void TreeItem_SetRInfo(TreeCtrl *tree, TreeItem item, TreeItemRInfo rInfo); MODULE_SCOPE TreeItemRInfo TreeItem_GetRInfo(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TagInfo *TreeItem_GetTagInfo(TreeCtrl *tree, TreeItem item); MODULE_SCOPE int TreeItem_HasTag(TreeItem, Tk_Uid tag); MODULE_SCOPE TreeItemColumn TreeItem_MakeColumnExist(TreeCtrl *tree, TreeItem item, int columnIndex); MODULE_SCOPE TreeItem TreeItem_CreateHeader(TreeCtrl *tree); MODULE_SCOPE TreeHeader TreeItem_GetHeader(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE TreeHeaderColumn TreeItemColumn_GetHeaderColumn(TreeCtrl *tree, TreeItemColumn itemColumn); MODULE_SCOPE int TreeItem_ConsumeHeaderCget(TreeCtrl *tree, TreeItem item, Tcl_Obj *objPtr); MODULE_SCOPE int TreeItem_ConsumeHeaderConfig(TreeCtrl *tree, TreeItem item, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int TreeItem_GetHeaderOptionInfo(TreeCtrl *tree, TreeHeader header, Tcl_Obj *objPtr, Tcl_Obj *resultObjPtr); MODULE_SCOPE int TreeItemCmd_Bbox(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[], int doHeaders); MODULE_SCOPE int TreeItemCmd_Element(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[], int doHeaders); MODULE_SCOPE int TreeItemCmd_Span(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[], int doHeaders); MODULE_SCOPE int TreeItemCmd_State(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[], int doHeaders); MODULE_SCOPE int TreeItemCmd_Style(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[], int doHeaders); MODULE_SCOPE int TreeItemCmd_ImageOrText(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[], int doImage, int doHeaders); MODULE_SCOPE int TreeItemCmd_Tag(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[], int doHeaders); MODULE_SCOPE void TreeItem_AppendChild(TreeCtrl *tree, TreeItem self, TreeItem child); MODULE_SCOPE void TreeItem_RemoveFromParent(TreeCtrl *tree, TreeItem self); MODULE_SCOPE int TreeItem_FirstAndLast(TreeCtrl *tree, TreeItem *first, TreeItem *last); MODULE_SCOPE void TreeItem_ListDescendants(TreeCtrl *tree, TreeItem item_, TreeItemList *items); MODULE_SCOPE void TreeItem_UpdateDepth(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void TreeItem_AddToParent(TreeCtrl *tree, TreeItem item); MODULE_SCOPE int TreeItem_Height(TreeCtrl *tree, TreeItem self); MODULE_SCOPE int TreeItem_TotalHeight(TreeCtrl *tree, TreeItem self); MODULE_SCOPE void TreeItem_InvalidateHeight(TreeCtrl *tree, TreeItem self); MODULE_SCOPE void TreeItem_SpansInvalidate(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE int TreeItem_SpansRedo(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE void TreeItem_SpansRedoIfNeeded(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE int *TreeItem_GetSpans(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE void TreeItem_Draw(TreeCtrl *tree, TreeItem self, int lock, int x, int y, int width, int height, TreeDrawable td, int minX, int maxX, int index); MODULE_SCOPE void TreeItem_DrawLines(TreeCtrl *tree, TreeItem self, int x, int y, int width, int height, TreeDrawable td, TreeStyle style); MODULE_SCOPE void TreeItem_DrawButton(TreeCtrl *tree, TreeItem self, int x, int y, int width, int height, TreeDrawable td, TreeStyle style); MODULE_SCOPE int TreeItem_ReallyVisible(TreeCtrl *tree, TreeItem self); MODULE_SCOPE void TreeItem_FreeResources(TreeCtrl *tree, TreeItem self); MODULE_SCOPE void TreeItem_Release(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem TreeItem_RootAncestor(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE int TreeItem_IsAncestor(TreeCtrl *tree, TreeItem item1, TreeItem item2); MODULE_SCOPE Tcl_Obj *TreeItem_ToObj(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void TreeItem_ToIndex(TreeCtrl *tree, TreeItem item, int *absolute, int *visible); MODULE_SCOPE TreeItem TreeItem_Next(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem TreeItem_NextVisible(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem TreeItem_Prev(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem TreeItem_PrevVisible(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void TreeItem_Identify(TreeCtrl *tree, TreeItem item_, int lock, int x, int y, TreeColumn *columnPtr, TreeElement *elemPtr); MODULE_SCOPE void TreeItem_Identify2(TreeCtrl *tree, TreeItem item_, int x1, int y1, int x2, int y2, Tcl_Obj *listObj); MODULE_SCOPE int TreeItem_GetRects(TreeCtrl *tree, TreeItem item_, TreeColumn treeColumn, int objc, Tcl_Obj *CONST objv[], TreeRectangle rects[]); MODULE_SCOPE int TreeItem_Indent(TreeCtrl *tree, TreeColumn column, TreeItem item_); MODULE_SCOPE void Tree_UpdateItemIndex(TreeCtrl *tree); MODULE_SCOPE void Tree_DeselectHidden(TreeCtrl *tree); MODULE_SCOPE int TreeItemCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE void TreeItem_UpdateWindowPositions(TreeCtrl *tree, TreeItem item_, int lock, int x, int y, int width, int height); MODULE_SCOPE void TreeItem_GetOnScreenColumns(TreeCtrl *tree, TreeItem item_, int lock, int x, int y, int width, int height, TreeColumnList *columns); MODULE_SCOPE void TreeItem_OnScreen(TreeCtrl *tree, TreeItem item_, int onScreen); MODULE_SCOPE TreeItemColumn TreeItem_GetFirstColumn(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItemColumn TreeItemColumn_GetNext(TreeCtrl *tree, TreeItemColumn column); MODULE_SCOPE void TreeItemColumn_InvalidateSize(TreeCtrl *tree, TreeItemColumn column); MODULE_SCOPE TreeStyle TreeItemColumn_GetStyle(TreeCtrl *tree, TreeItemColumn column); MODULE_SCOPE void TreeItemColumn_SetStyle(TreeCtrl *tree, TreeItemColumn column, TreeStyle style); MODULE_SCOPE int TreeItemColumn_Index(TreeCtrl *tree, TreeItem item_, TreeItemColumn column_); MODULE_SCOPE void TreeItemColumn_ForgetStyle(TreeCtrl *tree, TreeItemColumn column_); MODULE_SCOPE int TreeItemColumn_NeededWidth(TreeCtrl *tree, TreeItem item_, TreeItemColumn column_); MODULE_SCOPE TreeItemColumn TreeItem_FindColumn(TreeCtrl *tree, TreeItem item, int columnIndex); MODULE_SCOPE int TreeItem_ColumnFromObj(TreeCtrl *tree, TreeItem item, Tcl_Obj *obj, TreeItemColumn *columnPtr, TreeColumn *treeColumnPtr, int *indexPtr, int flags); MODULE_SCOPE void TreeItem_RemoveColumns(TreeCtrl *tree, TreeItem item_, int first, int last); MODULE_SCOPE void TreeItem_RemoveAllColumns(TreeCtrl *tree, TreeItem item_); MODULE_SCOPE void TreeItem_MoveColumn(TreeCtrl *tree, TreeItem item_, int columnIndex, int beforeIndex); MODULE_SCOPE void TreeItem_RequestWidthInColumns(TreeCtrl *tree, TreeItem item, TreeColumn columnMin, TreeColumn columnMax); MODULE_SCOPE void TreeItems_RequestWidthInColumns(TreeCtrl *tree, TreeColumn columnMin, TreeColumn columnMax); /* tkTreeElem.c */ MODULE_SCOPE int TreeElement_InitInterp(Tcl_Interp *interp); MODULE_SCOPE int TreeElement_InitWidget(TreeCtrl *tree); MODULE_SCOPE void TreeElement_FreeWidget(TreeCtrl *tree); MODULE_SCOPE int TreeStateFromObj(TreeCtrl *tree, int domain, Tcl_Obj *obj, int *stateOff, int *stateOn); MODULE_SCOPE int StringTableCO_Init(Tk_OptionSpec *optionTable, CONST char *optionName, CONST char **tablePtr); struct StyleDrawArgs { TreeCtrl *tree; TreeColumn column; TreeItem item; TreeStyle style; int indent; int x; /* Display area of the style. */ int y; /* ^ */ int width; /* ^ */ int height; /* ^ */ int spanIndex; /* 0-based index in the list of visible spans. */ TreeDrawable td; /* Where to draw. */ int state; /* STATE_xxx */ Tk_Justify justify; /* How to justify the style within 'bounds'. */ TreeRectangle bounds; /* TREE_AREA_XXX bounds. */ }; /* tkTreeStyle.c */ MODULE_SCOPE int TreeStyle_InitWidget(TreeCtrl *tree); MODULE_SCOPE int TreeStyle_NeededWidth(TreeCtrl *tree, TreeStyle style_, int state); MODULE_SCOPE int TreeStyle_NeededHeight(TreeCtrl *tree, TreeStyle style_, int state); MODULE_SCOPE int TreeStyle_UseHeight(StyleDrawArgs *drawArgs); MODULE_SCOPE void TreeStyle_Draw(StyleDrawArgs *args); MODULE_SCOPE void TreeStyle_FreeResources(TreeCtrl *tree, TreeStyle style_); MODULE_SCOPE void TreeStyle_FreeWidget(TreeCtrl *tree); MODULE_SCOPE Tcl_Obj *TreeElement_ToObj(TreeElement elem); MODULE_SCOPE int TreeElement_FromObj(TreeCtrl *tree, Tcl_Obj *obj, TreeElement *elemPtr); MODULE_SCOPE int TreeElement_IsType(TreeCtrl *tree, TreeElement elem, CONST char *type); MODULE_SCOPE int TreeStyle_FromObj(TreeCtrl *tree, Tcl_Obj *obj, TreeStyle *stylePtr); MODULE_SCOPE Tcl_Obj *TreeStyle_ToObj(TreeStyle style_); MODULE_SCOPE Tcl_Obj *TreeStyle_GetImage(TreeCtrl *tree, TreeStyle style_, TreeElement *elemPtr); MODULE_SCOPE Tcl_Obj *TreeStyle_GetText(TreeCtrl *tree, TreeStyle style_, TreeElement *elemPtr); MODULE_SCOPE int TreeStyle_SetImage(TreeCtrl *tree, TreeItem item, TreeItemColumn column, TreeStyle style_, Tcl_Obj *imageObj, TreeElement *elemPtr); MODULE_SCOPE int TreeStyle_SetText(TreeCtrl *tree, TreeItem item, TreeItemColumn column, TreeStyle style_, Tcl_Obj *textObj, TreeElement *elemPtr); MODULE_SCOPE int TreeStyle_FindElement(TreeCtrl *tree, TreeStyle style_, TreeElement elem, int *index); MODULE_SCOPE TreeStyle TreeStyle_NewInstance(TreeCtrl *tree, TreeStyle master); MODULE_SCOPE int TreeStyle_ElementActual(TreeCtrl *tree, TreeStyle style_, int state, Tcl_Obj *elemObj, Tcl_Obj *obj); MODULE_SCOPE int TreeStyle_ElementCget(TreeCtrl *tree, TreeItem item, TreeItemColumn column, TreeStyle style_, Tcl_Obj *elemObj, Tcl_Obj *obj); MODULE_SCOPE int TreeStyle_ElementConfigure(TreeCtrl *tree, TreeItem item, TreeItemColumn column, TreeStyle style_, TreeElement elem, int objc, Tcl_Obj **objv, int *eMask); MODULE_SCOPE int TreeStyle_ElementConfigureFromObj(TreeCtrl *tree, TreeItem item, TreeItemColumn column, TreeStyle style_, Tcl_Obj *elemObj, int objc, Tcl_Obj **objv, int *eMask); MODULE_SCOPE void TreeStyle_ListElements(TreeCtrl *tree, TreeStyle style_); MODULE_SCOPE int TreeStyle_GetButtonY(TreeCtrl *tree, TreeStyle style_); MODULE_SCOPE TreeStyle TreeStyle_GetMaster(TreeCtrl *tree, TreeStyle style_); MODULE_SCOPE CONST char *TreeStyle_GetName(TreeCtrl *tree, TreeStyle style_); MODULE_SCOPE int TreeStyle_GetStateDomain(TreeCtrl *tree, TreeStyle style_); MODULE_SCOPE TreeElement TreeStyle_Identify(StyleDrawArgs *drawArgs, int x, int y); MODULE_SCOPE void TreeStyle_Identify2(StyleDrawArgs *drawArgs, int x1, int y1, int x2, int y2, Tcl_Obj *listObj); MODULE_SCOPE int TreeStyle_Remap(TreeCtrl *tree, TreeStyle styleFrom_, TreeStyle styleTo_, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE void TreeStyle_TreeChanged(TreeCtrl *tree, int flagT); #define SORT_ASCII 0 #define SORT_DICT 1 #define SORT_DOUBLE 2 #define SORT_LONG 3 #define SORT_COMMAND 4 MODULE_SCOPE int TreeStyle_GetSortData(TreeCtrl *tree, TreeStyle style_, int elemIndex, int type, long *lv, double *dv, char **sv); #if 0 MODULE_SCOPE int TreeStyle_ValidateElements(TreeCtrl *tree, TreeStyle style_, int objc, Tcl_Obj *CONST objv[]); #endif MODULE_SCOPE int TreeStyle_GetElemRects(StyleDrawArgs *drawArgs, int objc, Tcl_Obj *CONST objv[], TreeRectangle rects[]); MODULE_SCOPE int TreeElementCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int TreeStyleCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int TreeStyle_ChangeState(TreeCtrl *tree, TreeStyle style_, int state1, int state2); MODULE_SCOPE void Tree_UndefineState(TreeCtrl *tree, int domain, int state); MODULE_SCOPE int TreeStyle_NumElements(TreeCtrl *tree, TreeStyle style_); MODULE_SCOPE int TreeStyle_IsHeaderStyle(TreeCtrl *tree, TreeStyle style); MODULE_SCOPE int TreeStyle_HasHeaderElement(TreeCtrl *tree, TreeStyle style); MODULE_SCOPE TreeStyle Tree_MakeHeaderStyle(TreeCtrl *tree, HeaderStyleParams *params); MODULE_SCOPE void TreeStyle_UpdateWindowPositions(StyleDrawArgs *drawArgs); MODULE_SCOPE void TreeStyle_OnScreen(TreeCtrl *tree, TreeStyle style_, int onScreen); MODULE_SCOPE void Tree_ButtonMaxSize(TreeCtrl *tree, int *maxWidth, int *maxHeight); MODULE_SCOPE int Tree_ButtonHeight(TreeCtrl *tree, int state); /* tkTreeNotify.c */ MODULE_SCOPE int TreeNotify_InitWidget(TreeCtrl *tree); MODULE_SCOPE void TreeNotify_OpenClose(TreeCtrl *tree, TreeItem item, int isOpen, int before); MODULE_SCOPE void TreeNotify_Selection(TreeCtrl *tree, TreeItemList *select, TreeItemList *deselect); MODULE_SCOPE int TreeNotifyCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE void TreeNotify_ActiveItem(TreeCtrl *tree, TreeItem itemOld, TreeItem itemNew); MODULE_SCOPE void TreeNotify_Scroll(TreeCtrl *tree, double fractions[2], int vertical); MODULE_SCOPE void TreeNotify_ItemDeleted(TreeCtrl *tree, TreeItemList *items); MODULE_SCOPE void TreeNotify_ItemVisibility(TreeCtrl *tree, TreeItemList *v, TreeItemList *h); /* tkTreeColumn.c */ MODULE_SCOPE Tk_ObjCustomOption TreeCtrlCO_column; MODULE_SCOPE Tk_ObjCustomOption TreeCtrlCO_column_NOT_TAIL; MODULE_SCOPE int TreeColumn_InitInterp(Tcl_Interp *interp); MODULE_SCOPE void TreeColumn_InitWidget(TreeCtrl *tree); MODULE_SCOPE TreeColumn Tree_FindColumn(TreeCtrl *tree, int columnIndex); MODULE_SCOPE int TreeColumn_FirstAndLast(TreeColumn *first, TreeColumn *last); #define COLUMN_ALL ((TreeColumn) -1) /* Every column. */ #define COLUMN_NTAIL ((TreeColumn) -2) /* Every column but the tail. */ #define CFO_NOT_MANY 0x01 #define CFO_NOT_NULL 0x02 #define CFO_NOT_TAIL 0x04 #define CFO_LIST_ALL 0x08 MODULE_SCOPE int TreeColumnList_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeColumnList *columns, int flags); MODULE_SCOPE int TreeColumn_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeColumn *columnPtr, int flags); /* Values for TreeColumn -arrow option, needed by themes */ #define COLUMN_ARROW_NONE 0 #define COLUMN_ARROW_UP 1 #define COLUMN_ARROW_DOWN 2 /* Values for TreeColumn -state option, needed by themes */ #define COLUMN_STATE_NORMAL 0 #define COLUMN_STATE_ACTIVE 1 #define COLUMN_STATE_PRESSED 2 typedef struct ColumnForEach ColumnForEach; struct ColumnForEach { TreeCtrl *tree; int error; int all; int ntail; TreeColumn current; TreeColumn next; TreeColumn last; TreeColumnList *list; int index; }; MODULE_SCOPE TreeColumn TreeColumnForEach_Start(TreeColumnList *columns, TreeColumnList *column2s, ColumnForEach *iter); MODULE_SCOPE TreeColumn TreeColumnForEach_Next(ColumnForEach *iter); #define COLUMN_FOR_EACH(column, columns, column2s, iter) \ for (column = TreeColumnForEach_Start(columns, column2s, iter); \ column != NULL; \ column = TreeColumnForEach_Next(iter)) MODULE_SCOPE Tcl_Obj *TreeColumn_ToObj(TreeCtrl *tree, TreeColumn column_); MODULE_SCOPE int TreeColumnCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int TreeColumn_GetID(TreeColumn column_); MODULE_SCOPE int TreeColumn_Index(TreeColumn column_); MODULE_SCOPE int TreeColumn_VisIndex(TreeColumn column_); MODULE_SCOPE TreeColumn Tree_FirstColumn(TreeCtrl *tree, int lock, int tailOK); MODULE_SCOPE TreeColumn Tree_ColumnToTheRight(TreeColumn column_, int displayOrder, int tailOK); MODULE_SCOPE TreeColumn TreeColumn_Next(TreeColumn column_); MODULE_SCOPE TreeColumn TreeColumn_Prev(TreeColumn column_); MODULE_SCOPE int TreeColumn_FixedWidth(TreeColumn column_); MODULE_SCOPE int TreeColumn_MinWidth(TreeColumn column_); MODULE_SCOPE int TreeColumn_MaxWidth(TreeColumn column_); MODULE_SCOPE int TreeColumn_NeededWidth(TreeColumn column_); MODULE_SCOPE int TreeColumn_NeededHeight(TreeColumn column_); MODULE_SCOPE int TreeColumn_UseWidth(TreeColumn column_); MODULE_SCOPE int TreeColumn_Offset(TreeColumn column_); MODULE_SCOPE Tk_Justify TreeColumn_ItemJustify(TreeColumn column_); #ifdef DEPRECATED MODULE_SCOPE int TreeColumn_WidthHack(TreeColumn column_); MODULE_SCOPE int TreeColumn_StepWidth(TreeColumn column_); #endif MODULE_SCOPE TreeStyle TreeColumn_ItemStyle(TreeColumn column_); MODULE_SCOPE void TreeColumn_StyleDeleted(TreeColumn column_, TreeStyle style); MODULE_SCOPE int TreeColumn_Visible(TreeColumn column_); MODULE_SCOPE int TreeColumn_Squeeze(TreeColumn column_); MODULE_SCOPE int TreeColumn_BackgroundCount(TreeColumn column_); MODULE_SCOPE TreeColor *TreeColumn_BackgroundColor(TreeColumn column_, int which); #if COLUMNGRID==1 MODULE_SCOPE int TreeColumn_GridColors(TreeColumn column, TreeColor **leftColorPtr, TreeColor **rightColorPtr, int *leftWidthPtr, int *rightWidthPtr); #endif MODULE_SCOPE void Tree_DrawHeader(TreeCtrl *tree, TreeDrawable td, int x, int y); MODULE_SCOPE int TreeColumn_WidthOfItems(TreeColumn column_); MODULE_SCOPE int TreeColumn_WidthOfHeaders(TreeColumn column_); MODULE_SCOPE void TreeColumn_InvalidateWidth(TreeColumn column_); MODULE_SCOPE void TreeColumn_FreeWidget(TreeCtrl *tree); MODULE_SCOPE void TreeColumns_InvalidateWidthOfItems(TreeCtrl *tree, TreeColumn column); MODULE_SCOPE void TreeColumns_InvalidateWidth(TreeCtrl *tree); MODULE_SCOPE void TreeColumns_InvalidateSpans(TreeCtrl *tree); MODULE_SCOPE int TreeColumn_Bbox(TreeColumn column, int *x, int *y, int *w, int *h); MODULE_SCOPE int TreeColumn_Lock(TreeColumn column_); MODULE_SCOPE int Tree_WidthOfColumns(TreeCtrl *tree); MODULE_SCOPE int Tree_WidthOfLeftColumns(TreeCtrl *tree); MODULE_SCOPE int Tree_WidthOfRightColumns(TreeCtrl *tree); MODULE_SCOPE void TreeColumns_UpdateCounts(TreeCtrl *tree); MODULE_SCOPE void TreeColumns_InvalidateCounts(TreeCtrl *tree); MODULE_SCOPE void TreeColumn_SetDInfo(TreeColumn column, TreeColumnDInfo dInfo); MODULE_SCOPE TreeColumnDInfo TreeColumn_GetDInfo(TreeColumn column); /* tkTreeDrag.c */ MODULE_SCOPE int TreeDragImage_InitWidget(TreeCtrl *tree); MODULE_SCOPE void TreeDragImage_FreeWidget(TreeCtrl *tree); MODULE_SCOPE int TreeDragImage_IsXOR(TreeDragImage dragImage_); MODULE_SCOPE int TreeDragImage_IsVisible(TreeDragImage dragImage_); MODULE_SCOPE void TreeDragImage_Display(TreeDragImage dragImage_); MODULE_SCOPE void TreeDragImage_Undisplay(TreeDragImage dragImage_); MODULE_SCOPE void TreeDragImage_DrawXOR(TreeDragImage dragImage_, Drawable drawable, int x, int y); MODULE_SCOPE void TreeDragImage_Draw(TreeDragImage dragImage, TreeDrawable td); MODULE_SCOPE int TreeDragImageCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); /* tkTreeMarquee.c */ MODULE_SCOPE int TreeMarquee_InitWidget(TreeCtrl *tree); MODULE_SCOPE void TreeMarquee_FreeWidget(TreeCtrl *tree); MODULE_SCOPE int TreeMarquee_IsXOR(TreeMarquee marquee_); MODULE_SCOPE int TreeMarquee_IsVisible(TreeMarquee marquee_); MODULE_SCOPE void TreeMarquee_DrawXOR(TreeMarquee marquee_, Drawable drawable, int x, int y); MODULE_SCOPE void TreeMarquee_Display(TreeMarquee marquee_); MODULE_SCOPE void TreeMarquee_Undisplay(TreeMarquee marquee_); MODULE_SCOPE void TreeMarquee_Draw(TreeMarquee marquee_, TreeDrawable td); MODULE_SCOPE int TreeMarqueeCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); /* tkTreeDisplay.c */ MODULE_SCOPE int Tree_CanvasWidth(TreeCtrl *tree); MODULE_SCOPE int Tree_CanvasHeight(TreeCtrl *tree); MODULE_SCOPE TreeItem Tree_ItemUnderPoint(TreeCtrl *tree, int *x, int *y, int *lock, int nearest); MODULE_SCOPE void Tree_FreeItemRInfo(TreeCtrl *tree, TreeItem item); MODULE_SCOPE int Tree_ItemBbox(TreeCtrl *tree, TreeItem item, int lock, TreeRectangle *tr); MODULE_SCOPE TreeItem Tree_ItemLARB(TreeCtrl *tree, TreeItem item, int vertical, int prev); MODULE_SCOPE TreeItem Tree_ItemAbove(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem Tree_ItemBelow(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem Tree_ItemLeft(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem Tree_ItemRight(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem Tree_ItemFL(TreeCtrl *tree, TreeItem item, int vertical, int first); MODULE_SCOPE TreeItem Tree_ItemTop(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem Tree_ItemBottom(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem Tree_ItemLeftMost(TreeCtrl *tree, TreeItem item); MODULE_SCOPE TreeItem Tree_ItemRightMost(TreeCtrl *tree, TreeItem item); MODULE_SCOPE int Tree_ItemToRNC(TreeCtrl *tree, TreeItem item, int *row, int *col); MODULE_SCOPE TreeItem Tree_RNCToItem(TreeCtrl *tree, int row, int col); MODULE_SCOPE int Tree_AreaBbox(TreeCtrl *tree, int area, TreeRectangle *tr); enum { TREE_AREA_NONE = 0, TREE_AREA_HEADER, TREE_AREA_CONTENT, TREE_AREA_LEFT, TREE_AREA_RIGHT, TREE_AREA_HEADER_LEFT, TREE_AREA_HEADER_NONE, TREE_AREA_HEADER_RIGHT }; MODULE_SCOPE int Tree_HitTest(TreeCtrl *tree, int x, int y); MODULE_SCOPE void TreeDisplay_InitWidget(TreeCtrl *tree); MODULE_SCOPE void TreeDisplay_FreeWidget(TreeCtrl *tree); MODULE_SCOPE void Tree_EventuallyRedraw(TreeCtrl *tree); MODULE_SCOPE void Tree_GetScrollFractionsX(TreeCtrl *tree, double fractions[2]); MODULE_SCOPE void Tree_GetScrollFractionsY(TreeCtrl *tree, double fractions[2]); MODULE_SCOPE int Tree_FakeCanvasWidth(TreeCtrl *tree); MODULE_SCOPE int Tree_FakeCanvasHeight(TreeCtrl *tree); MODULE_SCOPE void Tree_SetScrollSmoothingX(TreeCtrl *tree, int smooth); MODULE_SCOPE void Tree_SetScrollSmoothingY(TreeCtrl *tree, int smooth); MODULE_SCOPE int Increment_FindX(TreeCtrl *tree, int offset); MODULE_SCOPE int Increment_FindY(TreeCtrl *tree, int offset); MODULE_SCOPE int Increment_ToOffsetX(TreeCtrl *tree, int index); MODULE_SCOPE int Increment_ToOffsetY(TreeCtrl *tree, int index); MODULE_SCOPE int TreeXviewCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int TreeYviewCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE void Tree_SetOriginX(TreeCtrl *tree, int xOrigin); MODULE_SCOPE void Tree_SetOriginY(TreeCtrl *tree, int yOrigin); MODULE_SCOPE int Tree_GetOriginX(TreeCtrl *tree); MODULE_SCOPE int Tree_GetOriginY(TreeCtrl *tree); MODULE_SCOPE void Tree_RelayoutWindow(TreeCtrl *tree); MODULE_SCOPE void Tree_FreeItemDInfo(TreeCtrl *tree, TreeItem item1, TreeItem item2); MODULE_SCOPE void Tree_InvalidateItemDInfo(TreeCtrl *tree, TreeColumn column, TreeItem item1, TreeItem item2); MODULE_SCOPE void TreeDisplay_ItemDeleted(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void TreeDisplay_ColumnDeleted(TreeCtrl *tree, TreeColumn column); MODULE_SCOPE void TreeDisplay_FreeColumnDInfo(TreeCtrl *tree, TreeColumn column); MODULE_SCOPE int Tree_ShouldDisplayLockedColumns(TreeCtrl *tree); MODULE_SCOPE void TreeDisplay_GetReadyForTrouble(TreeCtrl *tree, int *requestsPtr); MODULE_SCOPE int TreeDisplay_WasThereTrouble(TreeCtrl *tree, int requests); MODULE_SCOPE void Tree_InvalidateArea(TreeCtrl *tree, int x1, int y1, int x2, int y2); MODULE_SCOPE void Tree_InvalidateItemArea(TreeCtrl *tree, int x1, int y1, int x2, int y2); MODULE_SCOPE void Tree_InvalidateItemOnScrollX(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void Tree_InvalidateItemOnScrollY(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void Tree_InvalidateRegion(TreeCtrl *tree, TkRegion region); MODULE_SCOPE void Tree_RedrawArea(TreeCtrl *tree, int x1, int y1, int x2, int y2); MODULE_SCOPE void Tree_ExposeArea(TreeCtrl *tree, int x1, int y1, int x2, int y2); MODULE_SCOPE void Tree_FocusChanged(TreeCtrl *tree, int gotFocus); MODULE_SCOPE void Tree_Activate(TreeCtrl *tree, int isActive); MODULE_SCOPE void Tree_ItemsInArea(TreeCtrl *tree, TreeItemList *items, int minX, int minY, int maxX, int maxY); MODULE_SCOPE void TreeColumnProxy_Undisplay(TreeCtrl *tree); MODULE_SCOPE void TreeColumnProxy_Display(TreeCtrl *tree); MODULE_SCOPE void TreeRowProxy_Undisplay(TreeCtrl *tree); MODULE_SCOPE void TreeRowProxy_Display(TreeCtrl *tree); MODULE_SCOPE int Tree_DrawTiledImage(TreeCtrl *tree, TreeDrawable td, Tk_Image image, TreeRectangle tr, int xOffset, int yOffset, int tileX, int tileY); MODULE_SCOPE int Tree_IsBgImageOpaque(TreeCtrl *tree); MODULE_SCOPE int Tree_DrawBgImage(TreeCtrl *tree, TreeDrawable td, TreeRectangle tr, int xOrigin, int yOrigin); MODULE_SCOPE int TreeRect_Intersect(TreeRectangle *resultPtr, CONST TreeRectangle *r1, CONST TreeRectangle *r2); #define DINFO_OUT_OF_DATE 0x0001 #define DINFO_CHECK_COLUMN_WIDTH 0x0002 #define DINFO_DRAW_HEADER 0x0004 #define DINFO_SET_ORIGIN_X 0x0008 #define DINFO_UPDATE_SCROLLBAR_X 0x0010 #define DINFO_REDRAW_PENDING 0x00020 #define DINFO_INVALIDATE 0x0040 #define DINFO_DRAW_HIGHLIGHT 0x0080 #define DINFO_DRAW_BORDER 0x0100 #define DINFO_REDO_RANGES 0x0200 #define DINFO_SET_ORIGIN_Y 0x0400 #define DINFO_UPDATE_SCROLLBAR_Y 0x0800 #define DINFO_REDO_INCREMENTS 0x1000 #define DINFO_REDO_COLUMN_WIDTH 0x2000 #define DINFO_REDO_SELECTION 0x4000 #define DINFO_DRAW_WHITESPACE 0x8000 MODULE_SCOPE void Tree_DInfoChanged(TreeCtrl *tree, int flags); MODULE_SCOPE void Tree_TheWorldHasChanged(Tcl_Interp *interp); MODULE_SCOPE int Tree_DumpDInfo(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]); /* tkTreeTheme.c */ MODULE_SCOPE int TreeTheme_InitInterp(Tcl_Interp *interp); MODULE_SCOPE void TreeTheme_ThemeChanged(TreeCtrl *tree); MODULE_SCOPE int TreeTheme_InitWidget(TreeCtrl *tree); MODULE_SCOPE int TreeTheme_FreeWidget(TreeCtrl *tree); MODULE_SCOPE int TreeTheme_DrawHeaderItem(TreeCtrl *tree, TreeDrawable td, int state, int arrow, int visIndex, int x, int y, int width, int height); MODULE_SCOPE int TreeTheme_GetHeaderFixedHeight(TreeCtrl *tree, int *heightPtr); MODULE_SCOPE int TreeTheme_GetHeaderContentMargins(TreeCtrl *tree, int state, int arrow, int bounds[4]); MODULE_SCOPE int TreeTheme_DrawHeaderArrow(TreeCtrl *tree, TreeDrawable td, int state, int up, int x, int y, int width, int height); MODULE_SCOPE int TreeTheme_DrawButton(TreeCtrl *tree, TreeDrawable td, TreeItem item, int state, int x, int y, int width, int height); MODULE_SCOPE int TreeTheme_GetButtonSize(TreeCtrl *tree, Drawable drawable, int open, int *widthPtr, int *heightPtr); MODULE_SCOPE int TreeTheme_GetArrowSize(TreeCtrl *tree, Drawable drawable, int up, int *widthPtr, int *heightPtr); MODULE_SCOPE int TreeTheme_SetBorders(TreeCtrl *tree); MODULE_SCOPE int TreeTheme_DrawBorders(TreeCtrl *tree, Drawable drawable); MODULE_SCOPE int TreeTheme_GetHeaderTextColor(TreeCtrl *tree, int state, XColor **xColorPtr); MODULE_SCOPE int TreeTheme_AnimateButtonStart(TreeCtrl *tree, TreeItem item); MODULE_SCOPE int TreeTheme_ItemDeleted(TreeCtrl *tree, TreeItem item); MODULE_SCOPE void TreeTheme_Relayout(TreeCtrl *tree); MODULE_SCOPE int TreeTheme_IsDesktopComposited(TreeCtrl *tree); MODULE_SCOPE int TreeThemeCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE void TreeTheme_SetOptionDefault(Tk_OptionSpec *specPtr); /* tkTreeUtils.c */ #ifdef TREECTRL_DEBUG #define WIPE(p,s) memset((char *) p, 0xAA, s) #else #define WIPE(p,s) #endif #define CWIPE(p,t,c) WIPE(p, sizeof(t) * (c)) #define WIPEFREE(p,s) { WIPE(p, s); ckfree((char *) p); } #define WFREE(p,t) WIPEFREE(p, sizeof(t)) #define WCFREE(p,t,c) WIPEFREE(p, sizeof(t) * (c)) MODULE_SCOPE int Tree_Ellipsis(Tk_Font tkfont, char *string, int numBytes, int *maxPixels, char *ellipsis, int force); MODULE_SCOPE void Tree_HDotLine(TreeCtrl *tree, Drawable drawable, int x1, int y1, int x2); MODULE_SCOPE void Tree_VDotLine(TreeCtrl *tree, Drawable drawable, int x1, int y1, int y2); MODULE_SCOPE void Tree_DrawActiveOutline(TreeCtrl *tree, Drawable drawable, int x, int y, int width, int height, int open); typedef struct DotState { void *stuff[10]; } DotState; MODULE_SCOPE void TreeDotRect_Setup(TreeCtrl *tree, Drawable drawable, DotState *dotState); MODULE_SCOPE void TreeDotRect_Draw(DotState *dotState, int x, int y, int width, int height); MODULE_SCOPE void TreeDotRect_Restore(DotState *dotState); typedef struct TextLayout_ *TextLayout; MODULE_SCOPE TextLayout TextLayout_Compute(Tk_Font tkfont, CONST char *string, int numChars, int wrapLength, Tk_Justify justify, int maxLines, int lMargin1, int lMargin2, int flags); MODULE_SCOPE void TextLayout_Free(TextLayout textLayout); MODULE_SCOPE void TextLayout_Size(TextLayout textLayout, int *widthPtr, int *heightPtr); MODULE_SCOPE int TextLayout_TotalWidth(TextLayout textLayout); MODULE_SCOPE void TextLayout_Draw(Display *display, Drawable drawable, GC gc, TextLayout layout, int x, int y, int firstChar, int lastChar, int underline); MODULE_SCOPE void Tree_RedrawImage(Tk_Image image, int imageX, int imageY, int width, int height, TreeDrawable td, int drawableX, int drawableY); MODULE_SCOPE void Tree_DrawBitmapWithGC(TreeCtrl *tree, Pixmap bitmap, Drawable drawable, GC gc, int src_x, int src_y, int width, int height, int dest_x, int dest_y); MODULE_SCOPE void Tree_DrawBitmap(TreeCtrl *tree, Pixmap bitmap, Drawable drawable, XColor *fg, XColor *bg, int src_x, int src_y, int width, int height, int dest_x, int dest_y); MODULE_SCOPE TkRegion Tree_GetRegion(TreeCtrl *tree); MODULE_SCOPE void Tree_FreeRegion(TreeCtrl *tree, TkRegion region); MODULE_SCOPE void Tree_FillRegion(Display *display, Drawable drawable, GC gc, TkRegion rgn); MODULE_SCOPE void Tree_OffsetRegion(TkRegion region, int xOffset, int yOffset); MODULE_SCOPE void Tree_SetEmptyRegion(TkRegion region); MODULE_SCOPE TkRegion Tree_GetRectRegion(TreeCtrl *tree, const TreeRectangle *rect); MODULE_SCOPE void Tree_SetRectRegion(TkRegion region, const TreeRectangle *rect); MODULE_SCOPE void Tree_GetRegionBounds(TkRegion region, TreeRectangle *rect); MODULE_SCOPE void Tree_UnionRegion(TkRegion rgnA, TkRegion rgnB, TkRegion rgnOut); MODULE_SCOPE int Tree_ScrollWindow(TreeCtrl *tree, GC gc, int x, int y, int width, int height, int dx, int dy, TkRegion damageRgn); MODULE_SCOPE void Tree_UnsetClipMask(TreeCtrl *tree, Drawable drawable, GC gc); MODULE_SCOPE void Tree_XImage2Photo(Tcl_Interp *interp, Tk_PhotoHandle photoH, XImage *ximage, unsigned long trans, int alpha); #define PAD_TOP_LEFT 0 #define PAD_BOTTOM_RIGHT 1 MODULE_SCOPE Tk_ObjCustomOption TreeCtrlCO_pad; MODULE_SCOPE int TreeCtrl_GetPadAmountFromObj(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *padObj, int *topLeftPtr, int *bottomRightPtr); MODULE_SCOPE Tcl_Obj *TreeCtrl_NewPadAmountObj(int *padAmounts); /*****/ #define ObjectIsEmpty TreeCtrl_ObjectIsEmpty MODULE_SCOPE int ObjectIsEmpty(Tcl_Obj *obj); #define pstBitmap TreeCtrl_pstBitmap #define pstBoolean TreeCtrl_pstBoolean #define pstBorder TreeCtrl_pstBorder #define pstColor TreeCtrl_pstColor #define pstFlags TreeCtrl_pstFlags #define pstFont TreeCtrl_pstFont #define pstImage TreeCtrl_pstImage #define pstRelief TreeCtrl_pstRelief MODULE_SCOPE PerStateType pstBitmap; MODULE_SCOPE PerStateType pstBoolean; MODULE_SCOPE PerStateType pstBorder; MODULE_SCOPE PerStateType pstColor; MODULE_SCOPE PerStateType pstFlags; MODULE_SCOPE PerStateType pstFont; MODULE_SCOPE PerStateType pstImage; MODULE_SCOPE PerStateType pstRelief; #define MATCH_NONE 0 #define MATCH_ANY 1 #define MATCH_PARTIAL 2 #define MATCH_EXACT 3 MODULE_SCOPE void PerStateInfo_Free(TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo); typedef int (*StateFromObjProc)(TreeCtrl *tree, int domain, Tcl_Obj *obj, int *stateOff, int *stateOn); MODULE_SCOPE int PerStateInfo_FromObj(TreeCtrl *tree, int domain, StateFromObjProc proc, PerStateType *typePtr, PerStateInfo *pInfo); MODULE_SCOPE PerStateData *PerStateInfo_ForState(TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo, int state, int *match); MODULE_SCOPE Tcl_Obj *PerStateInfo_ObjForState(TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo, int state, int *match); MODULE_SCOPE int PerStateInfo_Undefine(TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo, int domain, int state); MODULE_SCOPE GC Tree_GetGC(TreeCtrl *tree, unsigned long mask, XGCValues *gcValues); MODULE_SCOPE void Tree_FreeAllGC(TreeCtrl *tree); MODULE_SCOPE Pixmap PerStateBitmap_ForState(TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match); MODULE_SCOPE void PerStateBitmap_MaxSize(TreeCtrl *tree, PerStateInfo *pInfo, int *widthPtr, int *heightPtr); MODULE_SCOPE int PerStateBoolean_ForState(TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match); MODULE_SCOPE Tk_3DBorder PerStateBorder_ForState(TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match); MODULE_SCOPE TreeColor *PerStateColor_ForState(TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match); MODULE_SCOPE int PerStateFlags_ForState(TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match); MODULE_SCOPE Tk_Font PerStateFont_ForState(TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match); MODULE_SCOPE Tk_Image PerStateImage_ForState(TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match); MODULE_SCOPE void PerStateImage_MaxSize(TreeCtrl *tree, PerStateInfo *pInfo, int *widthPtr, int *heightPtr); MODULE_SCOPE int PerStateRelief_ForState(TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match); MODULE_SCOPE void PSTSave(PerStateInfo *pInfo, PerStateInfo *pSave); MODULE_SCOPE void PSTRestore(TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo, PerStateInfo *pSave); typedef struct CharFlag { char flagChar; int flagBit; } CharFlag; MODULE_SCOPE int Tree_GetFlagsFromString(TreeCtrl *tree, const char *string, int length, const char *typeStr, const CharFlag flags[], int *flagsPtr); MODULE_SCOPE int Tree_GetFlagsFromObj(TreeCtrl *tree, Tcl_Obj *obj, const char *typeStr, const CharFlag flags[], int *flagsPtr); #ifdef ALLOC_HAX MODULE_SCOPE ClientData TreeAlloc_Init(void); MODULE_SCOPE void TreeAlloc_Finalize(ClientData data); MODULE_SCOPE char *TreeAlloc_Alloc(ClientData data, Tk_Uid id, int size); MODULE_SCOPE char *TreeAlloc_CAlloc(ClientData data, Tk_Uid id, int size, int count, int roundUp); MODULE_SCOPE char *TreeAlloc_Realloc(ClientData data, Tk_Uid id, char *ptr, int size1, int size2); MODULE_SCOPE void TreeAlloc_Free(ClientData data, Tk_Uid id, char *ptr, int size); MODULE_SCOPE void TreeAlloc_CFree(ClientData data, Tk_Uid id, char *ptr, int size, int count, int roundUp); MODULE_SCOPE void TreeAlloc_Stats(Tcl_Interp *interp, ClientData data); #endif /*****/ MODULE_SCOPE void TreePtrList_Init(TreeCtrl *tree, TreePtrList *tilPtr, int count); MODULE_SCOPE void TreePtrList_Grow(TreePtrList *tilPtr, int count); MODULE_SCOPE ClientData *TreePtrList_Append(TreePtrList *tilPtr, ClientData ptr); MODULE_SCOPE ClientData *TreePtrList_Concat(TreePtrList *tilPtr, TreePtrList *til2Ptr); MODULE_SCOPE void TreePtrList_Free(TreePtrList *tilPtr); #define TreeItemList_Init TreePtrList_Init #define TreeItemList_Append TreePtrList_Append #define TreeItemList_Concat TreePtrList_Concat #define TreeItemList_Free TreePtrList_Free #define TreeItemList_Items(L) ((TreeItem *) (L)->pointers) #define TreeItemList_Nth(L,n) ((TreeItem) (L)->pointers[n]) #define TreeItemList_Count(L) ((L)->count) MODULE_SCOPE void TreeItemList_Sort(TreeItemList *items); #define TreeColumnList_Init TreePtrList_Init #define TreeColumnList_Append TreePtrList_Append #define TreeColumnList_Concat TreePtrList_Concat #define TreeColumnList_Free TreePtrList_Free #define TreeColumnList_Nth(L,n) ((TreeColumn) (L)->pointers[n]) #define TreeColumnList_Count(L) ((L)->count) /*****/ /* * This structure holds a list of tags. */ struct TagInfo { int numTags; /* Number of tag slots actually used * at tagPtr. */ int tagSpace; /* Total amount of tag space available * at tagPtr. */ #define TREE_TAG_SPACE 3 Tk_Uid tagPtr[TREE_TAG_SPACE]; /* Array of tags. The actual size will * be tagSpace. THIS FIELD MUST BE THE * LAST IN THE STRUCTURE. */ }; MODULE_SCOPE TagInfo *TagInfo_Add(TreeCtrl *tree, TagInfo *tagInfo, Tk_Uid tags[], int numTags); MODULE_SCOPE TagInfo *TagInfo_Remove(TreeCtrl *tree, TagInfo *tagInfo, Tk_Uid tags[], int numTags); MODULE_SCOPE Tk_Uid *TagInfo_Names(TreeCtrl *tree, TagInfo *tagInfo, Tk_Uid *tags, int *numTagsPtr, int *tagSpacePtr); MODULE_SCOPE TagInfo *TagInfo_Copy(TreeCtrl *tree, TagInfo *tagInfo); MODULE_SCOPE void TagInfo_Free(TreeCtrl *tree, TagInfo *tagInfo); MODULE_SCOPE int TagInfo_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TagInfo **tagInfoPtr); MODULE_SCOPE Tk_ObjCustomOption TreeCtrlCO_tagInfo; /* * This struct holds information about a tag expression. */ typedef struct TagExpr { TreeCtrl *tree; Tk_Uid *uids; /* expresion compiled to an array of uids */ Tk_Uid staticUids[15]; int allocated; /* available space for array of uids */ int length; /* number of uids */ int index; /* current position in expression evaluation */ int simple; /* TRUE if expr is single tag */ Tk_Uid uid; /* single tag if 'simple' is TRUE */ char *string; /* tag expression string */ int stringIndex; /* current position in string scan */ int stringLength; /* length of tag expression string */ char *rewritebuffer; /* tag string (after removing escapes) */ char staticRWB[100]; } TagExpr; MODULE_SCOPE int TagExpr_Init(TreeCtrl *tree, Tcl_Obj *exprObj, TagExpr *expr); MODULE_SCOPE int TagExpr_Scan(TagExpr *expr); MODULE_SCOPE int TagExpr_Eval(TagExpr *expr, TagInfo *tags); MODULE_SCOPE void TagExpr_Free(TagExpr *expr); MODULE_SCOPE Tk_OptionSpec *Tree_FindOptionSpec(Tk_OptionSpec *optionTable, CONST char *optionName); MODULE_SCOPE Tk_ObjCustomOption *PerStateCO_Alloc(CONST char *optionName, PerStateType *typePtr, StateFromObjProc proc); MODULE_SCOPE int PerStateCO_Init(Tk_OptionSpec *optionTable, CONST char *optionName, PerStateType *typePtr, StateFromObjProc proc); /*****/ typedef struct DynamicOptionSpec DynamicOptionSpec; typedef struct DynamicOption DynamicOption; struct DynamicOption { int id; /* Unique id. */ DynamicOption *next; /* Linked list. */ char data[1]; /* Actual size will be > 1 */ }; typedef void (DynamicOptionInitProc)(void *data); MODULE_SCOPE DynamicOption *DynamicOption_AllocIfNeeded(TreeCtrl *tree, DynamicOption **firstPtr, int id, int size, DynamicOptionInitProc *init); MODULE_SCOPE void *DynamicOption_FindData(DynamicOption *first, int id); MODULE_SCOPE void DynamicOption_Free(TreeCtrl *tree, DynamicOption *first, Tk_OptionSpec *optionTable); MODULE_SCOPE void DynamicOption_Free1(TreeCtrl *tree, DynamicOption **firstPtr, int id, int size); MODULE_SCOPE int DynamicCO_Init(Tk_OptionSpec *optionTable, CONST char *optionName, int id, int size, int objOffset, int internalOffset, Tk_ObjCustomOption *custom, DynamicOptionInitProc *init); /*****/ MODULE_SCOPE int Tree_InitOptions(TreeCtrl *tree, int domain, void *recordPtr, Tk_OptionTable optionTable); MODULE_SCOPE int Tree_SetOptions(TreeCtrl *tree, int domain, void *recordPtr, Tk_OptionTable optionTable, int objc, Tcl_Obj *CONST objv[], Tk_SavedOptions *savePtr, int *maskPtr); MODULE_SCOPE int BooleanFlagCO_Init(Tk_OptionSpec *optionTable, CONST char *optionName, int theFlag); MODULE_SCOPE int ItemButtonCO_Init(Tk_OptionSpec *optionTable, CONST char *optionName, int flag1, int flag2); MODULE_SCOPE void TreeStyleCO_Init(Tk_OptionSpec *optionTable, CONST char *optionName, int domain); MODULE_SCOPE int Tree_GetIntForIndex(TreeCtrl *tree, Tcl_Obj *objPtr, int *indexPtr, int *endRelativePtr); MODULE_SCOPE Tk_ObjCustomOption TreeCtrlCO_pixels; MODULE_SCOPE Tk_ObjCustomOption TreeCtrlCO_string; MODULE_SCOPE Tk_ObjCustomOption TreeCtrlCO_style; MODULE_SCOPE Tk_ObjCustomOption TreeCtrlCO_treecolor; /*****/ #define STATIC_SIZE 20 #define STATIC_ALLOC(P,T,C) \ do { \ if (C > STATIC_SIZE) \ P = (T *) ckalloc(sizeof(T) * (C)); \ } while (0) #define STATIC_FREE(P,T,C) \ do { \ CWIPE(P, T, C); \ if (C > STATIC_SIZE) \ ckfree((char *) P); \ } while (0) #define STATIC_FREE2(P,P2) \ do { \ if (P != P2) \ ckfree((char *) P); \ } while (0) MODULE_SCOPE TreeColor *Tree_AllocColorFromObj(TreeCtrl *tree, Tcl_Obj *obj); MODULE_SCOPE void Tree_FreeColor(TreeCtrl *tree, TreeColor *tc); MODULE_SCOPE Tcl_Obj *TreeColor_ToObj(TreeCtrl *tree, TreeColor *tc); MODULE_SCOPE int TreeColor_IsOpaque(TreeCtrl *tree, TreeColor *tc); #define pstGradient TreeCtrl_pstGradient MODULE_SCOPE PerStateType pstGradient; MODULE_SCOPE TreeGradient PerStateGradient_ForState(TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match); /*****/ typedef struct GradientCoord GradientCoord; /* * Records for gradient fills. * We need a separate GradientStopArray to simplify option parsing. */ typedef struct GradientStop { double offset; XColor *color; double opacity; } GradientStop; typedef struct GradientStopArray { int nstops; GradientStop **stops; /* Array of pointers to GradientStop. */ } GradientStopArray; typedef struct TreeGradient_ { int refCount; /* Number of users of gradient. */ int deletePending; /* Non-zero if gradient should be deleted when * last reference goes away. */ Tk_Uid name; Tcl_Obj *stopsObj; /* -stops */ GradientStopArray *stopArrPtr; /* -stops */ int vertical; /* -orient */ int steps; /* -steps */ int nStepColors; /* length of stepColors */ XColor **stepColors; /* calculated from color1,color2,steps */ GradientCoord *left, *right, *top, *bottom; Tcl_Obj *leftObj, *rightObj, *topObj, *bottomObj; } TreeGradient_; MODULE_SCOPE void TreeGradient_InitWidget(TreeCtrl *tree); MODULE_SCOPE void TreeGradient_FreeWidget(TreeCtrl *tree); MODULE_SCOPE int TreeGradientCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int TreeGradient_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeGradient *gradientPtr); MODULE_SCOPE void TreeGradient_Release(TreeCtrl *tree, TreeGradient gradient); MODULE_SCOPE int TreeGradient_IsOpaque(TreeCtrl *tree, TreeGradient gradient); MODULE_SCOPE int Tree_HasNativeGradients(TreeCtrl *tree); MODULE_SCOPE int TreeGradient_GetBrushBounds(TreeCtrl *tree, TreeGradient gradient, const TreeRectangle *trPaint, TreeRectangle *trBrush, TreeColumn column, TreeItem item); MODULE_SCOPE void TreeGradient_IsRelativeToCanvas(TreeGradient gradient, int *relX, int *relY); MODULE_SCOPE void TreeColor_GetBrushBounds(TreeCtrl *tree, TreeColor *tc, TreeRectangle trPaint, int xOrigin, int yOrigin, TreeColumn column, TreeItem item, TreeRectangle *trBrush); MODULE_SCOPE void TreeGradient_ColumnDeleted(TreeCtrl *tree, TreeColumn column); MODULE_SCOPE void TreeGradient_ItemDeleted(TreeCtrl *tree, TreeItem item); /*****/ typedef enum { TREE_CLIP_REGION, TREE_CLIP_RECT, TREE_CLIP_AREA } TreeClipType; typedef struct { TreeClipType type; TkRegion region; TreeRectangle tr; int area; } TreeClip; #define RECT_OPEN_W 0x01 #define RECT_OPEN_N 0x02 #define RECT_OPEN_E 0x04 #define RECT_OPEN_S 0x08 #define RECT_OPEN_WNES (RECT_OPEN_W|RECT_OPEN_N|RECT_OPEN_E|RECT_OPEN_S) MODULE_SCOPE void Tree_FillRectangle(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, GC gc, TreeRectangle tr); #if USE_ITEM_PIXMAP == 0 MODULE_SCOPE void Tree_DrawArc(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, GC gc, int x, int y, unsigned int width, unsigned int height, int start, int extent); MODULE_SCOPE void Tree_FillArc(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, GC gc, int x, int y, unsigned int width, unsigned int height, int start, int extent); MODULE_SCOPE void Tree_Draw3DRectangle(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, Tk_3DBorder border, int x, int y, int width, int height, int borderWidth, int relief); MODULE_SCOPE void Tree_Fill3DRectangle(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, Tk_3DBorder border, int x, int y, int width, int height, int borderWidth, int relief); #else /* USE_ITEM_PIXMAP == 1 */ #define Tree_DrawArc(tree,td,clip,gc,x,y,width,height,start,extent) \ XDrawArc(tree->display,td.drawable,gc,x,y,width,height,start,extent); #define Tree_FillArc(tree,td,clip,gc,x,y,width,height,start,extent) \ XFillArc(tree->display,td.drawable,gc,x,y,width,height,start,extent); #endif /* USE_ITEM_PIXMAP == 1 */ MODULE_SCOPE void Tree_DrawRoundRectX11(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, GC gc, TreeRectangle tr, int outlineWidth, int rx, int ry, int open); MODULE_SCOPE void Tree_FillRoundRectX11(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, GC gc, TreeRectangle tr, int rx, int ry, int open); MODULE_SCOPE void TreeGradient_DrawRectX11(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeGradient gradient, TreeRectangle trBrush, TreeRectangle tr, int outlineWidth, int open); MODULE_SCOPE void TreeGradient_FillRectX11(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeGradient gradient, TreeRectangle trBrush, TreeRectangle tr); MODULE_SCOPE void TreeGradient_FillRoundRectX11(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeGradient gradient, TreeRectangle trBrush, TreeRectangle tr, int rx, int ry, int open); MODULE_SCOPE void Tree_DrawRoundRect(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, XColor *xcolor, TreeRectangle tr, int outlineWidth, int rx, int ry, int open); MODULE_SCOPE void Tree_FillRoundRect(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, XColor *xcolor, TreeRectangle tr, int rx, int ry, int open); MODULE_SCOPE void TreeGradient_DrawRect(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeGradient gradient, TreeRectangle trBrush, TreeRectangle tr, int outlineWidth, int open); MODULE_SCOPE void TreeGradient_DrawRoundRect(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeGradient gradient, TreeRectangle trBrush, TreeRectangle tr, int outlineWidth, int rx, int ry, int open); MODULE_SCOPE void TreeGradient_FillRect(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeGradient gradient, TreeRectangle trBrush, TreeRectangle tr); MODULE_SCOPE void TreeGradient_FillRoundRect(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeGradient gradient, TreeRectangle trBrush, TreeRectangle tr, int rx, int ry, int open); MODULE_SCOPE void TreeColor_DrawRect(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeColor *tc, TreeRectangle trBrush, TreeRectangle tr, int outlineWidth, int open); MODULE_SCOPE void TreeColor_FillRect(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeColor *tc, TreeRectangle trBrush, TreeRectangle tr); MODULE_SCOPE void TreeColor_DrawRoundRect(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeColor *tc, TreeRectangle trBrush, TreeRectangle tr, int outlineWidth, int rx, int ry, int open); MODULE_SCOPE void TreeColor_FillRoundRect(TreeCtrl *tree, TreeDrawable td, TreeClip *clip, TreeColor *tc, TreeRectangle trBrush, TreeRectangle tr, int rx, int ry, int open); MODULE_SCOPE int TreeDraw_InitInterp(Tcl_Interp *interp); tktreectrl-2.4.1/generic/tkTreeDisplay.c0000644000076400010400000077507411572030172020601 0ustar TimAdministrators/* * tkTreeDisplay.c -- * * This module implements treectrl widget's main display code. * * Copyright (c) 2002-2011 Tim Baker */ #include "tkTreeCtrl.h" /* Window -> Canvas */ #define W2Cx(x) ((x) + tree->xOrigin) #define W2Cy(y) ((y) + tree->yOrigin) #define DW2Cx(x) ((x) + dInfo->xOrigin) #define DW2Cy(y) ((y) + dInfo->yOrigin) /* Canvas -> Window */ #define C2Wx(x) ((x) - tree->xOrigin) #define C2Wy(y) ((y) - tree->yOrigin) #define COMPLEX_WHITESPACE #define REDRAW_RGN 0 #define CACHE_BG_IMG 1 typedef struct TreeColumnDInfo_ TreeColumnDInfo_; typedef struct TreeDInfo_ TreeDInfo_; typedef struct RItem RItem; typedef struct Range Range; typedef struct DItem DItem; typedef struct DItemArea DItemArea; typedef struct DScrollIncrements DScrollIncrements; static void CheckPendingHeaderUpdate(TreeCtrl *tree); static void Range_RedoIfNeeded(TreeCtrl *tree); static int Range_TotalWidth(TreeCtrl *tree, Range *range_); static int Range_TotalHeight(TreeCtrl *tree, Range *range_); static void Range_Redo(TreeCtrl *tree); static Range *Range_UnderPoint(TreeCtrl *tree, int *x_, int *y_, int nearest); static Pixmap DisplayGetPixmap(TreeCtrl *tree, TreeDrawable *dPixmap, int width, int height); #if COLUMNGRID == 1 static int GridLinesInWhiteSpace(TreeCtrl *tree); #endif /* One of these per TreeItem that is ReallyVisible(). */ struct RItem { TreeItem item; /* The item. */ Range *range; /* Range the item is in. */ int size; /* Height or width consumed in Range. */ int offset; /* Vertical or horizontal offset in Range. */ struct { /* Spacing between adjacent items: */ int x, y; /* x is to right of this item. */ } gap; /* y is below this item. */ int index; /* 0-based index in Range. */ }; /* A collection of visible TreeItems. */ struct Range { RItem *first; RItem *last; int totalWidth; int totalHeight; int index; /* 0-based index in list of Ranges. */ struct { int x, y; /* vertical/horizontal offset from canvas */ } offset; /* top/left. */ Range *prev; Range *next; }; struct DItemArea { int x; /* Where it should be drawn, window coords. */ int width; /* Current width. */ int dirty[4]; /* Dirty area in item coords. */ #define DITEM_DIRTY 0x0001 #define DITEM_ALL_DIRTY 0x0002 #define DITEM_DRAWN 0x0004 int flags; }; /* Display information for a TreeItem that is onscreen. */ struct DItem { #ifdef TREECTRL_DEBUG char magic[4]; #endif TreeItem item; int y; /* Where it should be drawn, window coords. */ int height; /* Current height. */ DItemArea area; /* COLUMN_LOCK_NONE. */ DItemArea left, right; /* COLUMN_LOCK_LEFT, COLUMN_LOCK_RIGHT. */ #define DITEM_INVALIDATE_ON_SCROLL_X 0x0001 #define DITEM_INVALIDATE_ON_SCROLL_Y 0x0002 int flags; int oldX, oldY; /* Where it was last drawn, window coords. */ Range *range; /* Range the TreeItem is in. */ int index; /* Used for alternating background colors. */ int oldIndex; /* Used for alternating background colors. */ int *spans; /* span[n] is the column index of the item * column displayed at the n'th tree column. */ DItem *next; /* Linked list of displayed items. */ }; /* Display information for a TreeColumn. */ struct TreeColumnDInfo_ { int offset; /* Last seen x-offset */ int width; /* Last seen column width */ }; struct DScrollIncrements { int *increments; /* When TreeCtrl.x|yScrollIncrement is zero */ int count; /* Size of increments[]. */ }; /* Display information for a TreeCtrl. */ struct TreeDInfo_ { GC scrollGC; int xOrigin; /* Last seen TreeCtrl.xOrigin */ int yOrigin; /* Last seen TreeCtrl.yOrigin */ int totalWidth; /* Last seen Tree_CanvasWidth() */ int totalHeight; /* Last seen Tree_CanvasHeight() */ int fakeCanvasWidth; /* totalWidth plus any "fake" width resulting * from the view being locked to the edge of * a scroll increment. */ int fakeCanvasHeight; /* totalHeight plus any "fake" height resulting * from the view being locked to the edge of * a scroll increment.*/ int headerHeight; /* Last seen TreeCtrl.headerHeight */ DItem *dItem; /* Head of list for each displayed item */ DItem *dItemHeader; /* Head of list for each displayed header */ DItem *dItemLast; /* Temp for UpdateDInfo() */ DItem *dItemFree; /* List of unused DItems */ Range *rangeFirst; /* Head of Ranges */ Range *rangeLast; /* Tail of Ranges */ Range *rangeFirstD; /* First range with valid display info */ Range *rangeLastD; /* Last range with valid display info */ RItem *rItem; /* Block of RItems for all Ranges */ int rItemMax; /* size of rItem[] */ int itemHeight; /* Observed max TreeItem height */ int itemWidth; /* Observed max TreeItem width */ TreeDrawable pixmapW; /* Pixmap as big as the window */ TreeDrawable pixmapI; /* Pixmap as big as the largest item */ TreeDrawable pixmapT; /* Pixmap as big as the window. Use on non-composited desktops when displaying non-XOR dragimage, marquee and/or proxies. */ TkRegion dirtyRgn; /* DOUBLEBUFFER_WINDOW */ int flags; /* DINFO_XXX */ DScrollIncrements xScrollIncrements; DScrollIncrements yScrollIncrements; TkRegion wsRgn; /* Region containing whitespace */ #ifdef COMPLEX_WHITESPACE int complexWhitespace; #endif Tcl_HashTable itemVisHash; /* Table of visible items */ Tcl_HashTable headerVisHash;/* Table of visible header items */ int requests; /* Incremented for every call to Tree_EventuallyRedraw */ TreeRectangle bounds; /* Bounds of TREE_AREA_CONTENT. */ TreeRectangle boundsL; /* Bounds of TREE_AREA_LEFT. */ TreeRectangle boundsR; /* Bounds of TREE_AREA_RIGHT. */ int empty, emptyL, emptyR; /* Whether bounds above are zero-sized.*/ int widthOfColumnsLeft; /* Last seen Tree_WidthOfLeftColumns() */ int widthOfColumnsRight; /* Last seen Tree_WidthOfRightColumns() */ Range *rangeLock; /* If there is no Range for non-locked * columns, this range holds the vertical * offset and height of each ReallyVisible * item for displaying locked columns. */ #if REDRAW_RGN == 1 TkRegion redrawRgn; /* Contains all redrawn (not copied) pixels * during a single Tree_Display call. */ #endif /* REDRAW_RGN */ int overlays; /* TRUE if the dragimage|marquee|proxy * were drawn in non-XOR mode. */ #if CACHE_BG_IMG TreeDrawable pixmapBgImg; /* Pixmap containing the -backgroundimage * for efficient blitting. Not used if the * -backgroundimage is transparent. */ #endif }; #ifdef COMPLEX_WHITESPACE static int ComplexWhitespace(TreeCtrl *tree); #endif static int CalcBgImageBounds(TreeCtrl *tree, TreeRectangle *trImage); /*========*/ void Tree_FreeItemRInfo( TreeCtrl *tree, TreeItem item ) { TreeItem_SetRInfo(tree, item, NULL); } static Range * Range_Free( TreeCtrl *tree, Range *range ) { Range *next = range->next; WFREE(range, Range); return next; } /* *---------------------------------------------------------------------- * * ItemWidthParams -- * * Calculates the fixed or incremental width of all items. * This is called when -orient=horizontal. * * Results: * Returns the fixed width all items should be, or -1. * Returns the width all item widths should be a multiple of, or -1. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void ItemWidthParams( TreeCtrl *tree, /* Widget info. */ int *fixedWidthPtr, /* Returned fixed width or -1. */ int *stepWidthPtr /* Returned incremental width or -1. */ ) { int fixedWidth = -1, stepWidth = -1; /* More than one item column, so all items have the same width */ if (tree->columnCountVis > 1) fixedWidth = Tree_WidthOfColumns(tree); /* Single item column, fixed width for all items */ else if (tree->itemWidth > 0) fixedWidth = tree->itemWidth; /* Single item column, fixed width for all items */ /* THIS IS FOR COMPATIBILITY ONLY */ else if (TreeColumn_FixedWidth(tree->columnVis) != -1) fixedWidth = TreeColumn_FixedWidth(tree->columnVis); /* Single item column, want all items same width */ else if (tree->itemWidthEqual #ifdef DEPRECATED || TreeColumn_WidthHack(tree->columnVis) #endif /* DEPRECATED */ ) { fixedWidth = TreeColumn_WidthOfItems(tree->columnVis); /* Each item is a multiple of this width */ if (tree->itemWidMult > 0) stepWidth = tree->itemWidMult; #ifdef DEPRECATED else stepWidth = TreeColumn_StepWidth(tree->columnVis); #endif /* DEPRECATED */ if ((stepWidth != -1) && (fixedWidth % stepWidth)) fixedWidth += stepWidth - fixedWidth % stepWidth; } /* Single item column, variable item width */ else { /* Each item is a multiple of this width */ if (tree->itemWidMult > 0) stepWidth = tree->itemWidMult; #ifdef DEPRECATED else stepWidth = TreeColumn_StepWidth(tree->columnVis); #endif /* DEPRECATED */ } (*fixedWidthPtr) = fixedWidth; (*stepWidthPtr) = stepWidth; } /* *---------------------------------------------------------------------- * * Range_Redo -- * * This procedure puts all ReallyVisible() TreeItems into a list of * Ranges. If tree->wrapMode is TREE_WRAP_NONE and no visible items * have the -wrap=true option there will only be a single Range. * * Results: * None. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void Range_Redo( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; Range *rangeList = dInfo->rangeFirst; Range *range; RItem *rItem; TreeItem item = tree->root; int fixedWidth = -1, stepWidth = -1; int wrapCount = 0, wrapPixels = 0; int count, pixels, rItemCount = 0; int rangeIndex = 0, rItemIndex; int *canvasPad; if (tree->debug.enable && tree->debug.display) dbwin("Range_Redo %s\n", Tk_PathName(tree->tkwin)); /* Update column variables */ (void) Tree_WidthOfColumns(tree); dInfo->rangeFirst = NULL; dInfo->rangeLast = NULL; if (tree->columnCountVis < 1) goto freeRanges; switch (tree->wrapMode) { case TREE_WRAP_NONE: break; case TREE_WRAP_ITEMS: wrapCount = tree->wrapArg; break; case TREE_WRAP_PIXELS: wrapPixels = tree->wrapArg; break; case TREE_WRAP_WINDOW: wrapPixels = tree->vertical ? Tree_ContentHeight(tree) : Tree_ContentWidth(tree); if (wrapPixels < 0) wrapPixels = 0; break; } /* For horizontal layout with wrapping I need to know how wide each item * is. */ if ((wrapPixels > 0) && !tree->vertical) { ItemWidthParams(tree, &fixedWidth, &stepWidth); } /* Speed up ReallyVisible() and get itemVisCount */ Tree_UpdateItemIndex(tree); if (dInfo->rItemMax < tree->itemVisCount) { dInfo->rItem = (RItem *) ckrealloc((char *) dInfo->rItem, tree->itemVisCount * sizeof(RItem)); dInfo->rItemMax = tree->itemVisCount; } if (!TreeItem_ReallyVisible(tree, item)) item = TreeItem_NextVisible(tree, item); while (item != NULL) { if (rangeList == NULL) range = (Range *) ckalloc(sizeof(Range)); else { range = rangeList; rangeList = rangeList->next; } memset(range, '\0', sizeof(Range)); range->totalWidth = -1; range->totalHeight = -1; range->index = rangeIndex++; count = 0; canvasPad = tree->vertical ? tree->canvasPadY : tree->canvasPadX; pixels = 0; rItemIndex = 0; while (1) { rItem = dInfo->rItem + rItemCount; if (rItemCount >= dInfo->rItemMax) panic("rItemCount > dInfo->rItemMax"); if (range->first == NULL) range->first = range->last = rItem; TreeItem_SetRInfo(tree, item, (TreeItemRInfo) rItem); rItem->item = item; rItem->range = range; rItem->index = rItemIndex; rItem->gap.x = rItem->gap.y = 0; /* Range must be <= this number of pixels */ if (wrapPixels > 0) { rItem->offset = pixels; if (tree->vertical) { rItem->size = TreeItem_Height(tree, item); } else { if (fixedWidth != -1) { rItem->size = fixedWidth; } else { TreeItemColumn itemColumn = TreeItem_FindColumn(tree, item, TreeColumn_Index(tree->columnVis)); if (itemColumn != NULL) { int columnWidth = TreeItemColumn_NeededWidth(tree, item, itemColumn); columnWidth += TreeItem_Indent(tree, tree->columnVis, item); rItem->size = columnWidth; } else rItem->size = 0; if ((stepWidth != -1) && (rItem->size % stepWidth)) rItem->size += stepWidth - rItem->size % stepWidth; } } /* Check if this item's bounds exceeds the -wrap distance. */ if (canvasPad[PAD_TOP_LEFT] + pixels + rItem->size + canvasPad[PAD_BOTTOM_RIGHT] > wrapPixels) { /* Remove the gap from the previous item in this range. */ if (rItem->index > 0) { if (tree->vertical) { pixels -= (rItem-1)->gap.y; (rItem-1)->gap.y = 0; } else { pixels -= (rItem-1)->gap.x; (rItem-1)->gap.x = 0; } } /* Ensure at least one item is in this Range */ if (rItemIndex == 0) { if (tree->vertical) { rItem->gap.y = tree->itemGapY; pixels += rItem->gap.y; } else { rItem->gap.x = tree->itemGapX; pixels += rItem->gap.x; } pixels += rItem->size; rItemCount++; } break; } if (tree->vertical) { rItem->gap.y = tree->itemGapY; pixels += rItem->gap.y; } else { rItem->gap.x = tree->itemGapX; pixels += rItem->gap.x; } pixels += rItem->size; } range->last = rItem; rItemIndex++; rItemCount++; if (++count == wrapCount) break; item = TreeItem_NextVisible(tree, item); if (item == NULL) break; if (TreeItem_GetWrap(tree, item)) break; } /* If we needed to calculate the height or width of this range, * we don't need to do it later in Range_TotalWidth/Height() */ if (wrapPixels > 0) { if (tree->vertical) { /* Remove the gap from the last item in this range. */ if (range->last->gap.y > 0) { pixels -= range->last->gap.y; range->last->gap.y = 0; } range->totalHeight = pixels; } else { /* Remove the gap from the last item in this range. */ if (range->last->gap.x > 0) { pixels -= range->last->gap.x; range->last->gap.x = 0; } range->totalWidth = pixels; } } if (dInfo->rangeFirst == NULL) dInfo->rangeFirst = range; else { range->prev = dInfo->rangeLast; dInfo->rangeLast->next = range; } dInfo->rangeLast = range; item = TreeItem_NextVisible(tree, range->last->item); } freeRanges: while (rangeList != NULL) rangeList = Range_Free(tree, rangeList); /* If there are no visible non-locked columns, we won't have a Range. * But we need to know the offset/size of each item for drawing any * locked columns (and for vertical scrolling... and hit testing). */ if (dInfo->rangeLock != NULL) { (void) Range_Free(tree, dInfo->rangeLock); dInfo->rangeLock = NULL; } (void) Tree_WidthOfColumns(tree); /* update columnCountVisLeft etc */ if ((dInfo->rangeFirst == NULL) && (tree->columnCountVisLeft || tree->columnCountVisRight)) { /* Speed up ReallyVisible() and get itemVisCount */ Tree_UpdateItemIndex(tree); if (tree->itemVisCount == 0) return; if (dInfo->rItemMax < tree->itemVisCount) { dInfo->rItem = (RItem *) ckrealloc((char *) dInfo->rItem, tree->itemVisCount * sizeof(RItem)); dInfo->rItemMax = tree->itemVisCount; } dInfo->rangeLock = (Range *) ckalloc(sizeof(Range)); range = dInfo->rangeLock; pixels = 0; rItemIndex = 0; rItem = dInfo->rItem; item = tree->root; if (!TreeItem_ReallyVisible(tree, item)) item = TreeItem_NextVisible(tree, item); while (item != NULL) { rItem->item = item; rItem->range = range; rItem->size = TreeItem_Height(tree, item); rItem->offset = pixels; rItem->gap.x = 0; if (TreeItem_NextVisible(tree, item) != NULL) { rItem->gap.y = tree->itemGapY; } else { rItem->gap.y = 0; } pixels += rItem->gap.y; rItem->index = rItemIndex++; TreeItem_SetRInfo(tree, item, (TreeItemRInfo) rItem); pixels += rItem->size; rItem++; item = TreeItem_NextVisible(tree, item); } range->offset.x = 0; range->offset.y = 0; range->first = dInfo->rItem; range->last = dInfo->rItem + tree->itemVisCount - 1; range->totalWidth = 1; range->totalHeight = pixels; range->prev = range->next = NULL; } } /* *---------------------------------------------------------------------- * * Range_TotalWidth -- * * Return the width of a Range. The width is only calculated if * it hasn't been done yet by Range_Redo(). * * Results: * Pixel width of the Range. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Range_TotalWidth( TreeCtrl *tree, /* Widget info. */ Range *range /* Range to return the width of. */ ) { TreeItem item; TreeItemColumn itemColumn; RItem *rItem; int fixedWidth = -1, stepWidth = -1; int itemWidth; if (range->totalWidth >= 0) return range->totalWidth; if (tree->vertical) { /* More than one item column, so all ranges have the same width */ if (tree->columnCountVis > 1) return range->totalWidth = Tree_WidthOfColumns(tree); /* If wrapping is disabled, then use the column width, * since it may expand to fill the window */ if ((tree->wrapMode == TREE_WRAP_NONE) && (tree->itemWrapCount <= 0)) return range->totalWidth = TreeColumn_UseWidth(tree->columnVis); /* Single item column, fixed width for all ranges */ if (tree->itemWidth > 0) return range->totalWidth = tree->itemWidth; /* Single item column, fixed width for all ranges */ /* THIS IS FOR COMPATIBILITY ONLY */ if (TreeColumn_FixedWidth(tree->columnVis) != -1) return range->totalWidth = TreeColumn_FixedWidth(tree->columnVis); /* Single item column, each item is a multiple of this width */ if (tree->itemWidMult > 0) stepWidth = tree->itemWidMult; #ifdef DEPRECATED else stepWidth = TreeColumn_StepWidth(tree->columnVis); #endif /* DEPRECATED */ /* Single item column, want all items same width */ if (tree->itemWidthEqual #ifdef DEPRECATED || TreeColumn_WidthHack(tree->columnVis) #endif /* DEPRECATED */ ) { range->totalWidth = TreeColumn_WidthOfItems(tree->columnVis); if ((stepWidth != -1) && (range->totalWidth % stepWidth)) range->totalWidth += stepWidth - range->totalWidth % stepWidth; return range->totalWidth; } /* Max needed width of items in this range */ range->totalWidth = 0; rItem = range->first; while (1) { item = rItem->item; itemColumn = TreeItem_FindColumn(tree, item, TreeColumn_Index(tree->columnVis)); if (itemColumn != NULL) itemWidth = TreeItemColumn_NeededWidth(tree, item, itemColumn); else itemWidth = 0; itemWidth += TreeItem_Indent(tree, tree->columnVis, item); if (itemWidth > range->totalWidth) range->totalWidth = itemWidth; if (rItem == range->last) break; rItem++; } if ((stepWidth != -1) && (range->totalWidth % stepWidth)) range->totalWidth += stepWidth - range->totalWidth % stepWidth; return range->totalWidth; /* -orient=horizontal */ } else { ItemWidthParams(tree, &fixedWidth, &stepWidth); /* Sum of widths of items in this range */ range->totalWidth = 0; rItem = range->first; while (1) { item = rItem->item; if (fixedWidth != -1) itemWidth = fixedWidth; else { itemColumn = TreeItem_FindColumn(tree, item, TreeColumn_Index(tree->columnVis)); if (itemColumn != NULL) itemWidth = TreeItemColumn_NeededWidth(tree, item, itemColumn); else itemWidth = 0; itemWidth += TreeItem_Indent(tree, tree->columnVis, item); if ((stepWidth != -1) && (itemWidth % stepWidth)) itemWidth += stepWidth - itemWidth % stepWidth; } rItem = (RItem *) TreeItem_GetRInfo(tree, item); rItem->offset = range->totalWidth; rItem->size = itemWidth; if (rItem != range->last) { rItem->gap.x = tree->itemGapX; } else { rItem->gap.x = 0; } range->totalWidth += rItem->gap.x; range->totalWidth += rItem->size; if (rItem == range->last) break; rItem++; } return range->totalWidth; } } /* *---------------------------------------------------------------------- * * Range_TotalHeight -- * * Return the height of a Range. The height is only calculated if * it hasn't been done yet by Range_Redo(). * * Results: * Pixel height of the Range. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Range_TotalHeight( TreeCtrl *tree, /* Widget info. */ Range *range /* Range to return the height of. */ ) { TreeItem item; RItem *rItem; int itemHeight; if (range->totalHeight >= 0) return range->totalHeight; range->totalHeight = 0; rItem = range->first; while (1) { item = rItem->item; itemHeight = TreeItem_Height(tree, item); if (tree->vertical) { rItem->offset = range->totalHeight; rItem->size = itemHeight; if (rItem != range->last) { rItem->gap.y = tree->itemGapY; } else { rItem->gap.y = 0; } range->totalHeight += rItem->gap.y; range->totalHeight += rItem->size; } else { if (itemHeight > range->totalHeight) range->totalHeight = itemHeight; } if (rItem == range->last) break; rItem++; } return range->totalHeight; } /* *---------------------------------------------------------------------- * * Tree_CanvasWidth -- * * Return the width needed by all the Ranges. The width is only * recalculated if it was marked out-of-date. * * Results: * Pixel width of the "canvas". * * Side effects: * The list of Ranges will be recalculated if needed. * *---------------------------------------------------------------------- */ int Tree_CanvasWidth( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; Range *range; int rangeWidth; Range_RedoIfNeeded(tree); if (tree->totalWidth >= 0) return tree->totalWidth; if (dInfo->rangeFirst == NULL) return tree->totalWidth = tree->canvasPadX[PAD_TOP_LEFT] + Tree_WidthOfColumns(tree) + tree->canvasPadX[PAD_BOTTOM_RIGHT]; tree->totalWidth = tree->canvasPadX[PAD_TOP_LEFT]; range = dInfo->rangeFirst; while (range != NULL) { rangeWidth = Range_TotalWidth(tree, range); if (tree->vertical) { range->offset.x = tree->totalWidth; tree->totalWidth += rangeWidth; if (range->next != NULL) tree->totalWidth += tree->itemGapX; } else { range->offset.x = tree->canvasPadX[PAD_TOP_LEFT]; if (range->offset.x + rangeWidth > tree->totalWidth) tree->totalWidth = range->offset.x + rangeWidth; } range = range->next; } tree->totalWidth += tree->canvasPadX[PAD_BOTTOM_RIGHT]; return tree->totalWidth; } /* *---------------------------------------------------------------------- * * Tree_CanvasHeight -- * * Return the height needed by all the Ranges. The height is only * recalculated if it was marked out-of-date. * * Results: * Pixel height of the "canvas". * * Side effects: * The list of Ranges will be recalculated if needed. * *---------------------------------------------------------------------- */ int Tree_CanvasHeight( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; Range *range; int rangeHeight; Range_RedoIfNeeded(tree); if (tree->totalHeight >= 0) return tree->totalHeight; tree->totalHeight = tree->canvasPadY[PAD_TOP_LEFT]; /* If dInfo->rangeLock is not NULL, then we are displaying some items * in locked columns but no non-locked columns. */ range = dInfo->rangeFirst ? dInfo->rangeFirst : dInfo->rangeLock; while (range != NULL) { rangeHeight = Range_TotalHeight(tree, range); if (tree->vertical) { range->offset.y = tree->canvasPadY[PAD_TOP_LEFT]; if (range->offset.y + rangeHeight > tree->totalHeight) tree->totalHeight = range->offset.y + rangeHeight; } else { range->offset.y = tree->totalHeight; tree->totalHeight += rangeHeight; if (range->next != NULL) tree->totalHeight += tree->itemGapY; } range = range->next; } tree->totalHeight += tree->canvasPadY[PAD_BOTTOM_RIGHT]; return tree->totalHeight; } /* *---------------------------------------------------------------------- * * Range_UnderPoint -- * * Return the Range containing the given coordinates. * * Results: * Range containing the coordinates or NULL if the point is * outside any Range. * * Side effects: * The list of Ranges will be recalculated if needed. * *---------------------------------------------------------------------- */ static Range * Range_UnderPoint( TreeCtrl *tree, /* Widget info. */ int *x_, /* In: window x coordinate. * Out: x coordinate relative to the top-left * of the Range. */ int *y_, /* In: window y coordinate. * Out: y coordinate relative to the top-left * of the Range. */ int nearest /* TRUE if the Range nearest the coordinates * should be returned. */ ) { TreeDInfo dInfo = tree->dInfo; Range *range; int x = *x_, y = *y_; Range_RedoIfNeeded(tree); if (Tree_CanvasWidth(tree) - tree->canvasPadX[PAD_TOP_LEFT] - tree->canvasPadX[PAD_BOTTOM_RIGHT] <= 0) return NULL; if (Tree_CanvasHeight(tree) - tree->canvasPadY[PAD_TOP_LEFT] - tree->canvasPadY[PAD_BOTTOM_RIGHT] <= 0) return NULL; range = dInfo->rangeFirst; if (nearest) { TreeRectangle tr; /* Keep inside borders and header. Perhaps another flag needed. */ if (!Tree_AreaBbox(tree, TREE_AREA_CONTENT, &tr)) return NULL; TreeRect_ClipPoint(tr, &x, &y); x = W2Cx(x); y = W2Cy(y); if (tree->vertical) { while (range != NULL) { if (x < range->offset.x) x = range->offset.x; if (y < range->offset.y) y = range->offset.y; if (x < range->offset.x + range->totalWidth || range->next == NULL) { (*x_) = MIN(x - range->offset.x, range->totalWidth - 1); (*y_) = MIN(y - range->offset.y, range->totalHeight - 1); return range; } if (x - (range->offset.x + range->totalWidth) < range->next->offset.x - x) { (*x_) = MIN(x - range->offset.x, range->totalWidth - 1); (*y_) = MIN(y - range->offset.y, range->totalHeight - 1); return range; } range = range->next; } } else { while (range != NULL) { if (x < range->offset.x) x = range->offset.x; if (y < range->offset.y) y = range->offset.y; if (y < range->offset.y + range->totalHeight || range->next == NULL) { (*x_) = MIN(x - range->offset.x, range->totalWidth - 1); (*y_) = MIN(y - range->offset.y, range->totalHeight - 1); return range; } if (y - (range->offset.y + range->totalHeight) < range->next->offset.y - y) { (*x_) = MIN(x - range->offset.x, range->totalWidth - 1); (*y_) = MIN(y - range->offset.y, range->totalHeight - 1); return range; } range = range->next; } } return NULL; } x = W2Cx(x); y = W2Cy(y); while (range != NULL) { if (tree->vertical && x < range->offset.x) return NULL; if (!tree->vertical && y < range->offset.y) return NULL; if ((x >= range->offset.x) && (x < range->offset.x + range->totalWidth) && (y >= range->offset.y) && (y < range->offset.y + range->totalHeight)) { (*x_) = x - range->offset.x; (*y_) = y - range->offset.y; return range; } range = range->next; } return NULL; } /* *---------------------------------------------------------------------- * * Range_ItemUnderPoint -- * * Return the RItem containing the given x and/or y coordinates. * * Results: * RItem containing the coordinates, or the RItem nearest the * coordinates, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static RItem * Range_ItemUnderPoint( TreeCtrl *tree, /* Widget info. */ Range *range, /* Range to search. */ int rcX, /* x coordinate relative to top-left of * the Range. */ int rcY, /* y coordinate relative to top-left of * the Range. */ int *icX, /* x coordinate relative to top-left of * the returned RItem. May be NULL. */ int *icY, /* y coordinate relative to top-left of * the returned RItem. May be NULL. */ int nearest /* '0' means return NULL if point is outside * every item. * '1' means return the nearest item. * '2' means return the nearest item. If the * point is in whitespace before/between * items, the item before the gap is returned. * '3' means return the nearest item. If the * point is in whitespace before/between * items, the item after the gap is returned. */ ) { RItem *rItem; int i, l, u; int rcOffset = tree->vertical ? rcY : rcX; if (nearest == 0) { if (!tree->vertical && (rcX < 0 || rcX >= range->totalWidth)) return NULL; if (tree->vertical && (rcY < 0 || rcY >= range->totalHeight)) return NULL; /* Binary search */ l = 0; u = range->last->index; while (l <= u) { i = (l + u) / 2; rItem = range->first + i; if ((rcOffset >= rItem->offset) && (rcOffset < rItem->offset + rItem->size)) { foundItem: /* Range -> item coords */ if (tree->vertical) { if (icX != NULL) (*icX) = rcX; if (icY != NULL) (*icY) = rcY - rItem->offset; } else { if (icX != NULL) (*icX) = rcX - rItem->offset; if (icY != NULL) (*icY) = rcY; } return rItem; } if ((rcOffset < rItem->offset) && ((rItem == range->first) || (rcOffset >= (rItem-1)->offset + (rItem-1)->size))) { /* Between previous item and this one. */ return NULL; } if ((rcOffset >= rItem->offset + rItem->size) && ((rItem == range->last) || (rcOffset < (rItem+1)->offset))) { /* Between next item and this one. */ return NULL; } if (rcOffset < rItem->offset) u = i - 1; else l = i + 1; } return NULL; } /* Binary search */ l = 0; u = range->last->index; while (l <= u) { i = (l + u) / 2; rItem = range->first + i; if ((rcOffset >= rItem->offset) && (rcOffset < rItem->offset + rItem->size)) { goto foundItem; } if ((rcOffset < rItem->offset) && ((rItem == range->first) || (rcOffset >= (rItem-1)->offset + (rItem-1)->size))) { /* Between previous item and this one. */ if (rItem != range->first) { RItem *prev = rItem - 1; if (nearest == 1) { int edgeMin = prev->offset + prev->size; int edgeMax = rItem->offset; if (rcOffset < edgeMin + (edgeMax - edgeMin) / 2.0f) rItem = prev; } else if (nearest == 2) rItem = prev; } goto foundItem; } if ((rcOffset >= rItem->offset + rItem->size) && ((rItem == range->last) || (rcOffset < (rItem+1)->offset))) { /* Between next item and this one. */ if (rItem != range->last) { RItem *next = rItem + 1; if (nearest == 1) { int edgeMin = rItem->offset + rItem->size; int edgeMax = next->offset; if (rcOffset >= edgeMin + (edgeMax - edgeMin) / 2.0f) rItem = next; } else if (nearest == 3) rItem = next; } goto foundItem; } if (rcOffset < rItem->offset) u = i - 1; else l = i + 1; } return NULL; } /* *---------------------------------------------------------------------- * * Increment_AddX -- * * Appends one or more values to the list of horizontal scroll * increments. * * Results: * New size of DInfo.xScrollIncrements. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static int Increment_AddX( TreeCtrl *tree, /* Widget info. */ int offset, /* Offset to add. */ int size /* Current size of DInfo.xScrollIncrements. */ ) { TreeDInfo dInfo = tree->dInfo; DScrollIncrements *dIncr = &dInfo->xScrollIncrements; int visWidth = Tree_ContentWidth(tree); while ((visWidth > 1) && (dIncr->count > 0) && (offset - dIncr->increments[dIncr->count - 1] > visWidth)) { size = Increment_AddX(tree, dIncr->increments[dIncr->count - 1] + visWidth, size); } #ifdef TREECTRL_DEBUG if ((dIncr->count > 0) && (offset == dIncr->increments[dIncr->count - 1])) { panic("Increment_AddX: offset %d same as previous offset", offset); } #endif if (dIncr->count + 1 > size) { size *= 2; dIncr->increments = (int *) ckrealloc( (char *) dIncr->increments, size * sizeof(int)); } dIncr->increments[dIncr->count++] = offset; return size; } /* *---------------------------------------------------------------------- * * Increment_AddY -- * * Appends one or more values to the list of vertical scroll * increments. * * Results: * New size of DInfo.yScrollIncrements. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static int Increment_AddY( TreeCtrl *tree, /* Widget info. */ int offset, /* Offset to add. */ int size /* Current size of DInfo.yScrollIncrements. */ ) { TreeDInfo dInfo = tree->dInfo; DScrollIncrements *dIncr = &dInfo->yScrollIncrements; int visHeight = Tree_ContentHeight(tree); while ((visHeight > 1) && (dIncr->count > 0) && (offset - dIncr->increments[dIncr->count - 1] > visHeight)) { size = Increment_AddY(tree, dIncr->increments[dIncr->count - 1] + visHeight, size); } #ifdef TREECTRL_DEBUG if ((dIncr->count > 0) && (offset == dIncr->increments[dIncr->count - 1])) { panic("Increment_AddY: offset %d same as previous offset", offset); } #endif if (dIncr->count + 1 > size) { size *= 2; dIncr->increments = (int *) ckrealloc( (char *) dIncr->increments, size * sizeof(int)); } dIncr->increments[dIncr->count++] = offset; return size; } /* *---------------------------------------------------------------------- * * RItemsToIncrementsX -- * * Recalculate the list of horizontal scroll increments. This gets * called when -orient=horizontal and -xscrollincrement=0. * * Results: * DInfo.xScrollIncrements is updated if the canvas width is > 0. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void RItemsToIncrementsX( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; DScrollIncrements *dIncr = &dInfo->xScrollIncrements; Range *range, *rangeFirst = dInfo->rangeFirst; RItem *rItem; int visWidth = Tree_ContentWidth(tree); int totalWidth = Tree_CanvasWidth(tree); int x1, increment, prev; int size; if (totalWidth <= 0) return; /* First increment is zero */ size = 10; dIncr->increments = (int *) ckalloc(size * sizeof(int)); dIncr->increments[dIncr->count++] = 0; prev = 0; if (rangeFirst == NULL) { /* Only the column headers are shown. */ } else if (rangeFirst->next == NULL) { /* A single horizontal range is easy. Add one increment for the * left edge of each item. */ rItem = rangeFirst->first; while (1) { increment = rangeFirst->offset.x + rItem->offset; if (increment > prev) { size = Increment_AddX(tree, increment, size); prev = increment; } if (rItem == rangeFirst->last) break; rItem++; } } else { x1 = 0; while (1) { int minLeft1 = totalWidth, minLeft2 = totalWidth; increment = totalWidth; /* Find the RItem whose left edge is >= x1 by the smallest * amount. */ for (range = rangeFirst; range != NULL; range = range->next) { if (x1 >= range->offset.x + range->totalWidth) continue; rItem = Range_ItemUnderPoint(tree, range, x1 - range->offset.x, -666, NULL, NULL, 3); if (range->offset.x + rItem->offset >= x1) increment = MIN(increment, range->offset.x + rItem->offset); if (range->offset.x + rItem->offset > x1) minLeft1 = MIN(minLeft1, range->offset.x + rItem->offset); if (rItem != range->last) { rItem += 1; if (range->offset.x + rItem->offset > x1) minLeft2 = MIN(minLeft2, range->offset.x + rItem->offset); } } if (increment == totalWidth) break; if (increment > prev) { size = Increment_AddX(tree, increment, size); prev = increment; } if (minLeft1 == totalWidth && minLeft2 == totalWidth) break; /* no increments > x1 */ if (minLeft1 != totalWidth && minLeft1 > increment) x1 = minLeft1; else x1 = minLeft2; } } if ((visWidth > 1) && (totalWidth - dIncr->increments[dIncr->count - 1] > visWidth)) { Increment_AddX(tree, totalWidth, size); dIncr->count--; dIncr->increments[dIncr->count - 1] = totalWidth - visWidth; } } /* *---------------------------------------------------------------------- * * RItemsToIncrementsY -- * * Recalculate the list of vertical scroll increments. This gets * called when -orient=vertical and -yscrollincrement=0. * * Results: * DInfo.yScrollIncrements is updated if the canvas height is > 0. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void RItemsToIncrementsY( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; DScrollIncrements *dIncr = &dInfo->yScrollIncrements; Range *range, *rangeFirst; RItem *rItem; int visHeight = Tree_ContentHeight(tree); int totalHeight = Tree_CanvasHeight(tree); int y1, increment, prev; int size; if (totalHeight <= 0) return; /* First increment is zero */ size = 10; dIncr->increments = (int *) ckalloc(size * sizeof(int)); dIncr->increments[dIncr->count++] = 0; prev = 0; /* If only locked columns are visible, we still scroll vertically. */ rangeFirst = dInfo->rangeFirst; if (rangeFirst == NULL) rangeFirst = dInfo->rangeLock; if (rangeFirst == NULL) { /* Only -canvaspady spacing, no items! */ } else if (rangeFirst->next == NULL) { /* A single vertical range is easy. Add one increment for the * top edge of each item. */ rItem = rangeFirst->first; while (1) { increment = rangeFirst->offset.y + rItem->offset; if (increment > prev) { size = Increment_AddY(tree, increment, size); prev = increment; } if (rItem == rangeFirst->last) break; rItem++; } } else { y1 = 0; while (1) { int minTop1 = totalHeight, minTop2 = totalHeight; increment = totalHeight; /* Find the RItem whose top edge is >= y1 by smallest amount. */ for (range = rangeFirst; range != NULL; range = range->next) { if (y1 >= range->totalHeight) continue; rItem = Range_ItemUnderPoint(tree, range, -666, y1 - range->offset.y, NULL, NULL, 3); if (range->offset.y + rItem->offset >= y1) increment = MIN(increment, range->offset.y + rItem->offset); if (range->offset.y + rItem->offset > y1) minTop1 = MIN(minTop1, range->offset.y + rItem->offset); if (rItem != range->last) { rItem += 1; if (range->offset.y + rItem->offset > y1) minTop2 = MIN(minTop2, range->offset.y + rItem->offset); } } if (increment == totalHeight) break; if (increment > prev) { size = Increment_AddY(tree, increment, size); prev = increment; } if (minTop1 == totalHeight && minTop2 == totalHeight) break; /* no increments > y1 */ if (minTop1 != totalHeight && minTop1 > increment) y1 = minTop1; else y1 = minTop2; } } if ((visHeight > 1) && (totalHeight - dIncr->increments[dIncr->count - 1] > visHeight)) { size = Increment_AddY(tree, totalHeight, size); dIncr->count--; dIncr->increments[dIncr->count - 1] = totalHeight - visHeight; } } /* *---------------------------------------------------------------------- * * RangesToIncrementsX -- * * Recalculate the list of horizontal scroll increments. This gets * called when -orient=vertical and -xscrollincrement=0. * * Results: * DInfo.xScrollIncrements is updated if there are any Ranges. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void RangesToIncrementsX( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; DScrollIncrements *dIncr = &dInfo->xScrollIncrements; Range *range = dInfo->rangeFirst; int visWidth = Tree_ContentWidth(tree); int totalWidth = Tree_CanvasWidth(tree); int size, prev; if (totalWidth <= 0) return; /* First increment is zero */ size = 10; dIncr->increments = (int *) ckalloc(size * sizeof(int)); dIncr->increments[dIncr->count++] = 0; prev = 0; while (range != NULL) { if (range->offset.x > prev) { size = Increment_AddX(tree, range->offset.x, size); prev = range->offset.x; } range = range->next; } if ((visWidth > 1) && (totalWidth - dIncr->increments[dIncr->count - 1] > visWidth)) { size = Increment_AddX(tree, totalWidth, size); dIncr->count--; dIncr->increments[dIncr->count - 1] = totalWidth - visWidth; } } /* *---------------------------------------------------------------------- * * RangesToIncrementsY -- * * Recalculate the list of vertical scroll increments. This gets * called when -orient=horizontal and -yscrollincrement=0. * * Results: * DInfo.yScrollIncrements is updated if there are any Ranges. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void RangesToIncrementsY( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; DScrollIncrements *dIncr = &dInfo->yScrollIncrements; Range *range = dInfo->rangeFirst; int visHeight = Tree_ContentHeight(tree); int totalHeight = Tree_CanvasHeight(tree); int size, prev; if (totalHeight <= 0) return; /* First increment is zero */ size = 10; dIncr->increments = (int *) ckalloc(size * sizeof(int)); dIncr->increments[dIncr->count++] = 0; prev = 0; while (range != NULL) { if (range->offset.y > prev) { size = Increment_AddY(tree, range->offset.y, size); prev = range->offset.y; } range = range->next; } if ((visHeight > 1) && (totalHeight - dIncr->increments[dIncr->count - 1] > visHeight)) { size = Increment_AddY(tree, totalHeight, size); dIncr->count--; dIncr->increments[dIncr->count - 1] = totalHeight - visHeight; } } /* *---------------------------------------------------------------------- * * Increment_Redo -- * * Recalculate the lists of scroll increments. * * Results: * DInfo.xScrollIncrements and DInfo.yScrollIncrements are updated. * Either may be set to NULL. The old values are freed, if any. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void Increment_Redo( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; DScrollIncrements *xIncr = &dInfo->xScrollIncrements; DScrollIncrements *yIncr = &dInfo->yScrollIncrements; /* Free x */ if (xIncr->increments != NULL) ckfree((char *) xIncr->increments); xIncr->increments = NULL; xIncr->count = 0; /* Free y */ if (yIncr->increments != NULL) ckfree((char *) yIncr->increments); yIncr->increments = NULL; yIncr->count = 0; if (tree->vertical) { /* No xScrollIncrement is given. Snap to left edge of a Range */ if (tree->xScrollIncrement <= 0) RangesToIncrementsX(tree); /* No yScrollIncrement is given. Snap to top edge of a TreeItem */ if (tree->yScrollIncrement <= 0) RItemsToIncrementsY(tree); } else { /* No xScrollIncrement is given. Snap to left edge of a TreeItem */ if (tree->xScrollIncrement <= 0) RItemsToIncrementsX(tree); /* No yScrollIncrement is given. Snap to top edge of a Range */ if (tree->yScrollIncrement <= 0) RangesToIncrementsY(tree); } } /* *---------------------------------------------------------------------- * * Increment_RedoIfNeeded -- * * Recalculate the lists of scroll increments if needed. * * Results: * DInfo.xScrollIncrements and DInfo.yScrollIncrements may be * updated. * * Side effects: * Memory may be allocated. The list of Ranges will be recalculated * if needed. * *---------------------------------------------------------------------- */ static void Increment_RedoIfNeeded( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; Range_RedoIfNeeded(tree); if (dInfo->flags & DINFO_REDO_INCREMENTS) { Increment_Redo(tree); dInfo->fakeCanvasWidth = dInfo->fakeCanvasHeight = -1; dInfo->flags &= ~DINFO_REDO_INCREMENTS; } } /* *---------------------------------------------------------------------- * * B_IncrementFind -- * * Search a list of increments and return one nearest to the * given offset. * * Results: * Index of the nearest increment <= the given offset. * Panic() if no appropriate offset if found. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int B_IncrementFind( int *increments, /* DInfo.x|yScrollIncrements. */ int count, /* Length of increments[]. */ int offset /* Offset to search for. */ ) { int i, l, u, v; if (offset < 0) offset = 0; /* Binary search */ l = 0; u = count - 1; while (l <= u) { i = (l + u) / 2; v = increments[i]; if ((offset >= v) && ((i == count - 1) || (offset < increments[i + 1]))) return i; if (offset < v) u = i - 1; else l = i + 1; } panic("B_IncrementFind failed (count %d offset %d)", count, offset); return -1; } /* *---------------------------------------------------------------------- * * B_IncrementFindX -- * * Search DInfo.xScrollIncrements and return one nearest to the * given offset. * * Results: * Index of the nearest increment <= the given offset. * Panic() if no appropriate offset if found. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int B_IncrementFindX( TreeCtrl *tree, /* Widget info. */ int offset /* Offset to search for. */ ) { TreeDInfo dInfo = tree->dInfo; DScrollIncrements *dIncr = &dInfo->xScrollIncrements; return B_IncrementFind( dIncr->increments, dIncr->count, offset); } /* *---------------------------------------------------------------------- * * B_IncrementFindY -- * * Search DInfo.yScrollIncrements and return one nearest to the * given offset. * * Results: * Index of the nearest increment <= the given offset. * Panic() if no appropriate offset if found. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int B_IncrementFindY( TreeCtrl *tree, /* Widget info. */ int offset /* Offset to search with. */ ) { TreeDInfo dInfo = tree->dInfo; DScrollIncrements *dIncr = &dInfo->yScrollIncrements; return B_IncrementFind( dIncr->increments, dIncr->count, offset); } /* *-------------------------------------------------------------- * * TreeXviewCmd -- * * This procedure is invoked to process the "xview" option for * the widget command for a TreeCtrl. See the user documentation * for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ int TreeXviewCmd( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tcl_Interp *interp = tree->interp; if (objc == 2) { double fractions[2]; Tcl_Obj *listObj; Tree_GetScrollFractionsX(tree, fractions); listObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(fractions[0])); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(fractions[1])); Tcl_SetObjResult(interp, listObj); } else { int count, index = 0, indexMax, offset, type; double fraction; int visWidth = Tree_ContentWidth(tree); int totWidth = Tree_CanvasWidth(tree); if (visWidth < 0) visWidth = 0; if (totWidth <= visWidth) return TCL_OK; type = Tk_GetScrollInfoObj(interp, objc, objv, &fraction, &count); Tree_SetScrollSmoothingX(tree, type != TK_SCROLL_UNITS); totWidth = Tree_FakeCanvasWidth(tree); if (visWidth > 1) { indexMax = Increment_FindX(tree, totWidth - visWidth); } else { indexMax = Increment_FindX(tree, totWidth); visWidth = 1; } switch (type) { case TK_SCROLL_ERROR: return TCL_ERROR; case TK_SCROLL_MOVETO: offset = (int) (fraction * totWidth + 0.5); index = Increment_FindX(tree, offset); break; case TK_SCROLL_PAGES: offset = W2Cx(Tree_ContentLeft(tree)); offset += (int) (count * visWidth * 0.9); index = Increment_FindX(tree, offset); if ((count > 0) && (index == Increment_FindX(tree, W2Cx(Tree_ContentLeft(tree))))) index++; break; case TK_SCROLL_UNITS: offset = W2Cx(Tree_ContentLeft(tree)); index = Increment_FindX(tree, offset); offset = Increment_ToOffsetX(tree, index); /* If the left-most increment is partially visible due to * non-unit scrolling, then scrolling by -1 units should * snap to the left of the partially-visible increment. */ if ((C2Wx(offset) < Tree_ContentLeft(tree)) && (count < 0)) index++; index += count; break; } /* Don't scroll too far left */ if (index < 0) index = 0; /* Don't scroll too far right */ if (index > indexMax) index = indexMax; offset = Increment_ToOffsetX(tree, index); if (tree->xOrigin != offset - Tree_ContentLeft(tree)) { tree->xOrigin = offset - Tree_ContentLeft(tree); Tree_EventuallyRedraw(tree); } } return TCL_OK; } /* *-------------------------------------------------------------- * * TreeYviewCmd -- * * This procedure is invoked to process the "yview" option for * the widget command for a TreeCtrl. See the user documentation * for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */ int TreeYviewCmd( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tcl_Interp *interp = tree->interp; if (objc == 2) { double fractions[2]; Tcl_Obj *listObj; Tree_GetScrollFractionsY(tree, fractions); listObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(fractions[0])); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(fractions[1])); Tcl_SetObjResult(interp, listObj); } else { int count, index = 0, indexMax, offset, type; double fraction; int visHeight = Tree_ContentHeight(tree); int totHeight = Tree_CanvasHeight(tree); if (visHeight < 0) visHeight = 0; if (totHeight <= visHeight) return TCL_OK; type = Tk_GetScrollInfoObj(interp, objc, objv, &fraction, &count); Tree_SetScrollSmoothingY(tree, type != TK_SCROLL_UNITS); totHeight = Tree_FakeCanvasHeight(tree); if (visHeight > 1) { indexMax = Increment_FindY(tree, totHeight - visHeight); } else { indexMax = Increment_FindY(tree, totHeight); visHeight = 1; } switch (type) { case TK_SCROLL_ERROR: return TCL_ERROR; case TK_SCROLL_MOVETO: offset = (int) (fraction * totHeight + 0.5); index = Increment_FindY(tree, offset); break; case TK_SCROLL_PAGES: offset = W2Cy(Tree_ContentTop(tree)); offset += (int) (count * visHeight * 0.9); index = Increment_FindY(tree, offset); if ((count > 0) && (index == Increment_FindY(tree, W2Cy(Tree_ContentTop(tree))))) index++; break; case TK_SCROLL_UNITS: offset = W2Cy(Tree_ContentTop(tree)); index = Increment_FindY(tree, offset); offset = Increment_ToOffsetY(tree, index); /* If the top-most increment is partially visible due to * non-unit scrolling, then scrolling by -1 units should * snap to the top of the partially-visible increment. */ if ((C2Wy(offset) < Tree_ContentTop(tree)) && (count < 0)) index++; index += count; break; } /* Don't scroll too far up */ if (index < 0) index = 0; /* Don't scroll too far down */ if (index > indexMax) index = indexMax; offset = Increment_ToOffsetY(tree, index); if (tree->yOrigin != offset - Tree_ContentTop(tree)) { tree->yOrigin = offset - Tree_ContentTop(tree); Tree_EventuallyRedraw(tree); } } return TCL_OK; } /* *-------------------------------------------------------------- * * Tree_ItemUnderPoint -- * * Return a TreeItem containing the given coordinates. * * Results: * TreeItem token or NULL if no item contains the point. * * Side effects: * The list of Ranges will be recalculated if needed. * *-------------------------------------------------------------- */ TreeItem Tree_ItemUnderPoint( TreeCtrl *tree, /* Widget info. */ int *x_, int *y_, /* In: window coordinates. * Out: coordinates relative to top-left * corner of the returned item. */ int *lock, /* Out: COLUMN_LOCK_XXX */ int nearest /* TRUE if the item nearest the coordinates * should be returned. */ ) { Range *range; RItem *rItem; int hit; hit = Tree_HitTest(tree, *x_, *y_); if (!nearest && ((hit == TREE_AREA_LEFT) || (hit == TREE_AREA_RIGHT))) { TreeDInfo dInfo = tree->dInfo; Range_RedoIfNeeded(tree); range = dInfo->rangeFirst; /* If range is NULL use dInfo->rangeLock. */ if (range == NULL) { if (dInfo->rangeLock == NULL) return NULL; range = dInfo->rangeLock; } if (W2Cy(*y_) < range->offset.y + range->totalHeight) { int x = *x_; int y = *y_; if (hit == TREE_AREA_RIGHT) { x -= Tree_ContentRight(tree); if (lock != NULL) (*lock) = COLUMN_LOCK_RIGHT; } else { x -= Tree_BorderLeft(tree); if (lock != NULL) (*lock) = COLUMN_LOCK_LEFT; } y = W2Cy(y) - range->offset.y; rItem = Range_ItemUnderPoint(tree, range, -666, y, NULL, &y, 0); if (rItem != NULL) { *x_ = x; *y_ = y; return rItem->item; } } return NULL; } if (lock != NULL) (*lock) = COLUMN_LOCK_NONE; range = Range_UnderPoint(tree, x_, y_, nearest); if (range == NULL) return NULL; rItem = Range_ItemUnderPoint(tree, range, *x_, *y_, x_, y_, nearest ? 1 : 0); if (rItem != NULL) return rItem->item; return NULL; } /* *-------------------------------------------------------------- * * Tree_AreaBbox -- * * Return the bounding box of a visible area. * * Results: * Return value is TRUE if the area is non-empty. * * Side effects: * Column and item layout will be updated if needed. * *-------------------------------------------------------------- */ int Tree_AreaBbox( TreeCtrl *tree, int area, TreeRectangle *tr ) { int x1 = 0, y1 = 0, x2 = 0, y2 = 0; switch (area) { case TREE_AREA_HEADER: x1 = Tree_HeaderLeft(tree); y1 = Tree_HeaderTop(tree); x2 = Tree_HeaderRight(tree); y2 = Tree_HeaderBottom(tree); break; case TREE_AREA_CONTENT: x1 = Tree_ContentLeft(tree); y1 = Tree_ContentTop(tree); x2 = Tree_ContentRight(tree); y2 = Tree_ContentBottom(tree); break; case TREE_AREA_LEFT: x1 = Tree_BorderLeft(tree); y1 = Tree_ContentTop(tree); x2 = Tree_ContentLeft(tree); y2 = Tree_ContentBottom(tree); /* Don't overlap right-locked columns. */ if (x2 > Tree_ContentRight(tree)) x2 = Tree_ContentRight(tree); break; case TREE_AREA_RIGHT: x1 = Tree_ContentRight(tree); y1 = Tree_ContentTop(tree); x2 = Tree_BorderRight(tree); y2 = Tree_ContentBottom(tree); break; case TREE_AREA_HEADER_NONE: x1 = Tree_ContentLeft(tree); y1 = Tree_HeaderTop(tree); x2 = Tree_ContentRight(tree); y2 = Tree_HeaderBottom(tree); break; case TREE_AREA_HEADER_LEFT: x1 = Tree_BorderLeft(tree); y1 = Tree_HeaderTop(tree); x2 = Tree_ContentLeft(tree); y2 = Tree_HeaderBottom(tree); /* Don't overlap right-locked columns. */ if (x2 > Tree_ContentRight(tree)) x2 = Tree_ContentRight(tree); break; case TREE_AREA_HEADER_RIGHT: x1 = Tree_ContentRight(tree); y1 = Tree_HeaderTop(tree); x2 = Tree_BorderRight(tree); y2 = Tree_HeaderBottom(tree); break; } if (x2 <= x1 || y2 <= y1) return FALSE; if (x1 < Tree_BorderLeft(tree)) x1 = Tree_BorderLeft(tree); if (x2 > Tree_BorderRight(tree)) x2 = Tree_BorderRight(tree); if (y1 < Tree_BorderTop(tree)) y1 = Tree_BorderTop(tree); if (y2 > Tree_BorderBottom(tree)) y2 = Tree_BorderBottom(tree); TreeRect_SetXYXY(*tr, x1, y1, x2, y2); return (x2 > x1) && (y2 > y1); } /* *-------------------------------------------------------------- * * Tree_HitTest -- * * Determine which are of the window contains the given point. * * Results: * Return value is one of the TREE_AREA_xxx constants. * * Side effects: * Column layout will be updated if needed. * *-------------------------------------------------------------- */ int Tree_HitTest( TreeCtrl *tree, int x, int y ) { if ((x < Tree_BorderLeft(tree)) || (x >= Tree_BorderRight(tree))) return TREE_AREA_NONE; if ((y < Tree_BorderTop(tree)) || (y >= Tree_BorderBottom(tree))) return TREE_AREA_NONE; if (y < Tree_HeaderBottom(tree)) { return TREE_AREA_HEADER; } /* Right-locked columns are drawn over the left. */ if (x >= Tree_ContentRight(tree)) { return TREE_AREA_RIGHT; } /* Left-locked columns are drawn over the non-locked. */ if (x < Tree_ContentLeft(tree)) { return TREE_AREA_LEFT; } if (Tree_ContentLeft(tree) >= Tree_ContentRight(tree)) { return TREE_AREA_NONE; } return TREE_AREA_CONTENT; } /* *-------------------------------------------------------------- * * Tree_ItemBbox -- * * Return the bounding box for an item. * * Results: * Return value is -1 if the item is not ReallyVisible() * or if there are no visible columns. The coordinates * are relative to the top-left corner of the canvas. * * Side effects: * Column layout will be updated if needed. * The list of Ranges will be recalculated if needed. * *-------------------------------------------------------------- */ int Tree_ItemBbox( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item whose bbox is needed. */ int lock, /* COLUMN_LOCK_xxx. */ TreeRectangle *tr /* Returned bbox. */ ) { Range *range; RItem *rItem; if (!TreeItem_ReallyVisible(tree, item)) return -1; /* Update columnCountVisXXX if needed */ (void) Tree_WidthOfColumns(tree); /* FIXME: update tree->xOrigin and tree->yOrigin also!!! */ if (TreeItem_GetHeader(tree, item) != NULL) { TreeItem walk = tree->headerItems; tr->y = W2Cy(Tree_BorderTop(tree)); while (walk != item) { tr->y += TreeItem_Height(tree, walk); walk = TreeItem_NextSiblingVisible(tree, walk); } tr->height = TreeItem_Height(tree, item); switch (lock) { case COLUMN_LOCK_LEFT: if (tree->columnCountVisLeft == 0) return -1; tr->x = W2Cx(Tree_BorderLeft(tree)); tr->width = Tree_WidthOfLeftColumns(tree); break; case COLUMN_LOCK_NONE: /* Unlike regular items, headers cover the width of the whole * canvas (or content width, whichever is greater) because * headers include the tail column. */ /* FIXME: what if the tail column has -visible=0 */ tr->x = 0; tr->width = tree->canvasPadX[PAD_TOP_LEFT] + Tree_WidthOfColumns(tree); if (tr->width < Tree_FakeCanvasWidth(tree)) { tr->width = Tree_FakeCanvasWidth(tree); } tr->width += tree->tailExtend; break; case COLUMN_LOCK_RIGHT: if (tree->columnCountVisRight == 0) return -1; tr->x = W2Cx(Tree_ContentRight(tree)); tr->width = Tree_WidthOfRightColumns(tree); break; } return 0; } Range_RedoIfNeeded(tree); rItem = (RItem *) TreeItem_GetRInfo(tree, item); range = rItem->range; switch (lock) { case COLUMN_LOCK_LEFT: if (tree->columnCountVisLeft == 0) return -1; TreeRect_SetXYWH(*tr, W2Cx(Tree_BorderLeft(tree)), range->offset.y + rItem->offset, Tree_WidthOfLeftColumns(tree), rItem->size); return 0; case COLUMN_LOCK_NONE: break; case COLUMN_LOCK_RIGHT: if (tree->columnCountVisRight == 0) return -1; TreeRect_SetXYWH(*tr, W2Cx(Tree_ContentRight(tree)), range->offset.y + rItem->offset, Tree_WidthOfRightColumns(tree), rItem->size); return 0; } if (tree->columnCountVis < 1) return -1; if (tree->vertical) { TreeRect_SetXYWH(*tr, range->offset.x, range->offset.y + rItem->offset, range->totalWidth, rItem->size); } else { TreeRect_SetXYWH(*tr, range->offset.x + rItem->offset, range->offset.y, rItem->size, range->totalHeight); } return 0; } /* *-------------------------------------------------------------- * * Tree_ItemLARB -- * * Return an adjacent item above, below, to the left or to the * right of the given item. * * Results: * An adjacent item or NULL if there is no such item. * * Side effects: * The list of Ranges will be recalculated if needed. * *-------------------------------------------------------------- */ TreeItem Tree_ItemLARB( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item to use as a reference. */ int vertical, /* TRUE if items are arranged * from top-to-bottom in each Range. */ int prev /* TRUE for above/left, * FALSE for below/right. */ ) { RItem *rItem; Range *range; if (!TreeItem_ReallyVisible(tree, item) || (tree->columnCountVis < 1)) return NULL; Range_RedoIfNeeded(tree); rItem = (RItem *) TreeItem_GetRInfo(tree, item); if (vertical) { if (prev) { if (rItem == rItem->range->first) return NULL; rItem--; } else { if (rItem == rItem->range->last) return NULL; rItem++; } return rItem->item; } else { range = prev ? rItem->range->prev : rItem->range->next; if (range == NULL) return NULL; /* Find item with same index */ if (range->last->index < rItem->index) return NULL; return (range->first + rItem->index)->item; } return NULL; } TreeItem Tree_ItemLeft( TreeCtrl *tree, TreeItem item) { return Tree_ItemLARB(tree, item, !tree->vertical, TRUE); } TreeItem Tree_ItemAbove( TreeCtrl *tree, TreeItem item) { return Tree_ItemLARB(tree, item, tree->vertical, TRUE); } TreeItem Tree_ItemRight( TreeCtrl *tree, TreeItem item) { return Tree_ItemLARB(tree, item, !tree->vertical, FALSE); } TreeItem Tree_ItemBelow( TreeCtrl *tree, TreeItem item) { return Tree_ItemLARB(tree, item, tree->vertical, FALSE); } /* *-------------------------------------------------------------- * * Tree_ItemFL -- * * Return the first or last item in the same row or column * as the given item. * * Results: * First/last item or NULL if there is no such item. * * Side effects: * The list of Ranges will be recalculated if needed. * *-------------------------------------------------------------- */ TreeItem Tree_ItemFL( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item to use as a reference. */ int vertical, /* TRUE if items are arranged * from top-to-bottom in each Range. */ int first /* TRUE for top/left, * FALSE for bottom/right. */ ) { TreeDInfo dInfo = tree->dInfo; RItem *rItem; Range *range; if (!TreeItem_ReallyVisible(tree, item) || (tree->columnCountVis < 1)) { return NULL; } Range_RedoIfNeeded(tree); rItem = (RItem *) TreeItem_GetRInfo(tree, item); if (vertical) { return (first ? rItem->range->first->item : rItem->range->last->item); } else { /* Find the first/last range */ range = first ? dInfo->rangeFirst : dInfo->rangeLast; /* Check next/prev range until happy */ while (1) { if (range == rItem->range) return item; if (range->last->index >= rItem->index) return (range->first + rItem->index)->item; range = first ? range->next : range->prev; } } return NULL; } TreeItem Tree_ItemTop( TreeCtrl *tree, TreeItem item) { return Tree_ItemFL(tree, item, tree->vertical, TRUE); } TreeItem Tree_ItemBottom( TreeCtrl *tree, TreeItem item) { return Tree_ItemFL(tree, item, tree->vertical, FALSE); } TreeItem Tree_ItemLeftMost( TreeCtrl *tree, TreeItem item) { return Tree_ItemFL(tree, item, !tree->vertical, TRUE); } TreeItem Tree_ItemRightMost( TreeCtrl *tree, TreeItem item) { return Tree_ItemFL(tree, item, !tree->vertical, FALSE); } /* *-------------------------------------------------------------- * * Tree_ItemToRNC -- * * Return the row and column for the given item. * * Results: * A standard Tcl result. * * Side effects: * The list of Ranges will be recalculated if needed. * *-------------------------------------------------------------- */ int Tree_ItemToRNC( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item to get row n' column of. */ int *row, int *col /* Returned row and column. */ ) { RItem *rItem; if (!TreeItem_ReallyVisible(tree, item) || (tree->columnCountVis < 1)) return TCL_ERROR; Range_RedoIfNeeded(tree); rItem = (RItem *) TreeItem_GetRInfo(tree, item); if (tree->vertical) { (*row) = rItem->index; (*col) = rItem->range->index; } else { (*row) = rItem->range->index; (*col) = rItem->index; } return TCL_OK; } /* *-------------------------------------------------------------- * * Tree_RNCToItem -- * * Return the item at a given row and column. * * Results: * Token for the item. Never returns NULL unless there are no * Ranges. * * Side effects: * The list of Ranges will be recalculated if needed. * *-------------------------------------------------------------- */ TreeItem Tree_RNCToItem( TreeCtrl *tree, /* Widget info. */ int row, int col /* Row and column. These values are * clipped to valid values. */ ) { TreeDInfo dInfo = tree->dInfo; Range *range; RItem *rItem; Range_RedoIfNeeded(tree); range = dInfo->rangeFirst; if (range == NULL) return NULL; if (row < 0) row = 0; if (col < 0) col = 0; if (tree->vertical) { if (col > dInfo->rangeLast->index) col = dInfo->rangeLast->index; while (range->index != col) range = range->next; rItem = range->last; if (row > rItem->index) row = rItem->index; return (range->first + row)->item; } else { if (row > dInfo->rangeLast->index) row = dInfo->rangeLast->index; while (range->index != row) range = range->next; rItem = range->last; if (col > rItem->index) col = rItem->index; return (range->first + col)->item; } return rItem->item; } /*=============*/ static void DisplayDelay(TreeCtrl *tree) { if (tree->debug.enable && tree->debug.display && tree->debug.displayDelay > 0) { #if !defined(WIN32) && !defined(MAC_OSX_TK) XSync(tree->display, False); #endif Tcl_Sleep(tree->debug.displayDelay); } } /* *-------------------------------------------------------------- * * DItem_Alloc -- * * Allocate and initialize a new DItem, and store a pointer to it * in the given item. * * Results: * Pointer to the DItem which may come from an existing pool of * unused DItems. * * Side effects: * Memory may be allocated. * *-------------------------------------------------------------- */ static DItem * DItem_Alloc( TreeCtrl *tree, /* Widget info. */ RItem *rItem /* Range info for the item. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItem; dItem = (DItem *) TreeItem_GetDInfo(tree, rItem->item); if (dItem != NULL) panic("tried to allocate duplicate DItem"); /* Pop unused DItem from stack */ if (dInfo->dItemFree != NULL) { dItem = dInfo->dItemFree; dInfo->dItemFree = dItem->next; /* No free DItems, alloc a new one */ } else { dItem = (DItem *) ckalloc(sizeof(DItem)); } memset(dItem, '\0', sizeof(DItem)); #ifdef TREECTRL_DEBUG strncpy(dItem->magic, "MAGC", 4); #endif dItem->item = rItem->item; dItem->area.flags = DITEM_DIRTY | DITEM_ALL_DIRTY; dItem->left.flags = DITEM_DIRTY | DITEM_ALL_DIRTY; dItem->right.flags = DITEM_DIRTY | DITEM_ALL_DIRTY; TreeItem_SetDInfo(tree, rItem->item, (TreeItemDInfo) dItem); return dItem; } /* *-------------------------------------------------------------- * * DItem_Unlink -- * * Remove a DItem from a linked list of DItems. * * Results: * Pointer to the given list of DItems. * * Side effects: * None. * *-------------------------------------------------------------- */ static DItem * DItem_Unlink( DItem *head, /* First in linked list. */ DItem *dItem /* DItem to remove from list. */ ) { DItem *prev; if (head == dItem) head = dItem->next; else { for (prev = head; prev->next != dItem; prev = prev->next) { /* nothing */ } prev->next = dItem->next; } dItem->next = NULL; return head; } /* *-------------------------------------------------------------- * * DItem_Free -- * * Add a DItem to the pool of unused DItems. If the DItem belongs * to a TreeItem the pointer to the DItem is set to NULL in that * TreeItem. * * Results: * Pointer to the next DItem. * * Side effects: * None. * *-------------------------------------------------------------- */ static DItem * DItem_Free( TreeCtrl *tree, /* Widget info. */ DItem *dItem /* DItem to free. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *next = dItem->next; #ifdef TREECTRL_DEBUG if (strncmp(dItem->magic, "MAGC", 4) != 0) panic("DItem_Free: dItem.magic != MAGC"); #endif if (dItem->item != NULL) { TreeItem_SetDInfo(tree, dItem->item, (TreeItemDInfo) NULL); dItem->item = NULL; } /* Push unused DItem on the stack */ dItem->next = dInfo->dItemFree; dInfo->dItemFree = dItem; return next; } /* *-------------------------------------------------------------- * * FreeDItems -- * * Add a list of DItems to the pool of unused DItems, * optionally removing the DItems from a linked list. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void FreeDItems( TreeCtrl *tree, /* Widget info. */ DItem **headPtr, /* Head of list to unlink from, or NULL. */ DItem *first, /* First DItem to free. */ DItem *last /* DItem after the last one to free. */ ) { DItem *prev; if (headPtr != NULL) { if ((*headPtr) == first) (*headPtr) = last; else { for (prev = (*headPtr); prev->next != first; prev = prev->next) { /* nothing */ } prev->next = last; } } while (first != last) first = DItem_Free(tree, first); } /* *-------------------------------------------------------------- * * Tree_ItemsInArea -- * * Return a list of items overlapping the given area. * * Results: * Initializes the given TreeItemList and appends any items * in the given area. * * Side effects: * The list of Ranges will be recalculated if needed. Memory may * be allocated. * *-------------------------------------------------------------- */ void Tree_ItemsInArea( TreeCtrl *tree, /* Widget info. */ TreeItemList *items, /* Uninitialized list. The caller must free * it with TreeItemList_Free. */ int minX, int minY, /* Left, top in canvas coordinates. */ int maxX, int maxY /* Right, bottom in canvas coordinates. * Points on the right/bottom edge are not * included in the area. */ ) { TreeDInfo dInfo = tree->dInfo; int rx, ry; Range *range; RItem *rItem; TreeItemList_Init(tree, items, 0); Range_RedoIfNeeded(tree); range = dInfo->rangeFirst; if (tree->vertical) { /* Find the first range which could be in the area horizontally */ while (range != NULL) { if ((range->offset.x < maxX) && (range->offset.x + range->totalWidth > minX)) { break; } range = range->next; } } else { /* Find the first range which could be in the area vertically */ while (range != NULL) { if ((range->offset.y < maxY) && (range->offset.y + range->totalHeight > minY)) { break; } range = range->next; } } if (range == NULL) return; while (range != NULL) { rx = range->offset.x; ry = range->offset.y; if ((rx + range->totalWidth > minX) && (ry + range->totalHeight > minY)) { rItem = Range_ItemUnderPoint(tree, range, minX - rx, minY - ry, NULL, NULL, 3); while (1) { if (tree->vertical) { if (ry + rItem->offset >= maxY) break; } else { if (rx + rItem->offset >= maxX) break; } TreeItemList_Append(items, rItem->item); if (rItem == range->last) break; rItem++; } } if (tree->vertical) { if (rx + range->totalWidth >= maxX) break; rx += range->totalWidth; } else { if (ry + range->totalHeight >= maxY) break; ry += range->totalHeight; } range = range->next; } } #define DCOLUMN #ifdef DCOLUMN /* *-------------------------------------------------------------- * * GetOnScreenColumnsForItem -- * * Determine which columns of an item are onscreen. * * Results: * Sets the column list. * * Side effects: * Memory may be allocated. * *-------------------------------------------------------------- */ static int GetOnScreenColumnsForItem( TreeCtrl *tree, /* Widget info. */ DItem *dItem, /* Display info for an item. */ TreeColumnList *columns /* Initialized list to append to. */ ) { TreeDInfo dInfo = tree->dInfo; if (TreeItem_GetHeader(tree, dItem->item) != NULL) { TreeRectangle bounds; if (Tree_AreaBbox(tree, TREE_AREA_HEADER_LEFT, &bounds)) { TreeItem_GetOnScreenColumns(tree, dItem->item, COLUMN_LOCK_LEFT, dItem->left.x, dItem->y, dItem->left.width, dItem->height, columns); } if (Tree_AreaBbox(tree, TREE_AREA_HEADER_NONE, &bounds)) { TreeItem_GetOnScreenColumns(tree, dItem->item, COLUMN_LOCK_NONE, dItem->area.x, dItem->y, dItem->area.width, dItem->height, columns); } if (Tree_AreaBbox(tree, TREE_AREA_HEADER_RIGHT, &bounds)) { TreeItem_GetOnScreenColumns(tree, dItem->item, COLUMN_LOCK_RIGHT, dItem->right.x, dItem->y, dItem->right.width, dItem->height, columns); } } else { if (!dInfo->emptyL) { TreeItem_GetOnScreenColumns(tree, dItem->item, COLUMN_LOCK_LEFT, dItem->left.x, dItem->y, dItem->left.width, dItem->height, columns); } if (!dInfo->empty && dInfo->rangeFirstD != NULL) { TreeItem_GetOnScreenColumns(tree, dItem->item, COLUMN_LOCK_NONE, dItem->area.x, dItem->y, dItem->area.width, dItem->height, columns); } if (!dInfo->emptyR) { TreeItem_GetOnScreenColumns(tree, dItem->item, COLUMN_LOCK_RIGHT, dItem->right.x, dItem->y, dItem->right.width, dItem->height, columns); } } return TreeColumnList_Count(columns); } /* *-------------------------------------------------------------- * * TrackOnScreenColumnsForItem -- * * Compares the list of onscreen columns for an item to the * list of previously-onscreen columns for the item. * * Results: * Hides window elements for columns that are no longer * onscreen. * * Side effects: * Memory may be allocated. * *-------------------------------------------------------------- */ static void TrackOnScreenColumnsForItem( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ Tcl_HashEntry *hPtr /* DInfo.itemVisHash entry. */ ) { TreeColumnList columns; TreeColumn column, *value; DItem *dItem; int i, j, count = 0, n = 0; Tcl_DString dString; TreeColumnList_Init(tree, &columns, 0); Tcl_DStringInit(&dString); /* dItem is NULL if the item just went offscreen. */ dItem = (DItem *) TreeItem_GetDInfo(tree, item); if (dItem != NULL) count = GetOnScreenColumnsForItem(tree, dItem, &columns); if (tree->debug.enable && tree->debug.span) DStringAppendf(&dString, "onscreen columns for %s %d:", TreeItem_GetHeader(tree, item) ? "header" : "item", TreeItem_GetID(tree, item)); /* value is NULL if the item just came onscreen. */ value = (TreeColumn *) Tcl_GetHashValue(hPtr); if (value == NULL) { value = (TreeColumn *) ckalloc(sizeof(TreeColumn) * (count + 1)); value[0] = NULL; } /* Track newly-visible columns */ for (i = 0; i < count; i++) { column = TreeColumnList_Nth(&columns, i); for (j = 0; value[j] != NULL; j++) { if (column == value[j]) break; } if (value[j] == NULL) { if (tree->debug.enable && tree->debug.span) { if (column == tree->columnTail) DStringAppendf(&dString, " +tail"); else DStringAppendf(&dString, " +%d", TreeColumn_GetID(column)); } n++; } } /* Track newly-hidden columns */ for (j = 0; value[j] != NULL; j++) { column = value[j]; for (i = 0; i < count; i++) { if (TreeColumnList_Nth(&columns, i) == column) break; } if (i == count) { TreeItemColumn itemColumn = TreeItem_FindColumn(tree, item, TreeColumn_Index(column)); if (itemColumn != NULL) { TreeStyle style = TreeItemColumn_GetStyle(tree, itemColumn); if (style != NULL) TreeStyle_OnScreen(tree, style, FALSE); } if (tree->debug.enable && tree->debug.span) { if (column == tree->columnTail) DStringAppendf(&dString, " -tail"); else DStringAppendf(&dString, " -%d", TreeColumn_GetID(column)); } n++; } } if (n && tree->debug.enable && tree->debug.span) dbwin("%s\n", Tcl_DStringValue(&dString)); /* Set the list of onscreen columns unless it is the same or the item * is hidden. */ if (n > 0 && dItem != NULL) { value = (TreeColumn *) ckrealloc((char *) value, sizeof(TreeColumn) * (count + 1)); memcpy(value, (TreeColumn *) columns.pointers, sizeof(TreeColumn) * count); value[count] = NULL; Tcl_SetHashValue(hPtr, (ClientData) value); } Tcl_DStringFree(&dString); TreeColumnList_Free(&columns); } #endif /* DCOLUMN */ /* *-------------------------------------------------------------- * * UpdateDInfoForRange -- * * Allocates or updates a DItem for every on-screen item in a Range. * If an item already has a DItem (because the item was previously * displayed), then the DItem may be marked dirty if there were * changes to the item's on-screen size or position. * * Results: * The return value is the possibly-updated dItemHead. * * Side effects: * Memory may be allocated. * *-------------------------------------------------------------- */ static DItem * UpdateDInfoForRange( TreeCtrl *tree, /* Widget info. */ DItem *dItemHead, /* Linked list of used DItems. */ Range *range, /* Range to update DItems for. */ RItem *rItem, /* First item in the Range we care about. */ int x, int y /* Left & top window coordinates of rItem. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItem; DItemArea *area; TreeItem item; int maxX, maxY; int index, indexVis; int bgImgWidth, bgImgHeight; if (tree->backgroundImage != NULL) { Tk_SizeOfImage(tree->backgroundImage, &bgImgWidth, &bgImgHeight); } maxX = Tree_ContentRight(tree); maxY = Tree_ContentBottom(tree); /* Top-to-bottom */ if (tree->vertical) { while (1) { item = rItem->item; /* Update item/style layout. This can be needed when using fixed * column widths. */ (void) TreeItem_Height(tree, item); TreeItem_ToIndex(tree, item, &index, &indexVis); switch (tree->backgroundMode) { #ifdef DEPRECATED case BG_MODE_INDEX: #endif case BG_MODE_ORDER: break; #ifdef DEPRECATED case BG_MODE_VISINDEX: #endif case BG_MODE_ORDERVIS: index = indexVis; break; case BG_MODE_COLUMN: index = range->index; break; case BG_MODE_ROW: index = rItem->index; break; } y = C2Wy(range->offset.y + rItem->offset); dItem = (DItem *) TreeItem_GetDInfo(tree, item); /* Re-use a previously allocated DItem */ if (dItem != NULL) { dItemHead = DItem_Unlink(dItemHead, dItem); area = &dItem->area; /* This item is already marked for total redraw */ if (area->flags & DITEM_ALL_DIRTY) ; /* nothing */ /* All display info is marked as invalid */ else if (dInfo->flags & DINFO_INVALIDATE) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; else if ((dItem->flags & DITEM_INVALIDATE_ON_SCROLL_X) && (x != dItem->oldX)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; else if ((dItem->flags & DITEM_INVALIDATE_ON_SCROLL_Y) && (y != dItem->oldY)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* The range may have changed size */ else if ((area->width != range->totalWidth) || (dItem->height != rItem->size)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* Items may have alternating background colors. */ else if ((tree->columnBgCnt > 1) && ((index % tree->columnBgCnt) != (dItem->index % tree->columnBgCnt))) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* We don't copy items horizontally to their new position, * except for horizontal scrolling which moves the whole * range */ else if (x - dItem->oldX != dInfo->xOrigin - tree->xOrigin) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* If we are displaying dotted lines and the item has moved * from odd-top to non-odd-top or vice versa, must redraw * the lines for this item. */ else if (tree->showLines && (tree->lineStyle == LINE_STYLE_DOT) && tree->columnTreeVis && (TreeColumn_Lock(tree->columnTree) == COLUMN_LOCK_NONE) && ((DW2Cy(dItem->oldY) & 1) != (W2Cy(y) & 1))) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* We can't copy the item to its new position unless it * has the same part of the background image behind it */ else if ((tree->backgroundImage != NULL) && (dInfo->xOrigin != tree->xOrigin) && !(tree->bgImageScroll & BGIMG_SCROLL_X)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; else if ((tree->backgroundImage != NULL) && (dInfo->yOrigin != tree->yOrigin) && !(tree->bgImageScroll & BGIMG_SCROLL_Y)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; else if ((tree->backgroundImage != NULL) && ((DW2Cy(dItem->oldY) % bgImgHeight) != (W2Cy(y) % bgImgHeight))) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; } /* Make a new DItem */ else { dItem = DItem_Alloc(tree, rItem); area = &dItem->area; } area->x = x; dItem->y = y; area->width = Range_TotalWidth(tree, range); dItem->height = rItem->size; dItem->range = range; dItem->index = index; dItem->spans = TreeItem_GetSpans(tree, dItem->item); /* Keep track of the maximum item size */ if (area->width > dInfo->itemWidth) dInfo->itemWidth = area->width; if (dItem->height > dInfo->itemHeight) dInfo->itemHeight = dItem->height; /* Linked list of DItems */ if (dInfo->dItem == NULL) dInfo->dItem = dItem; else dInfo->dItemLast->next = dItem; dInfo->dItemLast = dItem; if (rItem == range->last) break; rItem++; /* Stop when out of bounds */ if (dItem->y + dItem->height >= maxY) break; } } /* Left-to-right */ else { while (1) { item = rItem->item; /* Update item/style layout. This can be needed when using fixed * column widths. */ (void) TreeItem_Height(tree, item); TreeItem_ToIndex(tree, item, &index, &indexVis); switch (tree->backgroundMode) { #ifdef DEPRECATED case BG_MODE_INDEX: #endif case BG_MODE_ORDER: break; #ifdef DEPRECATED case BG_MODE_VISINDEX: #endif case BG_MODE_ORDERVIS: index = indexVis; break; case BG_MODE_COLUMN: index = rItem->index; break; case BG_MODE_ROW: index = range->index; break; } x = C2Wx(range->offset.x + rItem->offset); dItem = (DItem *) TreeItem_GetDInfo(tree, item); /* Re-use a previously allocated DItem */ if (dItem != NULL) { dItemHead = DItem_Unlink(dItemHead, dItem); area = &dItem->area; /* This item is already marked for total redraw */ if (area->flags & DITEM_ALL_DIRTY) ; /* nothing */ /* All display info is marked as invalid */ else if (dInfo->flags & DINFO_INVALIDATE) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; else if ((dItem->flags & DITEM_INVALIDATE_ON_SCROLL_X) && (x != dItem->oldX)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; else if ((dItem->flags & DITEM_INVALIDATE_ON_SCROLL_Y) && (y != dItem->oldY)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* The range may have changed size */ else if ((area->width != rItem->size) || (dItem->height != range->totalHeight)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* Items may have alternating background colors. */ else if ((tree->columnBgCnt > 1) && ((index % tree->columnBgCnt) != (dItem->index % tree->columnBgCnt))) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* We don't copy items vertically to their new position, * except for vertical scrolling which moves the whole range */ else if (y - dItem->oldY != dInfo->yOrigin - tree->yOrigin) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* If we are displaying dotted lines and the item has moved * from odd-top to non-odd-top or vice versa, must redraw * the lines for this item. */ else if (tree->showLines && (tree->lineStyle == LINE_STYLE_DOT) && tree->columnTreeVis && ((DW2Cy(dItem->oldY) & 1) != (W2Cy(y) & 1))) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* We can't copy the item to its new position unless it * has the same part of the background image behind it */ else if ((tree->backgroundImage != NULL) && (dInfo->xOrigin != tree->xOrigin) && !(tree->bgImageScroll & BGIMG_SCROLL_X)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; else if ((tree->backgroundImage != NULL) && (dInfo->yOrigin != tree->yOrigin) && !(tree->bgImageScroll & BGIMG_SCROLL_Y)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; else if ((tree->backgroundImage != NULL) && ((DW2Cx(dItem->oldX) % bgImgWidth) != (W2Cx(x) % bgImgWidth))) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; } /* Make a new DItem */ else { dItem = DItem_Alloc(tree, rItem); area = &dItem->area; } area->x = x; dItem->y = y; area->width = rItem->size; dItem->height = Range_TotalHeight(tree, range); dItem->range = range; dItem->index = index; dItem->spans = TreeItem_GetSpans(tree, dItem->item); /* Keep track of the maximum item size */ if (area->width > dInfo->itemWidth) dInfo->itemWidth = area->width; if (dItem->height > dInfo->itemHeight) dInfo->itemHeight = dItem->height; /* Linked list of DItems */ if (dInfo->dItem == NULL) dInfo->dItem = dItem; else dInfo->dItemLast->next = dItem; dInfo->dItemLast = dItem; if (rItem == range->last) break; rItem++; /* Stop when out of bounds */ if (area->x + area->width >= maxX) break; } } return dItemHead; } /* *-------------------------------------------------------------- * * Tree_UpdateDInfo -- * * At the finish of this procedure every on-screen item will have * a DItem associated with it and no off-screen item will have * a DItem. * * Results: * None. * * Side effects: * Memory may be allocated. * *-------------------------------------------------------------- */ static void Tree_UpdateDInfo( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItemHead = dInfo->dItem; int x, y, rx = 0, ry = 0, ix, iy, dx, dy; int minX, minY, maxX, maxY; Range *range; RItem *rItem; DItem *dItem; if (tree->debug.enable && tree->debug.display) dbwin("Tree_UpdateDInfo %s\n", Tk_PathName(tree->tkwin)); dInfo->dItem = dInfo->dItemLast = NULL; dInfo->rangeFirstD = dInfo->rangeLastD = NULL; dInfo->itemWidth = dInfo->itemHeight = 0; dInfo->empty = !Tree_AreaBbox(tree, TREE_AREA_CONTENT, &dInfo->bounds); dInfo->emptyL = !Tree_AreaBbox(tree, TREE_AREA_LEFT, &dInfo->boundsL); dInfo->emptyR = !Tree_AreaBbox(tree, TREE_AREA_RIGHT, &dInfo->boundsR); if (dInfo->empty) goto done; TreeRect_XYXY(dInfo->bounds, &minX, &minY, &maxX, &maxY); range = dInfo->rangeFirst; if (tree->vertical) { /* Find the first range which could be onscreen horizontally. * It may not be onscreen if it has less height than other ranges. */ while (range != NULL) { if ((range->offset.x < W2Cx(maxX)) && (range->offset.x + range->totalWidth > W2Cx(minX))) { rx = range->offset.x; ry = range->offset.y; break; } range = range->next; } } else { /* Find the first range which could be onscreen vertically. * It may not be onscreen if it has less width than other ranges. */ while (range != NULL) { if ((range->offset.y < W2Cy(maxY)) && (range->offset.y + range->totalHeight > W2Cy(minY))) { rx = range->offset.x; ry = range->offset.y; break; } range = range->next; } } while (range != NULL) { rx = range->offset.x; ry = range->offset.y; if (tree->vertical) { if (rx >= W2Cx(maxX)) break; } else { if (ry >= W2Cy(maxY)) break; } if ((rx + range->totalWidth > W2Cx(minX)) && (ry + range->totalHeight > W2Cy(minY))) { dx = MAX(W2Cx(minX) - rx, 0); dy = MAX(W2Cy(minY) - ry, 0); rItem = Range_ItemUnderPoint(tree, range, dx, dy, &ix, &iy, 3); /* Window coords of top-left of item */ x = C2Wx(rx) + dx - ix; y = C2Wy(ry) + dy - iy; dItemHead = UpdateDInfoForRange(tree, dItemHead, range, rItem, x, y); } /* Track this range even if it has no DItems, so whitespace is * erased */ if (dInfo->rangeFirstD == NULL) dInfo->rangeFirstD = range; dInfo->rangeLastD = range; range = range->next; } if (dInfo->dItemLast != NULL) dInfo->dItemLast->next = NULL; done: if (dInfo->dItem != NULL) goto skipLock; if (!tree->itemVisCount) goto skipLock; if (dInfo->emptyL && dInfo->emptyR) goto skipLock; range = dInfo->rangeFirst; if ((range != NULL) && !range->totalHeight) goto skipLock; { int y = W2Cy(Tree_ContentTop(tree)); int index, indexVis; /* If no non-locked columns are displayed, we have no Range and * must use dInfo->rangeLock. */ if (range == NULL) { range = dInfo->rangeLock; } /* Find the first item on-screen vertically. */ rItem = Range_ItemUnderPoint(tree, range, -666, y, NULL, &y, 3); y = C2Wy(range->offset.y + rItem->offset); while (1) { DItem *dItem = (DItem *) TreeItem_GetDInfo(tree, rItem->item); /* Re-use a previously allocated DItem */ if (dItem != NULL) { dItemHead = DItem_Unlink(dItemHead, dItem); } else { dItem = DItem_Alloc(tree, rItem); } TreeItem_ToIndex(tree, rItem->item, &index, &indexVis); switch (tree->backgroundMode) { #ifdef DEPRECATED case BG_MODE_INDEX: #endif case BG_MODE_ORDER: break; #ifdef DEPRECATED case BG_MODE_VISINDEX: #endif case BG_MODE_ORDERVIS: index = indexVis; break; case BG_MODE_COLUMN: index = range->index; break; case BG_MODE_ROW: index = rItem->index; break; } dItem->y = C2Wy(range->offset.y + rItem->offset); /* Canvas -> Window */ dItem->height = rItem->size; dItem->range = range; dItem->index = index; dItem->spans = TreeItem_GetSpans(tree, dItem->item); /* Keep track of the maximum item size */ if (dItem->height > dInfo->itemHeight) dInfo->itemHeight = dItem->height; /* Linked list of DItems */ if (dInfo->dItem == NULL) dInfo->dItem = dItem; else dInfo->dItemLast->next = dItem; dInfo->dItemLast = dItem; if (rItem == range->last) break; if (dItem->y + dItem->height >= Tree_ContentBottom(tree)) break; rItem++; } } skipLock: if (!dInfo->emptyL || !dInfo->emptyR) { int bgImgWidth, bgImgHeight; DItemArea *area; if (!dInfo->emptyL) { /* Keep track of the maximum item size */ if (dInfo->widthOfColumnsLeft > dInfo->itemWidth) dInfo->itemWidth = dInfo->widthOfColumnsLeft; } if (!dInfo->emptyR) { /* Keep track of the maximum item size */ if (dInfo->widthOfColumnsRight > dInfo->itemWidth) dInfo->itemWidth = dInfo->widthOfColumnsRight; } if (tree->backgroundImage != NULL) Tk_SizeOfImage(tree->backgroundImage, &bgImgWidth, &bgImgHeight); for (dItem = dInfo->dItem; dItem != NULL; dItem = dItem->next) { if (!dInfo->emptyL) { area = &dItem->left; area->x = Tree_BorderLeft(tree); area->width = dInfo->widthOfColumnsLeft; /* This item is already marked for total redraw */ if (area->flags & DITEM_ALL_DIRTY) { ; /* nothing */ /* All display info is marked as invalid */ } else if (dInfo->flags & DINFO_INVALIDATE) { area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* Items may have alternating background colors. */ } else if ((tree->columnBgCnt > 1) && ((dItem->oldIndex % tree->columnBgCnt) != (dItem->index % tree->columnBgCnt))) { area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* If we are displaying dotted lines and the item has moved * from odd-top to non-odd-top or vice versa, must redraw * the lines for this item. */ } else if (tree->showLines && (tree->lineStyle == LINE_STYLE_DOT) && tree->columnTreeVis && (TreeColumn_Lock(tree->columnTree) == COLUMN_LOCK_LEFT) && ((DW2Cy(dItem->oldY) & 1) != (W2Cy(dItem->y) & 1))) { area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* We can't copy the item to its new position unless it * has the same part of the background image behind it */ } else if ((tree->backgroundImage != NULL) && ((dInfo->xOrigin % bgImgWidth) != (tree->xOrigin % bgImgWidth))) { area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; } } if (!dInfo->emptyR) { area = &dItem->right; area->x = Tree_ContentRight(tree); area->width = dInfo->widthOfColumnsRight; /* This item is already marked for total redraw */ if (area->flags & DITEM_ALL_DIRTY) { ; /* nothing */ /* All display info is marked as invalid */ } else if (dInfo->flags & DINFO_INVALIDATE) { area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* Items may have alternating background colors. */ } else if ((tree->columnBgCnt > 1) && ((dItem->oldIndex % tree->columnBgCnt) != (dItem->index % tree->columnBgCnt))) { area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* If we are displaying dotted lines and the item has moved * from odd-top to non-odd-top or vice versa, must redraw * the lines for this item. */ } else if (tree->showLines && (tree->lineStyle == LINE_STYLE_DOT) && tree->columnTreeVis && (TreeColumn_Lock(tree->columnTree) == COLUMN_LOCK_RIGHT) && ((DW2Cy(dItem->oldY) & 1) != (W2Cy(dItem->y) & 1))) { area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* We can't copy the item to its new position unless it * has the same part of the background image behind it */ } else if ((tree->backgroundImage != NULL) && ((dInfo->xOrigin % bgImgWidth) != (tree->xOrigin % bgImgWidth))) { area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; } } } } while (dItemHead != NULL) dItemHead = DItem_Free(tree, dItemHead); dInfo->flags &= ~DINFO_INVALIDATE; } /* *-------------------------------------------------------------- * * InvalidateWhitespace -- * * Subtract a rectangular area from the current whitespace * region. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void InvalidateWhitespace( TreeCtrl *tree, /* Widget info. */ int x1, int y1, /* Window coords to invalidate. */ int x2, int y2) /* Window coords to invalidate. */ { TreeDInfo dInfo = tree->dInfo; if ((x1 < x2 && y1 < y2) && TkRectInRegion(dInfo->wsRgn, x1, y1, x2 - x1, y2 - y1)) { XRectangle rect; TkRegion rgn = Tree_GetRegion(tree); rect.x = x1; rect.y = y1; rect.width = x2 - x1; rect.height = y2 - y1; TkUnionRectWithRegion(&rect, rgn, rgn); TkSubtractRegion(dInfo->wsRgn, rgn, dInfo->wsRgn); Tree_FreeRegion(tree, rgn); } } /* *-------------------------------------------------------------- * * InvalidateDItemX -- * * Mark a horizontal span of a DItem as dirty (needing to be * redrawn). The caller must set the DITEM_DIRTY flag afterwards. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void InvalidateDItemX( DItem *dItem, /* Item to mark dirty. */ DItemArea *area, int itemX, /* x-coordinate of item. */ int dirtyX, /* Left edge of area to mark as dirty. */ int dirtyWidth /* Width of area to mark as dirty. */ ) { int x1, x2; if (dirtyX <= itemX) area->dirty[LEFT] = 0; else { x1 = dirtyX - itemX; if (!(area->flags & DITEM_DIRTY) || (x1 < area->dirty[LEFT])) area->dirty[LEFT] = x1; } if (dirtyX + dirtyWidth >= itemX + area->width) area->dirty[RIGHT] = area->width; else { x2 = dirtyX + dirtyWidth - itemX; if (!(area->flags & DITEM_DIRTY) || (x2 > area->dirty[RIGHT])) area->dirty[RIGHT] = x2; } } /* *-------------------------------------------------------------- * * InvalidateDItemY -- * * Mark a vertical span of a DItem as dirty (needing to be * redrawn). The caller must set the DITEM_DIRTY flag afterwards. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void InvalidateDItemY( DItem *dItem, /* Item to mark dirty. */ DItemArea *area, int itemY, /* y-coordinate of item. */ int dirtyY, /* Top edge of area to mark as dirty. */ int dirtyHeight /* Height of area to mark as dirty. */ ) { int y1, y2; if (dirtyY <= itemY) area->dirty[TOP] = 0; else { y1 = dirtyY - itemY; if (!(area->flags & DITEM_DIRTY) || (y1 < area->dirty[TOP])) area->dirty[TOP] = y1; } if (dirtyY + dirtyHeight >= itemY + dItem->height) area->dirty[BOTTOM] = dItem->height; else { y2 = dirtyY + dirtyHeight - itemY; if (!(area->flags & DITEM_DIRTY) || (y2 > area->dirty[BOTTOM])) area->dirty[BOTTOM] = y2; } } /* *-------------------------------------------------------------- * * Range_RedoIfNeeded -- * * Recalculate the list of Ranges if they are marked out-of-date. * Also calculate the height and width of the canvas based on the * list of Ranges. * * Results: * None. * * Side effects: * Memory may be allocated. * *-------------------------------------------------------------- */ static void Range_RedoIfNeeded( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; CheckPendingHeaderUpdate(tree); if (dInfo->flags & DINFO_REDO_RANGES) { dInfo->rangeFirstD = dInfo->rangeLastD = NULL; dInfo->flags |= DINFO_OUT_OF_DATE; Range_Redo(tree); dInfo->flags &= ~DINFO_REDO_RANGES; #ifdef COMPLEX_WHITESPACE if (ComplexWhitespace(tree)) { dInfo->flags |= DINFO_DRAW_WHITESPACE; } #endif #if COLUMNGRID == 1 if (GridLinesInWhiteSpace(tree)) { dInfo->flags |= DINFO_DRAW_WHITESPACE; } #endif /* Do this after clearing REDO_RANGES to prevent infinite loop */ tree->totalWidth = tree->totalHeight = -1; (void) Tree_CanvasWidth(tree); (void) Tree_CanvasHeight(tree); dInfo->flags |= DINFO_REDO_INCREMENTS; } } /* *-------------------------------------------------------------- * * DblBufWinDirty -- * * Add a rectangle to the dirty region of the "-doublebuffer window" * pixmap. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void DblBufWinDirty( TreeCtrl *tree, int x1, int y1, int x2, int y2 ) { TreeDInfo dInfo = tree->dInfo; XRectangle rect; /* Fix BUG ID: 3015429 */ if (x1 >= x2 || y1 >= y2) return; rect.x = x1; rect.y = y1; rect.width = x2 - x1; rect.height = y2 - y1; TkUnionRectWithRegion(&rect, dInfo->dirtyRgn, dInfo->dirtyRgn); } #if REDRAW_RGN == 1 static void AddRgnToRedrawRgn( TreeCtrl *tree, TkRegion rgn ) { TreeDInfo dInfo = tree->dInfo; Tree_UnionRegion(dInfo->redrawRgn, rgn, dInfo->redrawRgn); } static void AddRectToRedrawRgn( TreeCtrl *tree, int minX, int minY, int maxX, int maxY ) { TkRegion rgn = Tree_GetRegion(tree); TreeRectangle rect; rect.x = minX; rect.y = minY; rect.width = maxX - minX; rect.height = maxY - minY; Tree_SetRectRegion(rgn, &rect); AddRgnToRedrawRgn(tree, rgn); Tree_FreeRegion(tree, rgn); } #endif /* REDRAW_RGN */ /* *-------------------------------------------------------------- * * DItemAllDirty -- * * Determine if a DItem will be entirely redrawn in all columns. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static int DItemAllDirty( TreeCtrl *tree, DItem *dItem ) { if ((dItem->area.flags & DITEM_DRAWN) && !(dItem->area.flags & DITEM_ALL_DIRTY)) return 0; if ((dItem->left.flags & DITEM_DRAWN) && !(dItem->left.flags & DITEM_ALL_DIRTY)) return 0; if ((dItem->right.flags & DITEM_DRAWN) && !(dItem->right.flags & DITEM_ALL_DIRTY)) return 0; return 1; } /* *-------------------------------------------------------------- * * ScrollHeaders -- * * Scrolls the header area horizontally if needed. * * Results: * Pixels are copied in the TreeCtrl window or in the * offscreen pixmap (if double-buffering is used). * * Side effects: * None. * *-------------------------------------------------------------- */ static void ScrollHeaders( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; TreeRectangle bounds; DItem *dItem; TkRegion damageRgn; int minX, minY, maxX, maxY; int width, offset; int x; int dirtyMin, dirtyMax; if (dInfo->xOrigin == tree->xOrigin) return; if (!Tree_AreaBbox(tree, TREE_AREA_HEADER_NONE, &bounds)) return; TreeRect_XYXY(bounds, &minX, &minY, &maxX, &maxY); offset = dInfo->xOrigin - tree->xOrigin; /* Update oldX */ for (dItem = dInfo->dItemHeader; dItem != NULL; dItem = dItem->next) { dItem->oldX = dItem->area.x; } /* Simplify if a whole screen was scrolled. */ if (abs(offset) >= maxX - minX) { for (dItem = dInfo->dItemHeader; dItem != NULL; dItem = dItem->next) { dItem->area.flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; dItem->left.flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; dItem->right.flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; } return; } width = maxX - minX - abs(offset); /* Move pixels right */ if (offset > 0) { x = minX; dirtyMin = minX; dirtyMax = maxX - width; /* Move pixels left */ } else { x = maxX - width; dirtyMin = minX + width; dirtyMax = maxX; } if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { XCopyArea(tree->display, dInfo->pixmapW.drawable, dInfo->pixmapW.drawable, tree->copyGC, x, minY, width, maxY - minY, x + offset, minY); } else { damageRgn = Tree_GetRegion(tree); if (Tree_ScrollWindow(tree, dInfo->scrollGC, x, minY, width, maxY - minY, offset, 0, damageRgn)) { DisplayDelay(tree); Tree_InvalidateRegion(tree, damageRgn); } Tree_FreeRegion(tree, damageRgn); } Tree_InvalidateArea(tree, dirtyMin, minY, dirtyMax, maxY); } /* *-------------------------------------------------------------- * * ScrollVerticalComplex -- * * Perform scrolling by copying the pixels of items from the * previous display position to the current position. Any areas * of items copied over by the moved items are marked dirty. * This is called when -orient=vertical. * * Results: * The number of items whose pixels were copied. * * Side effects: * Pixels are copied in the TreeCtrl window or in the * offscreen pixmap (if double-buffering is used). * *-------------------------------------------------------------- */ static int ScrollVerticalComplex( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItem, *dItem2; Range *range; TkRegion damageRgn; int minX, minY, maxX, maxY; int oldX, oldY, width, height, offset; int y; int numCopy = 0; if (dInfo->empty && dInfo->emptyL && dInfo->emptyR) return 0; minX = Tree_BorderLeft(tree); minY = Tree_ContentTop(tree); maxX = Tree_BorderRight(tree); maxY = Tree_ContentBottom(tree); /* Try updating the display by copying items on the screen to their * new location */ for (dItem = dInfo->dItem; dItem != NULL; dItem = dItem->next) { /* Copy an item to its new location unless: * (a) item display info is invalid * (b) item is in same location as last draw */ if (DItemAllDirty(tree, dItem) || (dItem->oldY == dItem->y)) continue; numCopy++; range = dItem->range; /* This item was previously displayed so it only needs to be * copied to the new location. Copy all such items as one */ offset = dItem->y - dItem->oldY; height = dItem->height; for (dItem2 = dItem->next; dItem2 != NULL; dItem2 = dItem2->next) { if ((dItem2->range != range) || DItemAllDirty(tree, dItem2) || (dItem2->oldY + offset != dItem2->y)) break; numCopy++; height = dItem2->y + dItem2->height - dItem->y; } y = dItem->y; oldY = dItem->oldY; /* Don't copy part of the window border */ if (oldY < minY) { height -= minY - oldY; oldY = minY; } if (oldY + height > maxY) height = maxY - oldY; /* Don't copy over the window border */ if (oldY + offset < minY) { height -= minY - (oldY + offset); oldY += minY - (oldY + offset); } if (oldY + offset + height > maxY) height = maxY - (oldY + offset); if (!dInfo->emptyL || !dInfo->emptyR) { oldX = minX; width = maxX - minX; } else { oldX = dItem->oldX; width = dItem->area.width; } if (oldX < minX) { width -= minX - oldX; oldX = minX; } if (oldX + width > maxX) width = maxX - oldX; /* Update oldY of copied items */ while (1) { /* If an item was partially visible, invalidate the exposed area */ if ((dItem->oldY < minY) && (offset > 0)) { if (!dInfo->empty && dInfo->rangeFirstD != NULL) { InvalidateDItemX(dItem, &dItem->area, dItem->oldX, oldX, width); InvalidateDItemY(dItem, &dItem->area, dItem->oldY, dItem->oldY, minY - dItem->oldY); dItem->area.flags |= DITEM_DIRTY; } if (!dInfo->emptyL) { InvalidateDItemX(dItem, &dItem->left, dItem->left.x, oldX, width); InvalidateDItemY(dItem, &dItem->left, dItem->oldY, dItem->oldY, minY - dItem->oldY); dItem->left.flags |= DITEM_DIRTY; } if (!dInfo->emptyR) { InvalidateDItemX(dItem, &dItem->right, dItem->right.x, oldX, width); InvalidateDItemY(dItem, &dItem->right, dItem->oldY, dItem->oldY, minY - dItem->oldY); dItem->right.flags |= DITEM_DIRTY; } } if ((dItem->oldY + dItem->height > maxY) && (offset < 0)) { if (!dInfo->empty && dInfo->rangeFirstD != NULL) { InvalidateDItemX(dItem, &dItem->area, dItem->oldX, oldX, width); InvalidateDItemY(dItem, &dItem->area, dItem->oldY, maxY, maxY - dItem->oldY + dItem->height); dItem->area.flags |= DITEM_DIRTY; } if (!dInfo->emptyL) { InvalidateDItemX(dItem, &dItem->left, dItem->left.x, oldX, width); InvalidateDItemY(dItem, &dItem->left, dItem->oldY, maxY, maxY - dItem->oldY + dItem->height); dItem->left.flags |= DITEM_DIRTY; } if (!dInfo->emptyR) { InvalidateDItemX(dItem, &dItem->right, dItem->right.x, oldX, width); InvalidateDItemY(dItem, &dItem->right, dItem->oldY, maxY, maxY - dItem->oldY + dItem->height); dItem->right.flags |= DITEM_DIRTY; } } dItem->oldY = dItem->y; if (dItem->next == dItem2) break; dItem = dItem->next; } /* Invalidate parts of items being copied over */ for ( ; dItem2 != NULL; dItem2 = dItem2->next) { if (dItem2->range != range) break; if (!DItemAllDirty(tree, dItem2) && (dItem2->oldY + dItem2->height > y) && (dItem2->oldY < y + height)) { if (!dInfo->empty && dInfo->rangeFirstD != NULL) { InvalidateDItemX(dItem2, &dItem2->area, dItem2->oldX, oldX, width); InvalidateDItemY(dItem2, &dItem2->area, dItem2->oldY, y, height); dItem2->area.flags |= DITEM_DIRTY; } if (!dInfo->emptyL) { InvalidateDItemX(dItem2, &dItem2->left, dItem2->left.x, oldX, width); InvalidateDItemY(dItem2, &dItem2->left, dItem2->oldY, y, height); dItem2->left.flags |= DITEM_DIRTY; } if (!dInfo->emptyR) { InvalidateDItemX(dItem2, &dItem2->right, dItem2->right.x, oldX, width); InvalidateDItemY(dItem2, &dItem2->right, dItem2->oldY, y, height); dItem2->right.flags |= DITEM_DIRTY; } } } if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { int dirtyMin, dirtyMax; XCopyArea(tree->display, dInfo->pixmapW.drawable, dInfo->pixmapW.drawable, tree->copyGC, oldX, oldY, width, height, oldX, oldY + offset); if (offset < 0) { dirtyMin = oldY + offset + height; dirtyMax = oldY + height; } else { dirtyMin = oldY; dirtyMax = oldY + offset; } Tree_InvalidateArea(tree, oldX, dirtyMin, oldX + width, dirtyMax); DblBufWinDirty(tree, oldX, oldY + offset, oldX + width, oldY + offset + height); continue; } /* Copy */ damageRgn = Tree_GetRegion(tree); if (Tree_ScrollWindow(tree, dInfo->scrollGC, oldX, oldY, width, height, 0, offset, damageRgn)) { DisplayDelay(tree); Tree_InvalidateRegion(tree, damageRgn); } Tree_FreeRegion(tree, damageRgn); } return numCopy; } /* *-------------------------------------------------------------- * * ScrollHorizontalSimple -- * * Perform scrolling by shifting the pixels in the content * area of the list to the left or right. * This is called when -orient=vertical. * * Results: * None. * * Side effects: * Stuff is copied/scrolled in the TreeCtrl window or in the * offscreen pixmap (if double-buffering is used). * *-------------------------------------------------------------- */ static void ScrollHorizontalSimple( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItem; TkRegion damageRgn; int minX, minY, maxX, maxY; int width, offset; int x, y; int dirtyMin, dirtyMax; if (dInfo->xOrigin == tree->xOrigin) return; /* Only column headers are visible. */ if (dInfo->rangeFirst == NULL) return; if (dInfo->empty) return; TreeRect_XYXY(dInfo->bounds, &minX, &minY, &maxX, &maxY); /* Update oldX */ for (dItem = dInfo->dItem; dItem != NULL; dItem = dItem->next) { dItem->oldX = dItem->area.x; } offset = dInfo->xOrigin - tree->xOrigin; /* We only scroll the content, not the whitespace */ y = C2Wy(Tree_CanvasHeight(tree)); if (y < maxY) maxY = y; /* Simplify if a whole screen was scrolled. */ if (abs(offset) >= maxX - minX) { Tree_InvalidateArea(tree, minX, minY, maxX, maxY); return; } /* We only scroll the content, not the whitespace */ x = C2Wx(Tree_CanvasWidth(tree)); if (x < maxX) maxX = x; width = maxX - minX - abs(offset); /* Move pixels right */ if (offset > 0) { x = minX; dirtyMin = minX; dirtyMax = maxX - width; /* Move pixels left */ } else { x = maxX - width; dirtyMin = minX + width; dirtyMax = maxX; } if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { XCopyArea(tree->display, dInfo->pixmapW.drawable, dInfo->pixmapW.drawable, tree->copyGC, x, minY, width, maxY - minY, x + offset, minY); } else { damageRgn = Tree_GetRegion(tree); if (Tree_ScrollWindow(tree, dInfo->scrollGC, x, minY, width, maxY - minY, offset, 0, damageRgn)) { DisplayDelay(tree); Tree_InvalidateRegion(tree, damageRgn); } Tree_FreeRegion(tree, damageRgn); } Tree_InvalidateArea(tree, dirtyMin, minY, dirtyMax, maxY); /* Invalidate the part of the whitespace that the content was copied * over. */ { TkRegion rgn; rgn = Tree_GetRectRegion(tree, &dInfo->bounds); TkSubtractRegion(rgn, dInfo->wsRgn, rgn); Tree_OffsetRegion(rgn, offset, 0); TkSubtractRegion(dInfo->wsRgn, rgn, dInfo->wsRgn); Tree_FreeRegion(tree, rgn); } } /* *-------------------------------------------------------------- * * ScrollVerticalSimple -- * * Perform scrolling by shifting the pixels in the content area of * the list up or down. This is called when -orient=horizontal. * * Results: * None. * * Side effects: * Stuff is copied/scrolled in the TreeCtrl window or in the * offscreen pixmap (if double-buffering is used). * *-------------------------------------------------------------- */ static void ScrollVerticalSimple( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItem; TkRegion damageRgn; int minX, minY, maxX, maxY; int height, offset; int x, y; int dirtyMin, dirtyMax; if (dInfo->yOrigin == tree->yOrigin) return; /* Update oldY */ for (dItem = dInfo->dItem; dItem != NULL; dItem = dItem->next) { dItem->oldY = dItem->y; } if (dInfo->empty) return; TreeRect_XYXY(dInfo->bounds, &minX, &minY, &maxX, &maxY); offset = dInfo->yOrigin - tree->yOrigin; /* Scroll the items, not the whitespace to the right */ x = C2Wx(Tree_CanvasWidth(tree)); if (x < maxX) maxX = x; /* Simplify if a whole screen was scrolled. */ if (abs(offset) > maxY - minY) { Tree_InvalidateArea(tree, minX, minY, maxX, maxY); return; } height = maxY - minY - abs(offset); /* Move pixels down */ if (offset > 0) { y = minY; dirtyMin = minY; dirtyMax = maxY - height; /* Move pixels up */ } else { y = maxY - height; dirtyMin = minY + height; dirtyMax = maxY; } if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { XCopyArea(tree->display, dInfo->pixmapW.drawable, dInfo->pixmapW.drawable, tree->copyGC, minX, y, maxX - minX, height, minX, y + offset); } else { damageRgn = Tree_GetRegion(tree); if (Tree_ScrollWindow(tree, dInfo->scrollGC, minX, y, maxX - minX, height, 0, offset, damageRgn)) { DisplayDelay(tree); Tree_InvalidateRegion(tree, damageRgn); } Tree_FreeRegion(tree, damageRgn); } Tree_InvalidateArea(tree, minX, dirtyMin, maxX, dirtyMax); /* Invalidate the part of the whitespace that the content was copied * over. */ { TkRegion rgn; rgn = Tree_GetRectRegion(tree, &dInfo->bounds); TkSubtractRegion(rgn, dInfo->wsRgn, rgn); Tree_OffsetRegion(rgn, 0, offset); TkSubtractRegion(dInfo->wsRgn, rgn, dInfo->wsRgn); Tree_FreeRegion(tree, rgn); } } /* *-------------------------------------------------------------- * * ScrollHorizontalComplex -- * * Perform scrolling by copying the pixels of items from the * previous display position to the current position. Any areas * of items copied over by the moved items are marked dirty. * This is called when -orient=horizontal. * * Results: * The number of items whose pixels were copied. * * Side effects: * Pixels are copied in the TreeCtrl window or in the * offscreen pixmap (if double-buffering is used). * *-------------------------------------------------------------- */ static int ScrollHorizontalComplex( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItem, *dItem2; Range *range; TkRegion damageRgn; TreeRectangle tr; int minX, minY, maxX, maxY; int oldX, oldY, width, height, offset; int x; int numCopy = 0; if (!Tree_AreaBbox(tree, TREE_AREA_CONTENT, &tr)) return 0; TreeRect_XYXY(tr, &minX, &minY, &maxX, &maxY); /* Try updating the display by copying items on the screen to their * new location */ for (dItem = dInfo->dItem; dItem != NULL; dItem = dItem->next) { /* Copy an item to its new location unless: * (a) item display info is invalid * (b) item is in same location as last draw */ if ((dItem->area.flags & DITEM_ALL_DIRTY) || (dItem->oldX == dItem->area.x)) continue; numCopy++; range = dItem->range; /* This item was previously displayed so it only needs to be * copied to the new location. Copy all such items as one */ offset = dItem->area.x - dItem->oldX; width = dItem->area.width; for (dItem2 = dItem->next; dItem2 != NULL; dItem2 = dItem2->next) { if ((dItem2->range != range) || (dItem2->area.flags & DITEM_ALL_DIRTY) || (dItem2->oldX + offset != dItem2->area.x)) break; numCopy++; width = dItem2->area.x + dItem2->area.width - dItem->area.x; } x = dItem->area.x; oldX = dItem->oldX; /* Don't copy part of the window border */ if (oldX < minX) { width -= minX - oldX; oldX = minX; } if (oldX + width > maxX) width = maxX - oldX; /* Don't copy over the window border */ if (oldX + offset < minX) { width -= minX - (oldX + offset); oldX += minX - (oldX + offset); } if (oldX + offset + width > maxX) width = maxX - (oldX + offset); oldY = dItem->oldY; height = dItem->height; /* range->totalHeight */ if (oldY < minY) { height -= minY - oldY; oldY = minY; } if (oldY + height > maxY) height = maxY - oldY; /* Update oldX of copied items */ while (1) { /* If an item was partially visible, invalidate the exposed area */ if ((dItem->oldX < minX) && (offset > 0)) { InvalidateDItemX(dItem, &dItem->area, dItem->oldX, dItem->oldX, minX - dItem->oldX); InvalidateDItemY(dItem, &dItem->area, oldY, oldY, height); dItem->area.flags |= DITEM_DIRTY; } if ((dItem->oldX + dItem->area.width > maxX) && (offset < 0)) { InvalidateDItemX(dItem, &dItem->area, dItem->oldX, maxX, maxX - dItem->oldX + dItem->area.width); InvalidateDItemY(dItem, &dItem->area, oldY, oldY, height); dItem->area.flags |= DITEM_DIRTY; } dItem->oldX = dItem->area.x; if (dItem->next == dItem2) break; dItem = dItem->next; } /* Invalidate parts of items being copied over */ for ( ; dItem2 != NULL; dItem2 = dItem2->next) { if (dItem2->range != range) break; if (!(dItem2->area.flags & DITEM_ALL_DIRTY) && (dItem2->oldX + dItem2->area.width > x) && (dItem2->oldX < x + width)) { InvalidateDItemX(dItem2, &dItem2->area, dItem2->oldX, x, width); InvalidateDItemY(dItem2, &dItem2->area, oldY, oldY, height); dItem2->area.flags |= DITEM_DIRTY; } } if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { int dirtyMin, dirtyMax; XCopyArea(tree->display, dInfo->pixmapW.drawable, dInfo->pixmapW.drawable, tree->copyGC, oldX, oldY, width, height, oldX + offset, oldY); if (offset < 0) { dirtyMin = oldX + offset + width; dirtyMax = oldX + width; } else { dirtyMin = oldX; dirtyMax = oldX + offset; } Tree_InvalidateArea(tree, dirtyMin, oldY, dirtyMax, oldY + height); DblBufWinDirty(tree, oldX + offset, oldY, oldX + offset + width, oldY + height); continue; } /* Copy */ damageRgn = Tree_GetRegion(tree); if (Tree_ScrollWindow(tree, dInfo->scrollGC, oldX, oldY, width, height, offset, 0, damageRgn)) { DisplayDelay(tree); Tree_InvalidateRegion(tree, damageRgn); } Tree_FreeRegion(tree, damageRgn); } return numCopy; } /* *---------------------------------------------------------------------- * * Proxy_IsXOR -- * * Return true if the column/row proxies should be drawn with XOR. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Proxy_IsXOR(void) { #if defined(WIN32) return FALSE; /* TRUE on XP, FALSE on Win7 (lots of flickering) */ #elif defined(MAC_OSX_TK) return FALSE; /* Cocoa doesn't have XOR */ #else return TRUE; /* X11 */ #endif } /* *-------------------------------------------------------------- * * Proxy_DrawXOR -- * * Draw (or erase) the visual indicator used when the user is * resizing a column or row (and -columnresizemode is "proxy"). * * Results: * None. * * Side effects: * Stuff is drawn in the TreeCtrl window (or erased, since this * is XOR drawing). * *-------------------------------------------------------------- */ static void Proxy_DrawXOR( TreeCtrl *tree, /* Widget info. */ int x1, /* Vertical or horizontal line window coords. */ int y1, int x2, int y2 ) { XGCValues gcValues; unsigned long gcMask; GC gc; #if defined(MAC_OSX_TK) gcValues.function = GXcopy; #else gcValues.function = GXinvert; #endif gcValues.graphics_exposures = False; gcMask = GCFunction | GCGraphicsExposures; gc = Tree_GetGC(tree, gcMask, &gcValues); #if defined(WIN32) /* GXinvert doesn't work with XFillRectangle() on Win32 */ XDrawLine(tree->display, Tk_WindowId(tree->tkwin), gc, x1, y1, x2, y2); #else XFillRectangle(tree->display, Tk_WindowId(tree->tkwin), gc, x1, y1, MAX(x2 - x1, 1), MAX(y2 - y1, 1)); #endif } /* *-------------------------------------------------------------- * * TreeColumnProxy_Display -- * * Display the visual indicator used when the user is * resizing a column (if it isn't displayed and should be * displayed). * * Results: * None. * * Side effects: * Stuff is drawn in the TreeCtrl window. * *-------------------------------------------------------------- */ void TreeColumnProxy_Display( TreeCtrl *tree /* Widget info. */ ) { if (!tree->columnProxy.onScreen && (tree->columnProxy.xObj != NULL)) { tree->columnProxy.sx = tree->columnProxy.x; if (Proxy_IsXOR()) { Proxy_DrawXOR(tree, tree->columnProxy.x, Tree_BorderTop(tree), tree->columnProxy.x, Tree_BorderBottom(tree)); } else { Tree_EventuallyRedraw(tree); } tree->columnProxy.onScreen = TRUE; } } /* *-------------------------------------------------------------- * * TreeColumnProxy_Undisplay -- * * Hide the visual indicator used when the user is * resizing a column (if it is displayed). * * Results: * None. * * Side effects: * Stuff is erased in the TreeCtrl window. * *-------------------------------------------------------------- */ void TreeColumnProxy_Undisplay( TreeCtrl *tree /* Widget info. */ ) { if (tree->columnProxy.onScreen) { if (Proxy_IsXOR()) { Proxy_DrawXOR(tree, tree->columnProxy.sx, Tree_BorderTop(tree), tree->columnProxy.sx, Tree_BorderBottom(tree)); } else { Tree_EventuallyRedraw(tree); } tree->columnProxy.onScreen = FALSE; } } /* *-------------------------------------------------------------- * * TreeRowProxy_Display -- * * Display the visual indicator used when the user is * resizing a row (if it isn't displayed and should be * displayed). * * Results: * None. * * Side effects: * Stuff is drawn in the TreeCtrl window. * *-------------------------------------------------------------- */ void TreeRowProxy_Display( TreeCtrl *tree /* Widget info. */ ) { if (!tree->rowProxy.onScreen && (tree->rowProxy.yObj != NULL)) { tree->rowProxy.sy = tree->rowProxy.y; if (Proxy_IsXOR()) { Proxy_DrawXOR(tree, Tree_BorderLeft(tree), tree->rowProxy.y, Tree_BorderRight(tree), tree->rowProxy.y); } else { Tree_EventuallyRedraw(tree); } tree->rowProxy.onScreen = TRUE; } } /* *-------------------------------------------------------------- * * TreeRowProxy_Undisplay -- * * Hide the visual indicator used when the user is * resizing a row (if it is displayed). * * Results: * None. * * Side effects: * Stuff is erased in the TreeCtrl window. * *-------------------------------------------------------------- */ void TreeRowProxy_Undisplay( TreeCtrl *tree /* Widget info. */ ) { if (tree->rowProxy.onScreen) { if (Proxy_IsXOR()) { Proxy_DrawXOR(tree, Tree_BorderLeft(tree), tree->rowProxy.sy, Tree_BorderRight(tree), tree->rowProxy.sy); } else { Tree_EventuallyRedraw(tree); } tree->rowProxy.onScreen = FALSE; } } /* *-------------------------------------------------------------- * * Proxy_Draw -- * * Draw the non-XOR -columnproxy or -rowproxy indicator. * * Results: * None. * * Side effects: * Stuff is drawn into a drawable. * *-------------------------------------------------------------- */ static void Proxy_Draw( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ int x1, /* Vertical or horizontal line window coords. */ int y1, int x2, int y2 ) { XGCValues gcValues; unsigned long gcMask; GC gc; gcValues.function = GXcopy; gcValues.graphics_exposures = False; gcMask = GCFunction | GCGraphicsExposures; gc = Tree_GetGC(tree, gcMask, &gcValues); XDrawLine(tree->display, td.drawable, gc, x1, y1, x2, y2); } /* *-------------------------------------------------------------- * * TreeColumnProxy_Draw -- * * Draw the non-XOR -columnproxy indicator if it is visible. * * Results: * None. * * Side effects: * Stuff is drawn into a drawable. * *-------------------------------------------------------------- */ static void TreeColumnProxy_Draw( TreeCtrl *tree, /* Widget info. */ TreeDrawable td /* Where to draw. */ ) { if (tree->columnProxy.xObj == NULL) return; Proxy_Draw(tree, td, tree->columnProxy.x, Tree_BorderTop(tree), tree->columnProxy.x, Tree_BorderBottom(tree)); } /* *-------------------------------------------------------------- * * TreeRowProxy_Draw -- * * Draw the non-XOR -rowproxy indicator if it is visible. * * Results: * None. * * Side effects: * Stuff is drawn into a drawable. * *-------------------------------------------------------------- */ static void TreeRowProxy_Draw( TreeCtrl *tree, /* Widget info. */ TreeDrawable td /* Where to draw. */ ) { if (tree->rowProxy.yObj == NULL) return; Proxy_Draw(tree, td, Tree_BorderLeft(tree), tree->rowProxy.y, Tree_BorderRight(tree), tree->rowProxy.y); } /* *-------------------------------------------------------------- * * CalcWhiteSpaceRegion -- * * Create a new region containing all the whitespace of the list * The whitespace is the area inside the borders/header where items * are not displayed. * * Results: * The new whitespace region, which may be empty. * * Side effects: * A new region is allocated. * *-------------------------------------------------------------- */ static TkRegion CalcWhiteSpaceRegion( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; int minX, minY, maxX, maxY; int left, right, top, bottom; TkRegion wsRgn; TkRegion itemRgn; XRectangle rect; Range *range; wsRgn = Tree_GetRegion(tree); /* Start with a region as big as the window minus borders + headers */ minX = Tree_BorderLeft(tree); minY = Tree_HeaderBottom(tree); maxX = Tree_BorderRight(tree); maxY = Tree_BorderBottom(tree); /* Nothing is visible? Return empty region. */ if (minX >= maxX || minY >= maxY) return wsRgn; rect.x = minX; rect.y = minY; rect.width = maxX - minX; rect.height = maxY - minY; TkUnionRectWithRegion(&rect, wsRgn, wsRgn); itemRgn = Tree_GetRegion(tree); if (tree->itemGapX > 0 || tree->itemGapY > 0) { TreeRectangle boundsRect, boundsRectL, boundsRectR; DItem *dItem = dInfo->dItem; boundsRect = dInfo->bounds; boundsRectL = dInfo->boundsL; boundsRectR = dInfo->boundsR; while (dItem != NULL) { TreeRectangle tr; if (!dInfo->emptyL) { tr.x = dItem->left.x; tr.y = dItem->y; tr.width = dItem->left.width; tr.height = dItem->height; TreeRect_Intersect(&tr, &tr, &boundsRectL); TreeRect_ToXRect(tr, &rect); TkUnionRectWithRegion(&rect, itemRgn, itemRgn); } if (!dInfo->emptyR) { tr.x = dItem->right.x; tr.y = dItem->y; tr.width = dItem->right.width; tr.height = dItem->height; TreeRect_Intersect(&tr, &tr, &boundsRectR); TreeRect_ToXRect(tr, &rect); TkUnionRectWithRegion(&rect, itemRgn, itemRgn); } if (!dInfo->empty) { tr.x = dItem->area.x; tr.y = dItem->y; tr.width = dItem->area.width; tr.height = dItem->height; TreeRect_Intersect(&tr, &tr, &boundsRect); TreeRect_ToXRect(tr, &rect); TkUnionRectWithRegion(&rect, itemRgn, itemRgn); } dItem = dItem->next; } TkSubtractRegion(wsRgn, itemRgn, wsRgn); Tree_FreeRegion(tree, itemRgn); return wsRgn; } /* Subtract area covered by items in left columns */ if (!dInfo->emptyL) { int pad1 = tree->canvasPadY[PAD_TOP_LEFT]; int pad2 = tree->canvasPadY[PAD_BOTTOM_RIGHT]; TreeRect_XYXY(dInfo->boundsL, &minX, &minY, &maxX, &maxY); left = minX; top = MAX(C2Wy(pad1), minY); right = maxX; bottom = MIN(C2Wy(Tree_CanvasHeight(tree) - pad2), maxY); if (top < bottom) { rect.x = left; rect.y = top; rect.width = right - left; rect.height = bottom - top; TkUnionRectWithRegion(&rect, itemRgn, itemRgn); } } /* Subtract area covered by items in right columns */ if (!dInfo->emptyR) { int pad1 = tree->canvasPadY[PAD_TOP_LEFT]; int pad2 = tree->canvasPadY[PAD_BOTTOM_RIGHT]; TreeRect_XYXY(dInfo->boundsR, &minX, &minY, &maxX, &maxY); left = minX; top = MAX(C2Wy(pad1), minY); right = maxX; bottom = MIN(C2Wy(Tree_CanvasHeight(tree) - pad2), maxY); if (top < bottom) { rect.x = left; rect.y = top; rect.width = right - left; rect.height = bottom - top; TkUnionRectWithRegion(&rect, itemRgn, itemRgn); } } /* Subtract area covered by items in unlocked columns */ if (!dInfo->empty) { TreeRect_XYXY(dInfo->bounds, &minX, &minY, &maxX, &maxY); for (range = dInfo->rangeFirstD; range != NULL; range = range->next) { left = MAX(C2Wx(range->offset.x), minX); top = MAX(C2Wy(range->offset.y), minY); right = MIN(C2Wx(range->offset.x + range->totalWidth), maxX); bottom = MIN(C2Wy(range->offset.y + range->totalHeight), maxY); if (left < right && top < bottom) { rect.x = left; rect.y = top; rect.width = right - left; rect.height = bottom - top; TkUnionRectWithRegion(&rect, itemRgn, itemRgn); } if (range == dInfo->rangeLastD) break; } } TkSubtractRegion(wsRgn, itemRgn, wsRgn); Tree_FreeRegion(tree, itemRgn); return wsRgn; } #ifdef COMPLEX_WHITESPACE /* *-------------------------------------------------------------- * * TreeRect_Intersect -- * * Determine the area of overlap between two rectangles. * * Results: * If the rectangles have non-zero size and overlap, resultPtr * holds the area of overlap, and the return value is 1. * Otherwise 0 is returned and resultPtr is untouched. * * Side effects: * None. * *-------------------------------------------------------------- */ int TreeRect_Intersect( TreeRectangle *resultPtr, /* Out: area of overlap. May be the same * as r1 or r2. */ CONST TreeRectangle *r1, /* First rectangle. */ CONST TreeRectangle *r2 /* Second rectangle. */ ) { TreeRectangle result; if (r1->width == 0 || r1->height == 0) return 0; if (r2->width == 0 || r2->height == 0) return 0; if (r1->x >= r2->x + r2->width) return 0; if (r2->x >= r1->x + r1->width) return 0; if (r1->y >= r2->y + r2->height) return 0; if (r2->y >= r1->y + r1->height) return 0; result.x = MAX(r1->x, r2->x); result.width = MIN(r1->x + r1->width, r2->x + r2->width) - result.x; result.y = MAX(r1->y, r2->y); result.height = MIN(r1->y + r1->height, r2->y + r2->height) - result.y; *resultPtr = result; return 1; } /* *-------------------------------------------------------------- * * GetItemBgIndex -- * * Determine the index used to pick an -itembackground color * for a displayed item. * This is only valid for tree->vertical=1. * * Results: * Integer index. * * Side effects: * None. * *-------------------------------------------------------------- */ static int GetItemBgIndex( TreeCtrl *tree, /* Widget info. */ RItem *rItem /* Range info for an item. */ ) { Range *range = rItem->range; int index, indexVis; TreeItem_ToIndex(tree, rItem->item, &index, &indexVis); switch (tree->backgroundMode) { #ifdef DEPRECATED case BG_MODE_INDEX: #endif case BG_MODE_ORDER: break; #ifdef DEPRECATED case BG_MODE_VISINDEX: #endif case BG_MODE_ORDERVIS: index = indexVis; break; case BG_MODE_COLUMN: index = range->index; break; case BG_MODE_ROW: index = rItem->index; break; } return index; } #ifdef ITEMBG_ABOVE /* *-------------------------------------------------------------- * * DrawColumnBackgroundReverse -- * * Draws rows of -itembackground colors in a column in the * whitespace region. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void DrawColumnBackgroundReverse( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeColumn treeColumn, /* Column to get background colors from. */ TkRegion dirtyRgn, /* Area that needs painting. Will be * inside 'bounds' and inside borders. */ TreeRectangle *bounds, /* Window coords of column to paint. */ RItem *rItem, /* Item(s) to get row heights from when drawing * in the tail column, otherwise NULL. */ int height, /* Height of each row below actual items. */ int index /* Used for alternating background colors. */ ) { #if 0 /* REMOVED BECAUSE OF GRADIENTS */ int bgCount = TreeColumn_BackgroundCount(treeColumn); #endif GC gc = None, backgroundGC; TreeRectangle dirtyBox, drawBox, rowBox; int top, bottom; TreeColor *tc; Tree_GetRegionBounds(dirtyRgn, &dirtyBox); if (!dirtyBox.width || !dirtyBox.height) return; backgroundGC = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC); #if 0 /* REMOVED BECAUSE OF GRADIENTS */ /* If the column has zero -itembackground colors, paint with the * treectrl's -background color. If a single -itembackground color * is specified, then paint with it. */ if (bgCount < 2) { if (bgCount == 1) gc = TreeColumn_BackgroundGC(treeColumn, 0); if (gc == None) gc = backgroundGC; Tree_FillRegion(tree->display, drawable, gc, dirtyRgn); return; } #endif #if 0 /* If -itembackground colors are transparent, we must draw the tree background * color first then the -itembackground colors. This results in flickering * when drawing directly to the toplevel. */ if (tree->doubleBuffer == DOUBLE_BUFFER_ITEM) { tpixmap.width = drawBox.width tpixmap.drawable = DisplayGetPixmap(tree, &dInfo->pixmapI, tpixmap.width, tpixmap.height); } #endif top = dirtyBox.y; bottom = bounds->y + bounds->height; while (top < bottom) { /* Can't use clipping regions with XFillRectangle * because the clip region is ignored on Win32. */ rowBox.x = bounds->x; rowBox.width = bounds->width; rowBox.height = rItem ? rItem->size : height; rowBox.y = bottom - rowBox.height; if (TreeRect_Intersect(&drawBox, &rowBox, &dirtyBox)) { if (rItem != NULL) { index = GetItemBgIndex(tree, rItem); } tc = TreeColumn_BackgroundColor(treeColumn, index); if (tc == NULL) { gc = backgroundGC; XFillRectangle(tree->display, td.drawable, gc, drawBox.x, drawBox.y, drawBox.width, drawBox.height); } else { if (!TreeColor_IsOpaque(tree ,tc)) { XFillRectangle(tree->display, td.drawable, backgroundGC, drawBox.x, drawBox.y, drawBox.width, drawBox.height); } TreeColor_FillRect(tree, td, NULL, tc, rowBox, drawBox); } } if (rItem != NULL && rItem == rItem->range->last) { index = GetItemBgIndex(tree, rItem); rItem = NULL; } if (rItem != NULL) { rItem++; } index++; /* FIXME: -- */ bottom -= rowBox.height; } } /* *-------------------------------------------------------------- * * DrawWhitespaceAboveItem -- * * Draws rows of -itembackground colors in each column in the * whitespace region. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void DrawWhitespaceAboveItem( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ int lock, /* Which columns to draw. */ int bounds[4], /* TREE_AREA_xxx bounds. */ int left, /* Window coord of first column's left edge. */ int bottom, /* Window coord just above the first item. */ TkRegion dirtyRgn, /* Area of whitespace that needs painting. */ TkRegion columnRgn, /* Existing region to set and use. */ int height, /* Height of each row. */ int index /* Used for alternating background colors. */ ) { int i = 0, width; TreeColumn treeColumn = NULL; TreeRectangle boundsBox, columnBox, visBox; switch (lock) { case COLUMN_LOCK_LEFT: treeColumn = tree->columnLockLeft; break; case COLUMN_LOCK_NONE: treeColumn = tree->columnLockNone; break; case COLUMN_LOCK_RIGHT: treeColumn = tree->columnLockRight; break; } boundsBox.x = bounds[0]; boundsBox.y = bounds[1]; boundsBox.width = bounds[2] - bounds[0]; boundsBox.height = bounds[3] - bounds[1]; for (i = TreeColumn_Index(treeColumn); i < tree->columnCount; i++) { if (TreeColumn_Lock(treeColumn) != lock) break; width = TreeColumn_GetDInfo(treeColumn)->width; if (width == 0) /* also handles hidden columns */ goto next; columnBox.x = left; columnBox.y = bounds[1]; columnBox.width = width; columnBox.height = bottom - columnBox.y; if (TreeRect_Intersect(&visBox, &boundsBox, &columnBox)) { Tree_SetRectRegion(columnRgn, &visBox); TkIntersectRegion(dirtyRgn, columnRgn, columnRgn); DrawColumnBackgroundReverse(tree, td, treeColumn, columnRgn, &columnBox, (RItem *) NULL, height, index); } left += width; next: treeColumn = TreeColumn_Next(treeColumn); } } #endif /* ITEMBG_ABOVE */ /* *-------------------------------------------------------------- * * DrawColumnBackground -- * * Draws rows of -itembackground colors in a column in the * whitespace region. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void DrawColumnBackground( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeColumn treeColumn, /* Column to get background colors from. */ TkRegion dirtyRgn, /* Area that needs painting. Will be * inside 'bounds' and inside borders. */ TreeRectangle *bounds, /* Window coords of column to paint. */ RItem *rItem, /* Item(s) to get row heights from when drawing * in the tail column, otherwise NULL. */ int height, /* Height of each row below actual items. */ int index /* Used for alternating background colors. */ ) { #if 0 /* REMOVED BECAUSE OF GRADIENTS */ int bgCount = TreeColumn_BackgroundCount(treeColumn); #endif GC gc = None, backgroundGC; TreeRectangle dirtyBox, drawBox, rowBox; int top, bottom; TreeColor *tc; Tree_GetRegionBounds(dirtyRgn, &dirtyBox); if (!dirtyBox.width || !dirtyBox.height) return; backgroundGC = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC); #if 0 /* REMOVED BECAUSE OF GRADIENTS */ /* If the column has zero -itembackground colors, paint with the * treectrl's -background color. If a single -itembackground color * is specified, then paint with it. */ if (bgCount < 2) { if (bgCount == 1) gc = TreeColumn_BackgroundGC(treeColumn, 0); if (gc == None) gc = backgroundGC; Tree_FillRegion(tree->display, drawable, gc, dirtyRgn); return; } #endif #if 0 /* If -itembackground colors are transparent, we must draw the tree background * color first then the -itembackground colors. This results in flickering * when drawing directly to the toplevel. */ if (tree->doubleBuffer == DOUBLE_BUFFER_ITEM) { tpixmap.width = drawBox.width tpixmap.drawable = DisplayGetPixmap(tree, &dInfo->pixmapI, tpixmap.width, tpixmap.height); } #endif top = bounds->y; bottom = dirtyBox.y + dirtyBox.height; while (top < bottom) { /* Can't use clipping regions with XFillRectangle * because the clip region is ignored on Win32. */ TreeRect_SetXYWH(rowBox, bounds->x, top, bounds->width, rItem ? rItem->size : height); if (TreeRect_Intersect(&drawBox, &rowBox, &dirtyBox)) { TreeRectangle trBrush; if (rItem != NULL) { index = GetItemBgIndex(tree, rItem); } tc = TreeColumn_BackgroundColor(treeColumn, index); /* Handle the drawable offset from the top-left of the window */ drawBox.x -= tree->drawableXOrigin; drawBox.y -= tree->drawableYOrigin; if (tc == NULL) { gc = backgroundGC; XFillRectangle(tree->display, td.drawable, gc, drawBox.x, drawBox.y, drawBox.width, drawBox.height); } else { TreeColor_GetBrushBounds(tree, tc, rowBox, tree->xOrigin, tree->yOrigin, treeColumn, (TreeItem) NULL, &trBrush); if (!TreeColor_IsOpaque(tree, tc) || (trBrush.width <= 0) || (trBrush.height <= 0)) { XFillRectangle(tree->display, td.drawable, backgroundGC, drawBox.x, drawBox.y, drawBox.width, drawBox.height); } /* Handle the drawable offset from the top-left of the window */ trBrush.x -= tree->drawableXOrigin; trBrush.y -= tree->drawableYOrigin; TreeColor_FillRect(tree, td, NULL, tc, trBrush, drawBox); } } if (rItem != NULL && rItem == rItem->range->last) { index = GetItemBgIndex(tree, rItem); rItem = NULL; } if (rItem != NULL) { rItem++; } if (tree->backgroundMode != BG_MODE_COLUMN) index++; top += rowBox.height; top += tree->itemGapY; } } /* *-------------------------------------------------------------- * * DrawWhitespaceBelowItem -- * * Draws rows of -itembackground colors in each column in the * whitespace region. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void DrawWhitespaceBelowItem( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeColumn treeColumn, /* Which columns to draw. */ TreeRectangle bounds, /* TREE_AREA_xxx bounds. */ int left, /* Window coord of first column's left edge. */ int rangeWidth, /* Width of range, needed when only 1 column * is visible with wrapping. */ int top, /* Window coord just below the last item. */ TkRegion dirtyRgn, /* Area of whitespace that needs painting. */ TkRegion columnRgn, /* Existing region to set and use. */ int height, /* Height of each row. */ int index /* Used for alternating background colors. */ ) { int lock = TreeColumn_Lock(treeColumn); int width; TreeRectangle boundsBox, columnBox, visBox; boundsBox = bounds; for (; (treeColumn != NULL) && (TreeColumn_Lock(treeColumn) == lock); treeColumn = TreeColumn_Next(treeColumn)) { width = TreeColumn_GetDInfo(treeColumn)->width; if (width == 0) /* also handles hidden columns */ continue; if (tree->columnCountVis == 1 && rangeWidth != -1) width = rangeWidth; TreeRect_SetXYWH(columnBox, left, top, width, TreeRect_Bottom(bounds) - top); if (TreeRect_Intersect(&visBox, &boundsBox, &columnBox)) { Tree_SetRectRegion(columnRgn, &visBox); TkIntersectRegion(dirtyRgn, columnRgn, columnRgn); DrawColumnBackground(tree, td, treeColumn, columnRgn, &columnBox, (RItem *) NULL, height, index); } left += width; } } /* *-------------------------------------------------------------- * * ComplexWhitespace -- * * Return 1 if -itembackground colors should be drawn into the * whitespace region. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static int ComplexWhitespace( TreeCtrl *tree ) { if (tree->columnBgCnt == 0 && TreeColumn_BackgroundCount(tree->columnTail) == 0) return 0; if (!tree->vertical /*|| (tree->wrapMode != TREE_WRAP_NONE) || (tree->itemWrapCount > 0)*/) return 0; if (tree->itemHeight <= 0 && tree->minItemHeight <= 0) return 0; return 1; } /* *-------------------------------------------------------------- * * DrawWhitespace -- * * Paints part of the whitespace region. * * Results: * If -itembackground colors are not being drawn into the * whitespace region, the dirtyRgn is filled with the treectrl's * -background color. Otherwise rows of color are drawn below * the last item and in the tail column if those columns have * any -itembackground colors specified. * * Side effects: * None. * *-------------------------------------------------------------- */ static void DrawWhitespace( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TkRegion dirtyRgn /* The region that needs repainting. */ ) { TreeDInfo dInfo = tree->dInfo; int minX, minY, maxX, maxY; int top, bottom; int height, index; TreeRectangle columnBox; TkRegion columnRgn; Range *range; RItem *rItem; /* If we aren't drawing -itembackground colors in the whitespace region, * then just paint the entire dirty area with the treectrl's -background * color. */ if (!ComplexWhitespace(tree)) { GC gc = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC); /* Handle the drawable offset from the top-left of the window */ Tree_OffsetRegion(dirtyRgn, -tree->drawableXOrigin, -tree->drawableYOrigin); Tree_FillRegion(tree->display, td.drawable, gc, dirtyRgn); /* Handle the drawable offset from the top-left of the window */ Tree_OffsetRegion(dirtyRgn, tree->drawableXOrigin, tree->drawableYOrigin); return; } /* Erase whitespace in the gaps between items using the treectrl's * background color. */ if (tree->itemGapX > 0 || tree->itemGapY > 0) { GC gc = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC); Tree_FillRegion(tree->display, td.drawable, gc, dirtyRgn); } /* Figure out the height of each row of color below the items. */ if (tree->backgroundMode == BG_MODE_COLUMN) height = -1; /* solid block of color */ else if (tree->itemHeight > 0) height = tree->itemHeight; else height = tree->minItemHeight; columnRgn = Tree_GetRegion(tree); range = dInfo->rangeFirst; if (range == NULL) range = dInfo->rangeLock; if (!dInfo->empty) { int leftEdgeOfColumns = tree->canvasPadX[PAD_TOP_LEFT]; int rightEdgeOfColumns = Tree_CanvasWidth(tree) - tree->canvasPadX[PAD_BOTTOM_RIGHT]; TreeRect_XYXY(dInfo->bounds, &minX, &minY, &maxX, &maxY); if (tree->backgroundMode == BG_MODE_COLUMN) { top = MAX(C2Wy(tree->canvasPadY[PAD_TOP_LEFT]), minY); bottom = maxY; height = bottom - top; /* solid block of color */ } /* Draw to the right of the items using the tail column's * -itembackground colors. The height of each row matches * the height of the adjacent item. */ if (C2Wx(rightEdgeOfColumns) < maxX) { columnBox.y = minY; if (range == NULL) { rItem = NULL; index = 0; } else { /* Get the item at the top of the screen. */ if (range->totalHeight == 0) { rItem = range->last; /* all items have zero height */ } else { int ccContentTop = W2Cy(minY); int rcContentTop = ccContentTop - range->offset.y; /* could be < 0 */ int rcY = MAX(rcContentTop, 0); rItem = Range_ItemUnderPoint(tree, range, -666, rcY, NULL, NULL, 3); columnBox.y = C2Wy(range->offset.y + rItem->offset); } index = GetItemBgIndex(tree, rItem); } columnBox.x = C2Wx(rightEdgeOfColumns); columnBox.width = maxX - columnBox.x; columnBox.height = maxY - columnBox.y; Tree_SetRectRegion(columnRgn, &columnBox); TkIntersectRegion(dirtyRgn, columnRgn, columnRgn); DrawColumnBackground(tree, td, tree->columnTail, columnRgn, &columnBox, rItem, height, index); } /* Draw to the left of the items using the first visible * column's -itembackground colors. The height of each row matches * the height of the adjacent item. */ if (C2Wx(leftEdgeOfColumns) > minX) { columnBox.y = minY; if (range == NULL) { rItem = NULL; index = 0; } else { /* Get the item at the top of the screen. */ if (range->totalHeight == 0) { rItem = range->last; /* all items have zero height */ } else { int ccContentTop = W2Cy(minY); int rcContentTop = ccContentTop - range->offset.y; /* could be < 0 */ int rcY = MAX(rcContentTop,0); rItem = Range_ItemUnderPoint(tree, range, -666, rcY, NULL, NULL, 3); columnBox.y = C2Wy(range->offset.y + rItem->offset); } index = GetItemBgIndex(tree, rItem); } columnBox.x = minX; columnBox.width = C2Wx(leftEdgeOfColumns) - columnBox.x; columnBox.height = maxY - columnBox.y; Tree_SetRectRegion(columnRgn, &columnBox); TkIntersectRegion(dirtyRgn, columnRgn, columnRgn); DrawColumnBackground(tree, td, tree->columnVis ? tree->columnVis : tree->columnTail, columnRgn, &columnBox, rItem, height, index); } } /* Draw below non-locked columns. */ if (!dInfo->empty && tree->columnVis != NULL) { if (dInfo->rangeFirst == NULL) { index = 0; top = Tree_ContentTop(tree); bottom = Tree_ContentBottom(tree); if (tree->backgroundMode == BG_MODE_COLUMN) height = bottom - top; /* solid block of color */ DrawWhitespaceBelowItem(tree, td, tree->columnLockNone, dInfo->bounds, C2Wx(tree->canvasPadX[PAD_TOP_LEFT]), -1, top, dirtyRgn, columnRgn, height, index); } else { int left = tree->canvasPadX[PAD_TOP_LEFT]; while (range != NULL) { top = MAX(C2Wy(range->offset.y + range->totalHeight), Tree_ContentTop(tree)); bottom = Tree_ContentBottom(tree); if ((C2Wx(left + range->totalWidth) > TreeRect_Left(dInfo->bounds)) && (top < bottom)) { rItem = range->last; index = GetItemBgIndex(tree, rItem); if (tree->backgroundMode != BG_MODE_COLUMN) { index++; } if (tree->backgroundMode == BG_MODE_COLUMN) height = bottom - top; /* solid block of color */ DrawWhitespaceBelowItem(tree, td, tree->columnLockNone, dInfo->bounds, C2Wx(left), range->totalWidth, top, dirtyRgn, columnRgn, height, index); } left += range->totalWidth; if (C2Wx(left) >= TreeRect_Right(dInfo->bounds)) break; range = range->next; } } } top = MAX(C2Wy(Tree_CanvasHeight(tree)) - tree->canvasPadY[PAD_BOTTOM_RIGHT] + tree->itemGapY, Tree_ContentTop(tree)); bottom = Tree_ContentBottom(tree); if ((top < bottom) && !(dInfo->emptyL && dInfo->emptyR)) { if (tree->backgroundMode == BG_MODE_COLUMN) height = bottom - top; /* solid block of color */ range = dInfo->rangeFirst; if (range == NULL) range = dInfo->rangeLock; /* Get the display index of the last visible item, if any. */ if (range == NULL) { index = 0; } else { rItem = range->last; index = GetItemBgIndex(tree, rItem); if (tree->backgroundMode != BG_MODE_COLUMN) { index++; } } /* Draw below the left columns. */ if (!dInfo->emptyL) { minX = TreeRect_Left(dInfo->boundsL); DrawWhitespaceBelowItem(tree, td, tree->columnLockLeft, dInfo->boundsL, minX, -1, top, dirtyRgn, columnRgn, height, index); } /* Draw below the right columns. */ if (!dInfo->emptyR) { minX = TreeRect_Left(dInfo->boundsR); DrawWhitespaceBelowItem(tree, td, tree->columnLockRight, dInfo->boundsR, minX, -1, top, dirtyRgn, columnRgn, height, index); } } top = MAX(C2Wy(0), Tree_ContentTop(tree)); bottom = MAX(C2Wy(tree->canvasPadY[PAD_TOP_LEFT]), Tree_ContentTop(tree)); if (top < bottom) { #ifndef ITEMBG_ABOVE GC gc = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC); columnBox.x = Tree_BorderLeft(tree); columnBox.y = Tree_ContentTop(tree); columnBox.width = Tree_BorderRight(tree) - Tree_BorderLeft(tree); columnBox.height = bottom - top; Tree_SetRectRegion(columnRgn, &columnBox); TkIntersectRegion(dirtyRgn, columnRgn, columnRgn); /* Handle the drawable offset from the top-left of the window */ Tree_OffsetRegion(columnRgn, -tree->drawableXOrigin, -tree->drawableYOrigin); Tree_FillRegion(tree->display, td.drawable, gc, columnRgn); /* Handle the drawable offset from the top-left of the window */ Tree_OffsetRegion(columnRgn, tree->drawableXOrigin, tree->drawableYOrigin); #else /* Get the display index of the first visible item. */ if (range == NULL) { index = 0; } else { rItem = range->first; index = GetItemBgIndex(tree, rItem); if (tree->backgroundMode != BG_MODE_COLUMN) { index++; /* FIXME: -- */ } } /* Draw above non-locked columns. */ if (!dInfo->empty && Tree_CanvasWidth(tree)/* && dInfo->rangeFirst != NULL */) { DrawWhitespaceAboveItem(tree, td, COLUMN_LOCK_NONE, dInfo->bounds, x + tree->canvasPadX[PAD_TOP_LEFT], bottom, dirtyRgn, columnRgn, height, index); } /* Draw above the left columns. */ if (!dInfo->emptyL) { minX = TreeRect_Left(dInfo->boundsL); DrawWhitespaceAboveItem(tree, td, COLUMN_LOCK_LEFT, dInfo->boundsL, minX, bottom, dirtyRgn, columnRgn, height, index); } /* Draw above the right columns. */ if (!dInfo->emptyR) { minX = TreeRect_Left(dInfo->boundsR); DrawWhitespaceAboveItem(tree, td, COLUMN_LOCK_RIGHT, dInfo->boundsR, minX, bottom, dirtyRgn, columnRgn, height, index); } #endif } Tree_FreeRegion(tree, columnRgn); } #endif /* COMPLEX_WHITESPACE */ #if COLUMNGRID == 1 static int GridLinesInWhiteSpace( TreeCtrl *tree ) { if (tree->columnsWithGridLines <= 0) return 0; if (!tree->vertical) return 0; /* if ((tree->wrapMode != TREE_WRAP_NONE) || (tree->itemWrapCount > 0)) return 0;*/ return 1; } static void DrawColumnGridLinesAux( TreeCtrl *tree, /* Widget info. */ TreeColumn treeColumn, /* First column. */ TreeDrawable td, /* Where to draw. */ const TreeRectangle *boundsPtr,/* TREA_AREA_xxx bounds. */ int left, /* Left edge of first column. */ int rangeWidth, /* Width of range, needed when only 1 column * is visible with wrapping. */ int minY, int maxY, /* Top & bottom of area to draw in. */ TkRegion dirtyRgn /* The region that needs repainting. */ ) { int lock = TreeColumn_Lock(treeColumn); int columnWidth; TreeRectangle columnBox, gridBox, trBrush; TreeColor *leftColor, *rightColor; int leftWidth, rightWidth; TreeClip clip; clip.type = TREE_CLIP_REGION; clip.region = dirtyRgn; for (; treeColumn != NULL && TreeColumn_Lock(treeColumn) == lock; treeColumn = TreeColumn_Next(treeColumn)) { if (TreeColumn_GridColors(treeColumn, &leftColor, &rightColor, &leftWidth, &rightWidth) == 0) { continue; } columnWidth = TreeColumn_GetDInfo(treeColumn)->width; if (columnWidth == 0) /* also handles hidden columns */ continue; if (tree->columnCountVis == 1 && rangeWidth != -1) columnWidth = rangeWidth; TreeRect_SetXYWH(columnBox, left + TreeColumn_Offset(treeColumn), minY, columnWidth, maxY - minY); if (TreeRect_Right(columnBox) <= TreeRect_Left(*boundsPtr)) continue; if (TreeRect_Left(columnBox) >= TreeRect_Right(*boundsPtr)) break; if (leftColor != NULL && leftWidth > 0) { TreeRect_SetXYWH(gridBox, columnBox.x, columnBox.y, leftWidth, columnBox.height); if (TreeRect_Intersect(&gridBox, boundsPtr, &gridBox)) { TreeColor_GetBrushBounds(tree, leftColor, gridBox, tree->xOrigin, tree->yOrigin, treeColumn, (TreeItem) NULL, &trBrush); TreeColor_FillRect(tree, td, &clip, leftColor, trBrush, gridBox); } } if (rightColor != NULL && rightWidth > 0) { TreeRect_SetXYWH(gridBox, columnBox.x + columnBox.width - rightWidth, columnBox.y, rightWidth, columnBox.height); if (TreeRect_Intersect(&gridBox, boundsPtr, &gridBox)) { TreeColor_GetBrushBounds(tree, rightColor, gridBox, tree->xOrigin, tree->yOrigin, treeColumn, (TreeItem) NULL, &trBrush); TreeColor_FillRect(tree, td, &clip, rightColor, trBrush, gridBox); } } } } /* *---------------------------------------------------------------------- * * DrawColumnGridLines -- * * Draws the column gridlines in the whitespace region below any * items. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ static void DrawColumnGridLines( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TkRegion dirtyRgn /* The region that needs repainting. */ ) { TreeDInfo dInfo = tree->dInfo; int minY, maxY; Range *range = dInfo->rangeFirst; if (!GridLinesInWhiteSpace(tree)) return; maxY = Tree_ContentBottom(tree); /* Draw gridlines below non-locked columns in every Range. */ if (!dInfo->empty && tree->columnVis != NULL) { int left = tree->canvasPadX[PAD_TOP_LEFT]; if (range == NULL) { minY = Tree_ContentTop(tree); if (minY < maxY) { DrawColumnGridLinesAux(tree, tree->columnLockNone, td, &dInfo->bounds, C2Wx(left - tree->canvasPadX[PAD_TOP_LEFT]), -1, minY, maxY, dirtyRgn); } } else { while (range != NULL) { minY = MAX(C2Wy(range->offset.y + range->totalHeight), Tree_ContentTop(tree)); if ((C2Wx(left + range->totalWidth) > TreeRect_Left(dInfo->bounds)) && (minY < maxY)) { DrawColumnGridLinesAux(tree, tree->columnLockNone, td, &dInfo->bounds, C2Wx(left - tree->canvasPadX[PAD_TOP_LEFT]), range->totalWidth, minY, maxY, dirtyRgn); } left += range->totalWidth; if (C2Wx(left) >= TreeRect_Right(dInfo->bounds)) break; range = range->next; } } } minY = MAX(C2Wy(Tree_CanvasHeight(tree)) - tree->canvasPadY[PAD_BOTTOM_RIGHT], Tree_ContentTop(tree)); if (minY >= maxY) return; if (!dInfo->emptyL) { DrawColumnGridLinesAux(tree, tree->columnLockLeft, td, &dInfo->boundsL, Tree_BorderLeft(tree), -1, minY, maxY, dirtyRgn); } if (!dInfo->emptyR) { DrawColumnGridLinesAux(tree, tree->columnLockRight, td, &dInfo->boundsR, Tree_ContentRight(tree), -1, minY, maxY, dirtyRgn); } } #endif /* *---------------------------------------------------------------------- * * Tree_IsBgImageOpaque -- * * Determines if there is any need to erase before drawing the * -backgroundimage. * * Results: * Return 1 if the -backgroundimage will completely fill any * whitespace it is drawn into. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tree_IsBgImageOpaque( TreeCtrl *tree /* Widget info. */ ) { if (tree->backgroundImage == NULL) return 0; if ((tree->bgImageTile & (BGIMG_TILE_X|BGIMG_TILE_Y)) != (BGIMG_TILE_X|BGIMG_TILE_Y)) return 0; return tree->bgImageOpaque; } /* *---------------------------------------------------------------------- * * Tree_DrawTiledImage -- * * This procedure draws a tiled image in the indicated box. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ int Tree_DrawTiledImage( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ Tk_Image image, /* The image to draw. */ TreeRectangle tr, /* Area to paint, may not be filled. */ int xOffset, int yOffset, /* X and Y coord of where to start tiling. */ int tileX, int tileY /* Axes to tile along. */ ) { int imgWidth, imgHeight; TreeRectangle trImage, trPaint; int drawn = 0; #if CACHE_BG_IMG Pixmap pixmap = None; #endif Tk_SizeOfImage(image, &imgWidth, &imgHeight); if (imgWidth <= 0 || imgHeight <= 0) return 0; #if CACHE_BG_IMG /* This pixmap is destroyed at the end of each call to Tree_Display, * so any changes to -backgroundimage will be seen. */ if ((image == tree->backgroundImage) && tree->bgImageOpaque) { pixmap = tree->dInfo->pixmapBgImg.drawable; if (pixmap == None) { pixmap = DisplayGetPixmap(tree, &tree->dInfo->pixmapBgImg, imgWidth, imgHeight); Tk_RedrawImage(image, 0, 0, imgWidth, imgHeight, pixmap, 0, 0); } } #endif while (tileX && xOffset > tr.x) xOffset -= imgWidth; while (tileY && yOffset > tr.y) yOffset -= imgHeight; trImage.x = xOffset, trImage.y = yOffset; trImage.width = imgWidth, trImage.height = imgHeight; do { do { if (TreeRect_Intersect(&trPaint, &trImage, &tr)) { #if CACHE_BG_IMG if (pixmap != None) { XCopyArea(tree->display, pixmap, td.drawable, tree->copyGC, trPaint.x - trImage.x, trPaint.y - trImage.y, trPaint.width, trPaint.height, trPaint.x, trPaint.y); } else #endif Tk_RedrawImage(image, trPaint.x - trImage.x, trPaint.y - trImage.y, trPaint.width, trPaint.height, td.drawable, trPaint.x, trPaint.y); drawn = 1; } trImage.y += trImage.height; } while (tileY && trImage.y < tr.y + tr.height); trImage.x += trImage.width; trImage.y = yOffset; } while (tileX && trImage.x < tr.x + tr.width); return drawn; } /* *---------------------------------------------------------------------- * * CalcBgImageBounds -- * * Calculate the bounds (in canvas coordinates) of the background * image. The background image may be tiled relative to the * returned bounds. * * Results: * Sets trImage with the bounds and returns 1. * * Side effects: * May update item layout. * *---------------------------------------------------------------------- */ static int CalcBgImageBounds( TreeCtrl *tree, /* Widget info. */ TreeRectangle *trImage /* Returned image bounds. */ ) { int x1, y1, x2, y2; int imgWidth, imgHeight; if (tree->bgImageScroll & BGIMG_SCROLL_X) { x1 = 0; x2 = Tree_FakeCanvasWidth(tree); } else { x1 = W2Cx(Tree_ContentLeft(tree)); x2 = x1 + Tree_ContentWidth(tree); } if (tree->bgImageScroll & BGIMG_SCROLL_Y) { y1 = 0; y2 = Tree_FakeCanvasHeight(tree); } else { y1 = W2Cy(Tree_ContentTop(tree)); y2 = y1 + Tree_ContentHeight(tree); } Tk_SizeOfImage(tree->backgroundImage, &imgWidth, &imgHeight); switch (tree->bgImageAnchor) { case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW: break; case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S: x1 = x1 + (x2 - x1) / 2 - imgWidth / 2; break; case TK_ANCHOR_NE: case TK_ANCHOR_E: case TK_ANCHOR_SE: x1 = x2 - imgWidth; break; } switch (tree->bgImageAnchor) { case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE: break; case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E: y1 = y1 + (y2 - y1) / 2 - imgHeight / 2; break; case TK_ANCHOR_SW: case TK_ANCHOR_S: case TK_ANCHOR_SE: y1 = y2 - imgHeight; break; } trImage->x = x1, trImage->y = y1; trImage->width = /*(tree->bgImageTile & BGIMG_TILE_X) ? (x2 - x1) :*/ imgWidth; trImage->height = /*(tree->bgImageTile & BGIMG_TILE_Y) ? (y2 - y1) :*/ imgHeight; return 1; } /* *---------------------------------------------------------------------- * * Tree_DrawBgImage -- * * Draws the -backgroundimage into the specified drawable inside * the given rectangle, positioning and tiling the image according * to the various bgimage widget options. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ int Tree_DrawBgImage( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeRectangle tr, /* Rect to paint with the image. */ int xOrigin, /* Origin of the given drawable in */ int yOrigin /* canvas coordinates. */ ) { TreeRectangle trImage; (void) CalcBgImageBounds(tree, &trImage); return Tree_DrawTiledImage(tree, td, tree->backgroundImage, tr, trImage.x - xOrigin, trImage.y - yOrigin, (tree->bgImageTile & BGIMG_TILE_X) != 0, (tree->bgImageTile & BGIMG_TILE_Y) != 0); } /* *---------------------------------------------------------------------- * * DisplayDItem -- * * Draw a single item. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ static int DisplayDItem( TreeCtrl *tree, /* Widget info. */ DItem *dItem, /* Display info for an item. */ DItemArea *area, int lock, /* Which set of columns. */ TreeRectangle bounds, /* TREE_AREA_xxx bounds of drawing. */ TreeDrawable pixmap, /* Where to draw. */ TreeDrawable drawable /* Where to copy to. */ ) { Tk_Window tkwin = tree->tkwin; int left, top, right, bottom; left = area->x; right = left + area->width; top = dItem->y; bottom = top + dItem->height; if (!(area->flags & DITEM_ALL_DIRTY)) { left += area->dirty[LEFT]; right = area->x + area->dirty[RIGHT]; top += area->dirty[TOP]; bottom = dItem->y + area->dirty[BOTTOM]; } area->flags &= ~(DITEM_DIRTY | DITEM_ALL_DIRTY); area->flags |= DITEM_DRAWN; dItem->flags &= ~(DITEM_INVALIDATE_ON_SCROLL_X | DITEM_INVALIDATE_ON_SCROLL_Y); if (left < TreeRect_Left(bounds)) left = TreeRect_Left(bounds); if (right > TreeRect_Right(bounds)) right = TreeRect_Right(bounds); if (top < TreeRect_Top(bounds)) top = TreeRect_Top(bounds); if (bottom > TreeRect_Bottom(bounds)) bottom = TreeRect_Bottom(bounds); if (right <= left || bottom <= top) return 0; if (tree->debug.enable && tree->debug.display && tree->debug.drawColor) { XFillRectangle(tree->display, Tk_WindowId(tkwin), tree->debug.gcDraw, left, top, right - left, bottom - top); DisplayDelay(tree); } #if USE_ITEM_PIXMAP == 0 if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { DblBufWinDirty(tree, left, top, right, bottom); } /* The top-left corner of the drawable is at this * point in the canvas */ tree->drawableXOrigin = tree->xOrigin; tree->drawableYOrigin = tree->yOrigin; TreeItem_Draw(tree, dItem->item, lock, area->x, dItem->y, area->width, dItem->height, drawable, left, right, dItem->index); #else if (tree->doubleBuffer != DOUBLEBUFFER_NONE) { if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { DblBufWinDirty(tree, left, top, right, bottom); } #ifdef TREECTRL_DEBUG if (tree->debug.eraseColor) XFillRectangle(tree->display, pixmap.drawable, tree->debug.gcErase, 0, 0, right - left, bottom - top); #endif /* The top-left corner of the drawable is at this * point in the canvas */ tree->drawableXOrigin = W2Cx(left); tree->drawableYOrigin = W2Cy(top); TreeItem_Draw(tree, dItem->item, lock, area->x - left, dItem->y - top, area->width, dItem->height, pixmap, 0, right - left, dItem->index); XCopyArea(tree->display, pixmap.drawable, drawable.drawable, tree->copyGC, 0, 0, right - left, bottom - top, left, top); } else { /* The top-left corner of the drawable is at this * point in the canvas */ tree->drawableXOrigin = tree->xOrigin; tree->drawableYOrigin = tree->yOrigin; TreeItem_Draw(tree, dItem->item, lock, area->x, dItem->y, area->width, dItem->height, drawable, left, right, dItem->index); } #endif #if REDRAW_RGN == 1 AddRectToRedrawRgn(tree, left, top, right, bottom); #endif /* REDRAW_RGN */ return 1; } /* *-------------------------------------------------------------- * * UpdateDItemsForHeaders -- * * Allocates or updates a DItem for every on-screen header. * If a header already has a DItem (because it was previously * displayed), then the DItem may be marked dirty if there were * changes to the header's on-screen size or position. * * Results: * None. * * Side effects: * Memory may be allocated. * *-------------------------------------------------------------- */ static void UpdateDItemsForHeaders( TreeCtrl *tree, /* Widget info. */ DItem *dItemHead, /* Linked list of used DItems. */ TreeItem item /* First header item. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItem, *last = NULL; RItem fakeRItem; TreeRectangle itemBbox, boundsL, bounds, boundsR, tr; int emptyL, empty, emptyR, i; DItemArea *areas[3], *area; if (item == NULL) return; emptyL = !Tree_AreaBbox(tree, TREE_AREA_HEADER_LEFT, &boundsL); empty = !Tree_AreaBbox(tree, TREE_AREA_HEADER_NONE, &bounds); emptyR = !Tree_AreaBbox(tree, TREE_AREA_HEADER_RIGHT, &boundsR); boundsL.x = W2Cx(boundsL.x), boundsL.y = W2Cy(boundsL.y); bounds.x = W2Cx(bounds.x), bounds.y = W2Cy(bounds.y); boundsR.x = W2Cx(boundsR.x), boundsR.y = W2Cy(boundsR.y); dInfo->dItemHeader = NULL; while (item != NULL) { if (TreeItem_Height(tree, item) > 0) { dItem = (DItem *) TreeItem_GetDInfo(tree, item); /* Re-use a previously allocated DItem */ if (dItem != NULL) { dItemHead = DItem_Unlink(dItemHead, dItem); /* Make a new DItem */ } else { fakeRItem.item = item; dItem = DItem_Alloc(tree, &fakeRItem); area = &dItem->area; } if (!emptyL && Tree_ItemBbox(tree, item, COLUMN_LOCK_LEFT, &itemBbox) != -1 && TreeRect_Intersect(&tr, &boundsL, &itemBbox)) { dItem->left.x = C2Wx(itemBbox.x); dItem->left.width = itemBbox.width; dItem->y = C2Wy(itemBbox.y); dItem->height = itemBbox.height; } if (!empty && Tree_ItemBbox(tree, item, COLUMN_LOCK_NONE, &itemBbox) != -1 && TreeRect_Intersect(&tr, &bounds, &itemBbox)) { dItem->area.x = C2Wx(itemBbox.x); dItem->area.width = itemBbox.width; dItem->y = C2Wy(itemBbox.y); dItem->height = itemBbox.height; } if (!emptyR && Tree_ItemBbox(tree, item, COLUMN_LOCK_RIGHT, &itemBbox) != -1 && TreeRect_Intersect(&tr, &boundsR, &itemBbox)) { dItem->right.x = C2Wx(itemBbox.x); dItem->right.width = itemBbox.width; dItem->y = C2Wy(itemBbox.y); dItem->height = itemBbox.height; } dItem->spans = TreeItem_GetSpans(tree, item); areas[0] = empty ? NULL : &dItem->area; areas[1] = emptyL ? NULL : &dItem->left; areas[2] = emptyR ? NULL : &dItem->right; for (i = 0; i < 3; i++) { area = areas[i]; if (area == NULL) continue; /* This item is already marked for total redraw */ if (area->flags & DITEM_ALL_DIRTY) ; /* nothing */ /* All display info is marked as invalid */ else if (dInfo->flags & DINFO_INVALIDATE) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; /* Y-coord can change if another header's -visible option changes. */ else if (dItem->y != dItem->oldY) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; else if ((i == 0) && (dItem->flags & DITEM_INVALIDATE_ON_SCROLL_X) && (area->x != dItem->oldX)) area->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; } /* Linked list of DItems */ if (dInfo->dItemHeader == NULL) dInfo->dItemHeader = dItem; else last->next = dItem; last = dItem; } item = TreeItem_GetNextSibling(tree, item); } if (last != NULL) last->next = NULL; while (dItemHead != NULL) dItemHead = DItem_Free(tree, dItemHead); } static void DebugDrawBorder( TreeCtrl *tree, int inset, int left, int top, int right, int bottom ) { Tk_Window tkwin = tree->tkwin; if (tree->debug.enable && tree->debug.display && tree->debug.drawColor) { if (left > 0) { XFillRectangle(tree->display, Tk_WindowId(tkwin), tree->debug.gcDraw, inset, inset, left, Tk_Height(tkwin) - inset * 2); } if (top > 0) { XFillRectangle(tree->display, Tk_WindowId(tkwin), tree->debug.gcDraw, inset, inset, Tk_Width(tkwin) - inset * 2, top); } if (right > 0) { XFillRectangle(tree->display, Tk_WindowId(tkwin), tree->debug.gcDraw, Tk_Width(tkwin) - inset - right, inset, right, Tk_Height(tkwin) - inset * 2); } if (bottom > 0) { XFillRectangle(tree->display, Tk_WindowId(tkwin), tree->debug.gcDraw, inset, Tk_Height(tkwin) - inset - bottom, Tk_Width(tkwin) - inset * 2, bottom); } DisplayDelay(tree); } } /* *-------------------------------------------------------------- * * TreeDisplay_GetReadyForTrouble -- * TreeDisplay_WasThereTrouble -- * * These 2 procedures are used to detect when something happens * during a display update that requests another display update. * If that happens, then the current display is aborted and we * try again (unless the window was destroyed). * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void TreeDisplay_GetReadyForTrouble( TreeCtrl *tree, int *requestsPtr ) { TreeDInfo dInfo = tree->dInfo; *requestsPtr = dInfo->requests; } int TreeDisplay_WasThereTrouble( TreeCtrl *tree, int requests ) { TreeDInfo dInfo = tree->dInfo; if (tree->deleted || (requests != dInfo->requests)) { if (tree->debug.enable) dbwin("TreeDisplay_WasThereTrouble: %p\n", tree); return 1; } return 0; } /* *---------------------------------------------------------------------- * * DisplayGetPixmap -- * * Allocate or reallocate a pixmap of needed size. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Pixmap DisplayGetPixmap( TreeCtrl *tree, TreeDrawable *dPixmap, int width, int height ) { Tk_Window tkwin = tree->tkwin; if (dPixmap->drawable == None) { dPixmap->drawable = Tk_GetPixmap(tree->display, Tk_WindowId(tkwin), width, height, Tk_Depth(tkwin)); dPixmap->width = width; dPixmap->height = height; } else if ((dPixmap->width < width) || (dPixmap->height < height)) { Tk_FreePixmap(tree->display, dPixmap->drawable); dPixmap->drawable = Tk_GetPixmap(tree->display, Tk_WindowId(tkwin), width, height, Tk_Depth(tkwin)); dPixmap->width = width; dPixmap->height = height; } return dPixmap->drawable; } /* *-------------------------------------------------------------- * * CheckPendingHeaderUpdate -- * * This block of code used to be in Tree_Display but it needs to * be checked wherever Range_RedoIfNeeded is called because it * may set the DINFO_REDO_RANGES flag. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ static void CheckPendingHeaderUpdate( TreeCtrl *tree ) { TreeDInfo dInfo = tree->dInfo; /* DINFO_REDO_COLUMN_WIDTH - A column was created or deleted. */ /* DINFO_CHECK_COLUMN_WIDTH - The width, offset or visibility of one or * more columns *might* have changed. */ if (dInfo->flags & (DINFO_REDO_COLUMN_WIDTH | DINFO_CHECK_COLUMN_WIDTH)) { TreeColumn treeColumn = Tree_FirstColumn(tree, -1, TRUE); TreeColumnDInfo dColumn; int force = (dInfo->flags & DINFO_REDO_COLUMN_WIDTH) != 0; int redoRanges = force, drawItems = force, drawHeader = force; int offset, width; /* Set max -itembackground as well. */ tree->columnBgCnt = 0; while (treeColumn != NULL) { offset = TreeColumn_Offset(treeColumn); width = TreeColumn_UseWidth(treeColumn); dColumn = TreeColumn_GetDInfo(treeColumn); /* Haven't seen this column before. */ if (dColumn == NULL) { dColumn = (TreeColumnDInfo) ckalloc(sizeof(TreeColumnDInfo_)); TreeColumn_SetDInfo(treeColumn, dColumn); if (width > 0) redoRanges = drawItems = drawHeader = TRUE; } else { /* Changes to observed width also detects column visibililty * changing. */ if (dColumn->width != width) { redoRanges = drawItems = drawHeader = TRUE; } else if ((dColumn->offset != offset) && (width > 0)) { drawItems = drawHeader = TRUE; } } dColumn->offset = offset; dColumn->width = width; if (TreeColumn_Visible(treeColumn) && (TreeColumn_BackgroundCount(treeColumn) > tree->columnBgCnt)) tree->columnBgCnt = TreeColumn_BackgroundCount(treeColumn); treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, TRUE); } if (redoRanges) dInfo->flags |= DINFO_REDO_RANGES | DINFO_OUT_OF_DATE; if (drawHeader) dInfo->flags |= DINFO_DRAW_HEADER; if (drawItems) dInfo->flags |= DINFO_INVALIDATE; dInfo->flags &= ~(DINFO_REDO_COLUMN_WIDTH | DINFO_CHECK_COLUMN_WIDTH); } if (dInfo->headerHeight != Tree_HeaderHeight(tree)) { dInfo->headerHeight = Tree_HeaderHeight(tree); dInfo->flags |= DINFO_INVALIDATE | /* FIXME: only do this for items covered/exposed */ DINFO_OUT_OF_DATE | DINFO_SET_ORIGIN_Y | DINFO_UPDATE_SCROLLBAR_Y | DINFO_DRAW_HEADER; if (tree->vertical && (tree->wrapMode == TREE_WRAP_WINDOW)) dInfo->flags |= DINFO_REDO_RANGES; } if (dInfo->widthOfColumnsLeft != Tree_WidthOfLeftColumns(tree) || dInfo->widthOfColumnsRight != Tree_WidthOfRightColumns(tree)) { dInfo->widthOfColumnsLeft = Tree_WidthOfLeftColumns(tree); dInfo->widthOfColumnsRight = Tree_WidthOfRightColumns(tree); dInfo->flags |= DINFO_SET_ORIGIN_X | DINFO_UPDATE_SCROLLBAR_X/* | DINFO_OUT_OF_DATE | DINFO_REDO_RANGES | DINFO_DRAW_HEADER*/; } } /* *---------------------------------------------------------------------- * * TrackItemVisibility -- * * Keeps track of the items and individual item-columns that * are visible onscreen. * * Results: * One of the DISPLAY_XXX constants. * * Side effects: * May generate an event. * *---------------------------------------------------------------------- */ enum { DISPLAY_OK, DISPLAY_RETRY, DISPLAY_EXIT }; static int TrackItemVisibility( TreeCtrl *tree, /* Widget info. */ DItem *dItemHead, /* Linked list of onscreen item info. */ int doHeaders /* TRUE to operate on headers, FALSE * to operate on items. */ ) { TreeDInfo dInfo = tree->dInfo; Tcl_HashTable *tablePtr = doHeaders ? &dInfo->headerVisHash : &dInfo->itemVisHash; DItem *dItem; int requests; Tcl_HashEntry *hPtr; Tcl_HashSearch search; TreeItemList newV, newH; TreeItem item; int isNew, i, count; TreeItemList_Init(tree, &newV, 0); TreeItemList_Init(tree, &newH, 0); TreeDisplay_GetReadyForTrouble(tree, &requests); for (dItem = dItemHead; dItem != NULL; dItem = dItem->next) { hPtr = Tcl_FindHashEntry(tablePtr, (char *) dItem->item); if (hPtr == NULL) { /* This item is now visible, wasn't before */ TreeItemList_Append(&newV, dItem->item); TreeItem_OnScreen(tree, dItem->item, TRUE); } #ifdef DCOLUMN /* The item was onscreen and still is. Figure out which * item-columns have become visible or hidden. */ else { TrackOnScreenColumnsForItem(tree, dItem->item, hPtr); } #endif /* DCOLUMN */ } hPtr = Tcl_FirstHashEntry(tablePtr, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashKey(tablePtr, hPtr); if (TreeItem_GetDInfo(tree, item) == NULL) { /* This item was visible but isn't now */ TreeItemList_Append(&newH, item); TreeItem_OnScreen(tree, item, FALSE); } hPtr = Tcl_NextHashEntry(&search); } /* Remove newly-hidden items from itemVisHash */ count = TreeItemList_Count(&newH); for (i = 0; i < count; i++) { item = TreeItemList_Nth(&newH, i); hPtr = Tcl_FindHashEntry(tablePtr, (char *) item); #ifdef DCOLUMN TrackOnScreenColumnsForItem(tree, item, hPtr); ckfree((char *) Tcl_GetHashValue(hPtr)); #endif Tcl_DeleteHashEntry(hPtr); } /* Add newly-visible items to itemVisHash */ count = TreeItemList_Count(&newV); for (i = 0; i < count; i++) { item = TreeItemList_Nth(&newV, i); hPtr = Tcl_CreateHashEntry(tablePtr, (char *) item, &isNew); #ifdef DCOLUMN TrackOnScreenColumnsForItem(tree, item, hPtr); #endif /* DCOLUMN */ } if (!doHeaders) { /* * Generate an event here. This can be used to set * an item's styles when the item is about to be displayed, and to * clear an item's styles when the item is no longer displayed. */ if (TreeItemList_Count(&newV) || TreeItemList_Count(&newH)) { TreeNotify_ItemVisibility(tree, &newV, &newH); } } TreeItemList_Free(&newV); TreeItemList_Free(&newH); if (tree->deleted || !Tk_IsMapped(tree->tkwin)) return DISPLAY_EXIT; if (TreeDisplay_WasThereTrouble(tree, requests)) return DISPLAY_RETRY; return DISPLAY_OK; } /* *---------------------------------------------------------------------- * * SetBuffering -- * * Chooses the appropriate level of offscreen buffering depending * on whether we need to draw the dragimage|marquee|proxies in non-XOR. * * Results: * tree->doubleBuffer is possibly updated. * * Side effects: * If the buffering level changes then the whole list is redrawn. * *---------------------------------------------------------------------- */ static void SetBuffering( TreeCtrl *tree) { TreeDInfo dInfo = tree->dInfo; int overlays = FALSE; if ((TreeDragImage_IsVisible(tree->dragImage) && !TreeDragImage_IsXOR(tree->dragImage)) || (TreeMarquee_IsVisible(tree->marquee) && !TreeMarquee_IsXOR(tree->marquee)) || ((tree->columnProxy.xObj || tree->rowProxy.yObj) && !Proxy_IsXOR())) { overlays = TRUE; } #if 1 tree->doubleBuffer = DOUBLEBUFFER_WINDOW; #else #if defined(MAC_OSX_TK) && (TK_MAJOR_VERSION==8) && (TK_MINOR_VERSION>=6) /* Do NOT call TkScrollWindow(), it generates an event which redraws *all* * child windows of children of the toplevel this treectrl is in. See Tk bug 3086887. */ tree->doubleBuffer = DOUBLEBUFFER_WINDOW; #else if (overlays) { tree->doubleBuffer = DOUBLEBUFFER_WINDOW; } else { tree->doubleBuffer = DOUBLEBUFFER_ITEM; } #endif #endif if (overlays != dInfo->overlays) { dInfo->flags |= DINFO_DRAW_HEADER | DINFO_INVALIDATE | DINFO_DRAW_WHITESPACE; dInfo->overlays = overlays; } } #if 0 struct ExposeRestrictClientData { TreeCtrl *tree; unsigned long serial; }; static Tk_RestrictAction ExposeRestrictProc( ClientData clientData, XEvent *eventPtr ) { struct ExposeRestrictClientData *cd = clientData; TreeCtrl *tree = cd->tree; dbwin("ExposeRestrictProc type=%d", eventPtr->type); if ((eventPtr->type == Expose) && (eventPtr->xexpose.window == Tk_WindowId(tree->tkwin)) && (eventPtr->xany.serial == cd->serial)) { int x = eventPtr->xexpose.x, y = eventPtr->xexpose.y; int w = eventPtr->xexpose.width, h = eventPtr->xexpose.height; if (w > 0 && h > 0) DblBufWinDirty(tree, x, y, x + w, y + h); /* FIXME: DINFO_DRAW_BORDERS */ return TK_DISCARD_EVENT; } return TK_DEFER_EVENT; } #endif /* *-------------------------------------------------------------- * * Tree_Display -- * * This procedure is called at idle time when something has happened * that might require the list to be redisplayed. An effort is made * to only redraw what is needed. * * Results: * None. * * Side effects: * Stuff is drawn in the TreeCtrl window. * *-------------------------------------------------------------- */ static void Tree_Display( ClientData clientData /* Widget info. */ ) { TreeCtrl *tree = clientData; TreeDInfo dInfo = tree->dInfo; DItem *dItem; Tk_Window tkwin = tree->tkwin; int didScrollX = 0, didScrollY = 0; Drawable drawable; TreeDrawable tdrawable; int count; int numCopy = 0, numDraw = 0; TkRegion wsRgnNew, wsRgnDif; #ifdef COMPLEX_WHITESPACE int complexWhitespace; #endif TreeRectangle wsBox; int requests; if (tree->debug.enable && tree->debug.display && 0) dbwin("Tree_Display %s\n", Tk_PathName(tkwin)); if (tree->deleted) { dInfo->flags &= ~(DINFO_REDRAW_PENDING); return; } /* After this point this function must only exit via the displayExit * label. */ Tcl_Preserve((ClientData) tree); Tree_PreserveItems(tree); displayRetry: SetBuffering(tree); /* Some change requires selection changes */ if (dInfo->flags & DINFO_REDO_SELECTION) { #ifdef SELECTION_VISIBLE /* Possible event. */ Tree_DeselectHidden(tree); if (tree->deleted) goto displayExit; #endif dInfo->flags &= ~(DINFO_REDO_SELECTION); } Range_RedoIfNeeded(tree); Increment_RedoIfNeeded(tree); if (dInfo->xOrigin != tree->xOrigin) { dInfo->flags |= DINFO_UPDATE_SCROLLBAR_X | DINFO_OUT_OF_DATE | DINFO_DRAW_HEADER; } if (dInfo->yOrigin != tree->yOrigin) { dInfo->flags |= DINFO_UPDATE_SCROLLBAR_Y | DINFO_OUT_OF_DATE; } if (dInfo->totalWidth != Tree_CanvasWidth(tree)) { dInfo->totalWidth = Tree_CanvasWidth(tree); dInfo->flags |= DINFO_SET_ORIGIN_X | DINFO_UPDATE_SCROLLBAR_X | DINFO_OUT_OF_DATE; } if (dInfo->totalHeight != Tree_CanvasHeight(tree)) { dInfo->totalHeight = Tree_CanvasHeight(tree); dInfo->flags |= DINFO_SET_ORIGIN_Y | DINFO_UPDATE_SCROLLBAR_Y | DINFO_OUT_OF_DATE; } if (dInfo->flags & DINFO_SET_ORIGIN_X) { Tree_SetOriginX(tree, tree->xOrigin); dInfo->flags &= ~DINFO_SET_ORIGIN_X; } if (dInfo->flags & DINFO_SET_ORIGIN_Y) { Tree_SetOriginY(tree, tree->yOrigin); dInfo->flags &= ~DINFO_SET_ORIGIN_Y; } #ifdef COMPLEX_WHITESPACE /* If -itembackground colors are being drawn in the whitespace region, * then redraw all the whitespace if: * a) scrolling occurs, or * b) all the display info was marked as invalid (such as when * -itembackground colors change, or a column moves), or * c) item/column sizes change (handled by Range_RedoIfNeeded). */ complexWhitespace = ComplexWhitespace(tree); if (complexWhitespace) { if ((dInfo->xOrigin != tree->xOrigin) || (dInfo->yOrigin != tree->yOrigin) || (dInfo->flags & DINFO_INVALIDATE)) { dInfo->flags |= DINFO_DRAW_WHITESPACE; } } /* If tree->columnBgCnt was > 0 but is now 0, redraw whitespace. */ if (complexWhitespace != dInfo->complexWhitespace) { dInfo->complexWhitespace = complexWhitespace; dInfo->flags |= DINFO_DRAW_WHITESPACE; } #endif #if COLUMNGRID == 1 /* If gridlines are drawn in the whitespace region then redraw all the * whitespace if: * a) horizontal scrolling occurs * b) all the display info was marked as invalid (such as when * -itembackground colors change, or a column moves) * c) item/column sizes change (handled by Range_RedoIfNeeded). */ if (GridLinesInWhiteSpace(tree)) { if ((dInfo->xOrigin != tree->xOrigin) || (dInfo->flags & DINFO_INVALIDATE)) { dInfo->flags |= DINFO_DRAW_WHITESPACE; } } #endif /* * dInfo->requests counts the number of calls to Tree_EventuallyRedraw(). * If binding scripts do something that causes a redraw to be requested, * then we abort the current draw and start again. */ TreeDisplay_GetReadyForTrouble(tree, &requests); if (dInfo->flags & DINFO_UPDATE_SCROLLBAR_X) { /* Possible event. */ Tree_UpdateScrollbarX(tree); dInfo->flags &= ~DINFO_UPDATE_SCROLLBAR_X; } if (dInfo->flags & DINFO_UPDATE_SCROLLBAR_Y) { /* Possible event. */ Tree_UpdateScrollbarY(tree); dInfo->flags &= ~DINFO_UPDATE_SCROLLBAR_Y; } if (tree->deleted || !Tk_IsMapped(tkwin)) goto displayExit; if (TreeDisplay_WasThereTrouble(tree, requests)) { goto displayRetry; } UpdateDItemsForHeaders(tree, dInfo->dItemHeader, tree->headerItems); if (dInfo->flags & DINFO_OUT_OF_DATE) { Tree_UpdateDInfo(tree); dInfo->flags &= ~DINFO_OUT_OF_DATE; } if (dInfo->flags & DINFO_INVALIDATE) { for (dItem = dInfo->dItem; dItem != NULL; dItem = dItem->next) { dItem->area.flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; dItem->left.flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; dItem->right.flags |= DITEM_DIRTY | DITEM_ALL_DIRTY; } dInfo->flags &= ~DINFO_INVALIDATE; } /* * When an item goes from visible to hidden, "window" elements in the * item must be hidden. An item may become hidden because of scrolling, * or because an ancestor was collapsed, or because the -visible option * of the item changed. */ switch (TrackItemVisibility(tree, dInfo->dItem, FALSE)) { case DISPLAY_RETRY: goto displayRetry; break; case DISPLAY_EXIT: goto displayExit; break; } /* Also track visibility of header items, but don't generate an * event. Just make sure that window elements * in any displayed styles in the headers know when they go offscreen. */ switch (TrackItemVisibility(tree, dInfo->dItemHeader, TRUE)) { case DISPLAY_RETRY: goto displayRetry; break; case DISPLAY_EXIT: goto displayExit; break; } tdrawable.width = Tk_Width(tkwin); tdrawable.height = Tk_Height(tkwin); if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { tdrawable.drawable = DisplayGetPixmap(tree, &dInfo->pixmapW, tdrawable.width, tdrawable.height); } else { tdrawable.drawable = Tk_WindowId(tkwin); } drawable = tdrawable.drawable; /* XOR off */ if (Proxy_IsXOR()) TreeColumnProxy_Undisplay(tree); if (Proxy_IsXOR()) TreeRowProxy_Undisplay(tree); if (TreeDragImage_IsXOR(tree->dragImage)) TreeDragImage_Undisplay(tree->dragImage); if (TreeMarquee_IsXOR(tree->marquee)) TreeMarquee_Undisplay(tree->marquee); #if REDRAW_RGN == 1 /* Collect all the pixels that are redrawn below into the redrawRgn. * The redrawRgn is used to clip drawing of the marquee and dragimage. */ Tree_SetEmptyRegion(dInfo->redrawRgn); #endif /* REDRAW_RGN */ if ((dInfo->flags & DINFO_DRAW_HEADER) && (dInfo->dItemHeader != NULL)) { TreeDrawable tpixmap = tdrawable; /* Scroll the headers if needed. */ ScrollHeaders(tree); for (dItem = dInfo->dItemHeader; dItem != NULL; dItem = dItem->next) { int drawn = 0; TreeRectangle bounds; #if USE_ITEM_PIXMAP == 1 /* Allocate pixmap for largest header */ tpixmap.width = /*MIN(*/Tk_Width(tkwin)/*, dItem->width)*/; tpixmap.height = MIN(Tk_Height(tkwin), dItem->height); tpixmap.drawable = DisplayGetPixmap(tree, &dInfo->pixmapI, tpixmap.width, tpixmap.height); #endif if (Tree_AreaBbox(tree, TREE_AREA_HEADER_NONE, &bounds)) { tree->drawableXOrigin = tree->xOrigin; tree->drawableYOrigin = tree->yOrigin; TreeItem_UpdateWindowPositions(tree, dItem->item, COLUMN_LOCK_NONE, dItem->area.x, dItem->y, dItem->area.width, dItem->height); if (TreeDisplay_WasThereTrouble(tree, requests)) { if (tree->deleted || !Tk_IsMapped(tree->tkwin)) goto displayExit; goto displayRetry; } if (dItem->area.flags & DITEM_DIRTY) { drawn += DisplayDItem(tree, dItem, &dItem->area, COLUMN_LOCK_NONE, bounds, tpixmap, tdrawable); } } else { dItem->area.flags &= ~DITEM_DRAWN; } if (Tree_AreaBbox(tree, TREE_AREA_HEADER_LEFT, &bounds)) { tree->drawableXOrigin = tree->xOrigin; tree->drawableYOrigin = tree->yOrigin; TreeItem_UpdateWindowPositions(tree, dItem->item, COLUMN_LOCK_LEFT, dItem->left.x, dItem->y, dItem->left.width, dItem->height); if (TreeDisplay_WasThereTrouble(tree, requests)) { if (tree->deleted || !Tk_IsMapped(tree->tkwin)) goto displayExit; goto displayRetry; } if (dItem->left.flags & DITEM_DIRTY) { drawn += DisplayDItem(tree, dItem, &dItem->left, COLUMN_LOCK_LEFT, bounds, tpixmap, tdrawable); } } else { dItem->left.flags &= ~DITEM_DRAWN; } if (Tree_AreaBbox(tree, TREE_AREA_HEADER_RIGHT, &bounds)) { tree->drawableXOrigin = tree->xOrigin; tree->drawableYOrigin = tree->yOrigin; TreeItem_UpdateWindowPositions(tree, dItem->item, COLUMN_LOCK_RIGHT, dItem->right.x, dItem->y, dItem->right.width, dItem->height); if (TreeDisplay_WasThereTrouble(tree, requests)) { if (tree->deleted || !Tk_IsMapped(tree->tkwin)) goto displayExit; goto displayRetry; } if (dItem->right.flags & DITEM_DIRTY) { drawn += DisplayDItem(tree, dItem, &dItem->right, COLUMN_LOCK_RIGHT, bounds, tpixmap, tdrawable); } } else { dItem->right.flags &= ~DITEM_DRAWN; } numDraw += drawn ? 1 : 0; dItem->oldX = dItem->area.x; /* FIXME: could have dInfo->empty */ dItem->oldY = dItem->y; dItem->oldIndex = dItem->index; } dInfo->flags &= ~DINFO_DRAW_HEADER; } if (tree->vertical) { numCopy = ScrollVerticalComplex(tree); ScrollHorizontalSimple(tree); } else { ScrollVerticalSimple(tree); numCopy = ScrollHorizontalComplex(tree); } /* If we scrolled, then copy the entire pixmap, plus the header * if needed. */ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { if ((dInfo->xOrigin != tree->xOrigin) || (dInfo->yOrigin != tree->yOrigin)) { DblBufWinDirty(tree, Tree_BorderLeft(tree), Tree_HeaderTop(tree), Tree_BorderRight(tree), Tree_ContentBottom(tree)); } } if (dInfo->flags & DINFO_DRAW_WHITESPACE) { Tree_SetEmptyRegion(dInfo->wsRgn); dInfo->flags &= ~DINFO_DRAW_WHITESPACE; } didScrollX = dInfo->xOrigin != tree->xOrigin; didScrollY = dInfo->yOrigin != tree->yOrigin; dInfo->xOrigin = tree->xOrigin; dInfo->yOrigin = tree->yOrigin; dInfo->flags &= ~(DINFO_REDRAW_PENDING); if (tree->backgroundImage != NULL) { wsRgnNew = CalcWhiteSpaceRegion(tree); /* If we scrolled, redraw entire whitespace area */ if ((didScrollX /*&& (tree->bgImageScroll & BGIMG_SCROLL_X)*/) || (didScrollY /*&& (tree->bgImageScroll & BGIMG_SCROLL_Y)*/)) { wsRgnDif = wsRgnNew; } else { wsRgnDif = Tree_GetRegion(tree); TkSubtractRegion(wsRgnNew, dInfo->wsRgn, wsRgnDif); } Tree_GetRegionBounds(wsRgnDif, &wsBox); if ((wsBox.width > 0) && (wsBox.height > 0)) { TreeDrawable tdPixmap; TreeRectangle trPaint = wsBox; tdPixmap.width = wsBox.width; tdPixmap.height = wsBox.height; tdPixmap.drawable = Tk_GetPixmap(tree->display, Tk_WindowId(tkwin), wsBox.width, wsBox.height, Tk_Depth(tkwin)); if (tree->debug.enable && tree->debug.display && tree->debug.drawColor) { Tree_FillRegion(tree->display, Tk_WindowId(tkwin), tree->debug.gcDraw, wsRgnDif); DisplayDelay(tree); } if (!Tree_IsBgImageOpaque(tree)) { #ifdef COMPLEX_WHITESPACE /* The drawable offset from the top-left of the window */ tree->drawableXOrigin = wsBox.x; tree->drawableYOrigin = wsBox.y; DrawWhitespace(tree, tdPixmap, wsRgnDif); #else GC gc = Tk_3DBorderGC(tkwin, tree->border, TK_3D_FLAT_GC); Tree_OffsetRegion(wsRgnDif, -wsBox.x, -wsBox.y); Tree_FillRegion(tree->display, tdPixmap.drawable, gc, wsRgnDif); Tree_OffsetRegion(wsRgnDif, wsBox.x, wsBox.y); #endif } trPaint.x = trPaint.y = 0; Tree_DrawBgImage(tree, tdPixmap, trPaint, W2Cx(wsBox.x), W2Cy(wsBox.y)); TkSetRegion(tree->display, tree->copyGC, wsRgnDif); XCopyArea(tree->display, tdPixmap.drawable, drawable, tree->copyGC, 0, 0, wsBox.width, wsBox.height, wsBox.x, wsBox.y); XSetClipMask(tree->display, tree->copyGC, None); Tk_FreePixmap(tree->display, tdPixmap.drawable); #if COLUMNGRID == 1 DrawColumnGridLines(tree, tdrawable, wsRgnDif); #endif if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { DblBufWinDirty(tree, wsBox.x, wsBox.y, wsBox.x + wsBox.width, wsBox.y + wsBox.height); } #if REDRAW_RGN == 1 AddRgnToRedrawRgn(tree, wsRgnDif); #endif /* REDRAW_RGN */ } if (wsRgnDif != wsRgnNew) Tree_FreeRegion(tree, wsRgnDif); Tree_FreeRegion(tree, dInfo->wsRgn); dInfo->wsRgn = wsRgnNew; } if (tree->backgroundImage == NULL) { /* Calculate the current whitespace region, subtract the old whitespace * region, and fill the difference with the background color. */ wsRgnNew = CalcWhiteSpaceRegion(tree); wsRgnDif = Tree_GetRegion(tree); TkSubtractRegion(wsRgnNew, dInfo->wsRgn, wsRgnDif); Tree_GetRegionBounds(wsRgnDif, &wsBox); if ((wsBox.width > 0) && (wsBox.height > 0)) { #ifndef COMPLEX_WHITESPACE GC gc = Tk_3DBorderGC(tkwin, tree->border, TK_3D_FLAT_GC); #endif if (tree->debug.enable && tree->debug.display && tree->debug.drawColor) { Tree_FillRegion(tree->display, Tk_WindowId(tkwin), tree->debug.gcDraw, wsRgnDif); DisplayDelay(tree); } #ifdef COMPLEX_WHITESPACE /* The drawable offset from the top-left of the window */ tree->drawableXOrigin = 0; tree->drawableYOrigin = 0; DrawWhitespace(tree, tdrawable, wsRgnDif); #else Tree_FillRegion(tree->display, drawable, gc, wsRgnDif); #endif if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { DblBufWinDirty(tree, wsBox.x, wsBox.y, wsBox.x + wsBox.width, wsBox.y + wsBox.height); } #if COLUMNGRID==1 DrawColumnGridLines(tree, tdrawable, wsRgnDif); #endif #if REDRAW_RGN == 1 AddRgnToRedrawRgn(tree, wsRgnDif); #endif /* REDRAW_RGN */ } Tree_FreeRegion(tree, wsRgnDif); Tree_FreeRegion(tree, dInfo->wsRgn); dInfo->wsRgn = wsRgnNew; } /* See if there are any dirty items */ count = 0; for (dItem = dInfo->dItem; dItem != NULL; dItem = dItem->next) { if ((!dInfo->empty && dInfo->rangeFirstD != NULL) && (dItem->area.flags & DITEM_DIRTY)) { count++; break; } if (!dInfo->emptyL && (dItem->left.flags & DITEM_DIRTY)) { count++; break; } if (!dInfo->emptyR && (dItem->right.flags & DITEM_DIRTY)) { count++; break; } } /* This is the main loop for redrawing dirty items as well as * updating window-element positions. The positions of window * elements must be updated whenever scrolling occurs even if * the scrolling did not invalidate any items. */ if (count > 0 || didScrollX || didScrollY) { TreeDrawable tpixmap = tdrawable; #if USE_ITEM_PIXMAP == 1 if (count > 0 && tree->doubleBuffer != DOUBLEBUFFER_NONE) { /* Allocate pixmap for largest item */ tpixmap.width = MIN(Tk_Width(tkwin), dInfo->itemWidth); tpixmap.height = MIN(Tk_Height(tkwin), dInfo->itemHeight); tpixmap.drawable = DisplayGetPixmap(tree, &dInfo->pixmapI, tpixmap.width, tpixmap.height); } #endif for (dItem = dInfo->dItem; dItem != NULL; dItem = dItem->next) { int drawn = 0; if (!dInfo->empty && dInfo->rangeFirstD != NULL) { tree->drawableXOrigin = tree->xOrigin; tree->drawableYOrigin = tree->yOrigin; TreeItem_UpdateWindowPositions(tree, dItem->item, COLUMN_LOCK_NONE, dItem->area.x, dItem->y, dItem->area.width, dItem->height); if (TreeDisplay_WasThereTrouble(tree, requests)) { if (tree->deleted || !Tk_IsMapped(tree->tkwin)) goto displayExit; goto displayRetry; } if (dItem->area.flags & DITEM_DIRTY) { drawn += DisplayDItem(tree, dItem, &dItem->area, COLUMN_LOCK_NONE, dInfo->bounds, tpixmap, tdrawable); } } else { dItem->area.flags &= ~DITEM_DRAWN; } if (!dInfo->emptyL) { tree->drawableXOrigin = tree->xOrigin; tree->drawableYOrigin = tree->yOrigin; TreeItem_UpdateWindowPositions(tree, dItem->item, COLUMN_LOCK_LEFT, dItem->left.x, dItem->y, dItem->left.width, dItem->height); if (TreeDisplay_WasThereTrouble(tree, requests)) { if (tree->deleted || !Tk_IsMapped(tree->tkwin)) goto displayExit; goto displayRetry; } if (dItem->left.flags & DITEM_DIRTY) { drawn += DisplayDItem(tree, dItem, &dItem->left, COLUMN_LOCK_LEFT, dInfo->boundsL, tpixmap, tdrawable); } } else { dItem->left.flags &= ~DITEM_DRAWN; } if (!dInfo->emptyR) { tree->drawableXOrigin = tree->xOrigin; tree->drawableYOrigin = tree->yOrigin; TreeItem_UpdateWindowPositions(tree, dItem->item, COLUMN_LOCK_RIGHT, dItem->right.x, dItem->y, dItem->right.width, dItem->height); if (TreeDisplay_WasThereTrouble(tree, requests)) { if (tree->deleted || !Tk_IsMapped(tree->tkwin)) goto displayExit; goto displayRetry; } if (dItem->right.flags & DITEM_DIRTY) { drawn += DisplayDItem(tree, dItem, &dItem->right, COLUMN_LOCK_RIGHT, dInfo->boundsR, tpixmap, tdrawable); } } else { dItem->right.flags &= ~DITEM_DRAWN; } numDraw += drawn ? 1 : 0; dItem->oldX = dItem->area.x; /* FIXME: could have dInfo->empty */ dItem->oldY = dItem->y; dItem->oldIndex = dItem->index; } } if (tree->debug.enable && tree->debug.display) dbwin("copy %d draw %d %s\n", numCopy, numDraw, Tk_PathName(tkwin)); #if 0 /* Eat events caused by embedded windows during scrolling. */ if ((tree->doubleBuffer == DOUBLEBUFFER_WINDOW) && (didScrollX || didScrollY)) { ClientData oldArg; Tk_RestrictProc *oldProc; struct ExposeRestrictClientData cd; int oldMode; while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}; oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); cd.tree = tree; cd.serial = LastKnownRequestProcessed(tree->display); TkpSync(tree->display); oldProc = Tk_RestrictEvents(ExposeRestrictProc, &cd, &oldArg); while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} Tk_RestrictEvents(oldProc, oldArg, &oldArg); /* while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}*/ Tcl_SetServiceMode(oldMode); } #endif #if 0 && REDRAW_RGN == 1 tree->drawableXOrigin = tree->xOrigin; tree->drawableYOrigin = tree->yOrigin; if (TreeDragImage_IsXOR(tree->dragImage) == FALSE) TreeDragImage_DrawClipped(tree->dragImage, tdrawable, dInfo->redrawRgn); if (TreeMarquee_IsXOR(tree->marquee) == FALSE) TreeMarquee_DrawClipped(tree->marquee, tdrawable, dInfo->redrawRgn); Tree_SetEmptyRegion(dInfo->redrawRgn); #endif /* REDRAW_RGN */ if (dInfo->overlays) { tdrawable.width = Tk_Width(tkwin); tdrawable.height = Tk_Height(tkwin); if (TreeTheme_IsDesktopComposited(tree)) { tdrawable.drawable = Tk_WindowId(tkwin); } else { tdrawable.drawable = DisplayGetPixmap(tree, &dInfo->pixmapT, Tk_Width(tree->tkwin), Tk_Height(tree->tkwin)); } /* Copy double-buffer */ /* FIXME: only copy what is in dirtyRgn plus overlays */ XCopyArea(tree->display, dInfo->pixmapW.drawable, tdrawable.drawable, tree->copyGC, Tree_BorderLeft(tree), Tree_BorderTop(tree), Tree_BorderRight(tree) - Tree_BorderLeft(tree), Tree_BorderBottom(tree) - Tree_BorderTop(tree), Tree_BorderLeft(tree), Tree_BorderTop(tree)); /* Draw dragimage|marquee|proxies */ tree->drawableXOrigin = tree->xOrigin; tree->drawableYOrigin = tree->yOrigin; if (TreeDragImage_IsXOR(tree->dragImage) == FALSE) TreeDragImage_Draw(tree->dragImage, tdrawable); if (TreeMarquee_IsXOR(tree->marquee) == FALSE) TreeMarquee_Draw(tree->marquee, tdrawable); if (Proxy_IsXOR() == FALSE) TreeColumnProxy_Draw(tree, tdrawable); if (Proxy_IsXOR() == FALSE) TreeRowProxy_Draw(tree, tdrawable); if (TreeTheme_IsDesktopComposited(tree) == FALSE) { /* Copy tripple-buffer to window */ /* FIXME: only copy what is in dirtyRgn plus overlays */ XCopyArea(tree->display, dInfo->pixmapT.drawable, Tk_WindowId(tkwin), tree->copyGC, Tree_BorderLeft(tree), Tree_BorderTop(tree), Tree_BorderRight(tree) - Tree_BorderLeft(tree), Tree_BorderBottom(tree) - Tree_BorderTop(tree), Tree_BorderLeft(tree), Tree_BorderTop(tree)); } Tree_SetEmptyRegion(dInfo->dirtyRgn); DisplayDelay(tree); } else if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { TreeRectangle box; drawable = Tk_WindowId(tkwin); Tree_GetRegionBounds(dInfo->dirtyRgn, &box); if (box.width > 0 && box.height > 0) { TkSetRegion(tree->display, tree->copyGC, dInfo->dirtyRgn); XCopyArea(tree->display, dInfo->pixmapW.drawable, drawable, tree->copyGC, box.x, box.y, box.width, box.height, box.x, box.y); XSetClipMask(tree->display, tree->copyGC, None); } Tree_SetEmptyRegion(dInfo->dirtyRgn); DisplayDelay(tree); } /* XOR on */ if (TreeMarquee_IsXOR(tree->marquee)) TreeMarquee_Display(tree->marquee); if (TreeDragImage_IsXOR(tree->dragImage)) TreeDragImage_Display(tree->dragImage); if (Proxy_IsXOR()) TreeRowProxy_Display(tree); if (Proxy_IsXOR()) TreeColumnProxy_Display(tree); if (tree->doubleBuffer == DOUBLEBUFFER_NONE) dInfo->flags |= DINFO_DRAW_HIGHLIGHT | DINFO_DRAW_BORDER; if (dInfo->flags & (DINFO_DRAW_BORDER | DINFO_DRAW_HIGHLIGHT)) { drawable = Tk_WindowId(tkwin); if (tree->useTheme && TreeTheme_DrawBorders(tree, drawable) == TCL_OK) { /* nothing */ } else { /* Draw focus rectangle (outside of 3D-border) */ if ((dInfo->flags & DINFO_DRAW_HIGHLIGHT) && (tree->highlightWidth > 0)) { GC fgGC, bgGC; DebugDrawBorder(tree, 0, tree->highlightWidth, tree->highlightWidth, tree->highlightWidth, tree->highlightWidth); bgGC = Tk_GCForColor(tree->highlightBgColorPtr, drawable); if (tree->gotFocus) fgGC = Tk_GCForColor(tree->highlightColorPtr, drawable); else fgGC = bgGC; TkpDrawHighlightBorder(tkwin, fgGC, bgGC, tree->highlightWidth, drawable); dInfo->flags &= ~DINFO_DRAW_HIGHLIGHT; } /* Draw 3D-border (inside of focus rectangle) */ if ((dInfo->flags & DINFO_DRAW_BORDER) && (tree->borderWidth > 0)) { DebugDrawBorder(tree, tree->highlightWidth, tree->borderWidth, tree->borderWidth, tree->borderWidth, tree->borderWidth); Tk_Draw3DRectangle(tkwin, drawable, tree->border, tree->highlightWidth, tree->highlightWidth, Tk_Width(tkwin) - tree->highlightWidth * 2, Tk_Height(tkwin) - tree->highlightWidth * 2, tree->borderWidth, tree->relief); dInfo->flags &= ~DINFO_DRAW_BORDER; } } dInfo->flags &= ~(DINFO_DRAW_BORDER | DINFO_DRAW_HIGHLIGHT); } displayExit: #if CACHE_BG_IMG if (dInfo->pixmapBgImg.drawable != None) { Tk_FreePixmap(tree->display, dInfo->pixmapBgImg.drawable); dInfo->pixmapBgImg.drawable = None; } #endif dInfo->flags &= ~(DINFO_REDRAW_PENDING); Tree_ReleaseItems(tree); Tcl_Release((ClientData) tree); } /* *-------------------------------------------------------------- * * A_IncrementFindX -- * * Return a horizontal scroll position nearest to the given * offset. * * Results: * Index of the nearest increment <= the given offset. * * Side effects: * None. * *-------------------------------------------------------------- */ static int A_IncrementFindX( TreeCtrl *tree, /* Widget info. */ int offset /* Canvas x-coordinate. */ ) { int totWidth = Tree_CanvasWidth(tree); int xIncr = tree->xScrollIncrement; int index, indexMax; indexMax = totWidth / xIncr; if (totWidth % xIncr == 0) indexMax--; if (offset < 0) offset = 0; index = offset / xIncr; if (index > indexMax) index = indexMax; return index; } /* *-------------------------------------------------------------- * * A_IncrementFindY -- * * Return a vertical scroll position nearest to the given * offset. * * Results: * Index of the nearest increment <= the given offset. * * Side effects: * None. * *-------------------------------------------------------------- */ static int A_IncrementFindY( TreeCtrl *tree, /* Widget info. */ int offset /* Canvas y-coordinate. */ ) { int totHeight = Tree_CanvasHeight(tree); int yIncr = tree->yScrollIncrement; int index, indexMax; indexMax = totHeight / yIncr; if (totHeight % yIncr == 0) indexMax--; if (offset < 0) offset = 0; index = offset / yIncr; if (index > indexMax) index = indexMax; return index; } int Tree_FakeCanvasWidth( TreeCtrl *tree ) { TreeDInfo dInfo = tree->dInfo; int visWidth, totWidth; int oldSmoothing = tree->scrollSmoothing; int indexMax, offset; Increment_RedoIfNeeded(tree); /* Use the cached value, if valid. */ if (dInfo->fakeCanvasWidth >= 0) return dInfo->fakeCanvasWidth; totWidth = Tree_CanvasWidth(tree); if (totWidth <= 0) return dInfo->fakeCanvasWidth = MAX(0, Tree_BorderRight(tree) - Tree_BorderLeft(tree)); visWidth = Tree_ContentWidth(tree); if (visWidth > 1) { tree->scrollSmoothing = 0; /* Find the increment at the left edge of the content area when * the view is scrolled all the way to the right. */ indexMax = Increment_FindX(tree, totWidth - visWidth); offset = Increment_ToOffsetX(tree, indexMax); /* If the increment starts before the left edge of the content area * then use the next increment to the right. */ if (offset < totWidth - visWidth) { indexMax++; offset = Increment_ToOffsetX(tree, indexMax); } /* Add some fake content to right. */ if (offset + visWidth > totWidth) totWidth = offset + visWidth; tree->scrollSmoothing = oldSmoothing; } return dInfo->fakeCanvasWidth = totWidth; } int Tree_FakeCanvasHeight( TreeCtrl *tree ) { TreeDInfo dInfo = tree->dInfo; int visHeight, totHeight; int oldSmoothing = tree->scrollSmoothing; int indexMax, offset; Increment_RedoIfNeeded(tree); /* Use the cached value, if valid. */ if (dInfo->fakeCanvasHeight >= 0) return dInfo->fakeCanvasHeight; totHeight = Tree_CanvasHeight(tree); if (totHeight <= 0) return dInfo->fakeCanvasHeight = MAX(0, Tree_ContentHeight(tree)); visHeight = Tree_ContentHeight(tree); if (visHeight > 1) { tree->scrollSmoothing = 0; /* Find the increment at the top edge of the content area when * the view is scrolled all the way down. */ indexMax = Increment_FindY(tree, totHeight - visHeight); offset = Increment_ToOffsetY(tree, indexMax); /* If the increment starts before the top edge of the content area * then use the next increment down. */ if (offset < totHeight - visHeight) { indexMax++; offset = Increment_ToOffsetY(tree, indexMax); } /* Add some fake content to bottom. */ if (offset + visHeight > totHeight) totHeight = offset + visHeight; tree->scrollSmoothing = oldSmoothing; } return dInfo->fakeCanvasHeight = totHeight; } static int Smooth_IncrementFindX( TreeCtrl *tree, /* Widget info. */ int offset /* Canvas x-coordinate. */ ) { int totWidth = Tree_FakeCanvasWidth(tree); int xIncr = 1; int index, indexMax; indexMax = totWidth / xIncr; if (totWidth % xIncr == 0) indexMax--; if (offset < 0) offset = 0; index = offset / xIncr; if (index > indexMax) index = indexMax; return index; } static int Smooth_IncrementFindY( TreeCtrl *tree, /* Widget info. */ int offset /* Canvas y-coordinate. */ ) { int totHeight = Tree_FakeCanvasHeight(tree); int yIncr = 1; int index, indexMax; indexMax = totHeight / yIncr; if (totHeight % yIncr == 0) indexMax--; if (offset < 0) offset = 0; index = offset / yIncr; if (index > indexMax) index = indexMax; return index; } /* *-------------------------------------------------------------- * * Increment_FindX -- * * Return a horizontal scroll position nearest to the given * offset. * * Results: * Index of the nearest increment <= the given offset. * * Side effects: * None. * *-------------------------------------------------------------- */ int Increment_FindX( TreeCtrl *tree, /* Widget info. */ int offset /* Canvas x-coordinate. */ ) { if (tree->scrollSmoothing & SMOOTHING_X) return Smooth_IncrementFindX(tree, offset); if (tree->xScrollIncrement <= 0) { Increment_RedoIfNeeded(tree); return B_IncrementFindX(tree, offset); } return A_IncrementFindX(tree, offset); } /* *-------------------------------------------------------------- * * Increment_FindY -- * * Return a vertical scroll position nearest to the given * offset. * * Results: * Index of the nearest increment <= the given offset. * * Side effects: * None. * *-------------------------------------------------------------- */ int Increment_FindY( TreeCtrl *tree, /* Widget info. */ int offset /* Canvas y-coordinate. */ ) { if (tree->scrollSmoothing & SMOOTHING_Y) return Smooth_IncrementFindY(tree, offset); if (tree->yScrollIncrement <= 0) { Increment_RedoIfNeeded(tree); return B_IncrementFindY(tree, offset); } return A_IncrementFindY(tree, offset); } /* *-------------------------------------------------------------- * * Increment_ToOffsetX -- * * Return the canvas coordinate for a scroll position. * * Results: * Pixel distance. * * Side effects: * None. * *-------------------------------------------------------------- */ int Increment_ToOffsetX( TreeCtrl *tree, /* Widget info. */ int index /* Index of the increment. */ ) { TreeDInfo dInfo = tree->dInfo; int xIncr = tree->xScrollIncrement; if (tree->scrollSmoothing & SMOOTHING_X) return index * 1; if (xIncr <= 0) { DScrollIncrements *dIncr = &dInfo->xScrollIncrements; if (index < 0 || index >= dIncr->count) { panic("Increment_ToOffsetX: bad index %d (must be 0-%d)", index, dIncr->count-1); } return dIncr->increments[index]; } return index * xIncr; } /* *-------------------------------------------------------------- * * Increment_ToOffsetY -- * * Return the canvas coordinate for a scroll position. * * Results: * Pixel distance. * * Side effects: * None. * *-------------------------------------------------------------- */ int Increment_ToOffsetY( TreeCtrl *tree, /* Widget info. */ int index /* Index of the increment. */ ) { TreeDInfo dInfo = tree->dInfo; int yIncr = tree->yScrollIncrement; if (tree->scrollSmoothing & SMOOTHING_Y) return index * 1; if (yIncr <= 0) { DScrollIncrements *dIncr = &dInfo->yScrollIncrements; if (index < 0 || index >= dIncr->count) { panic("Increment_ToOffsetY: bad index %d (must be 0-%d)\ntotHeight %d visHeight %d", index, dIncr->count - 1, Tree_CanvasHeight(tree), Tree_ContentHeight(tree)); } return dIncr->increments[index]; } return index * yIncr; } /* *-------------------------------------------------------------- * * GetScrollFractions -- * * Return the fractions that may be passed to a scrollbar "set" * command. * * Results: * Two fractions from 0.0 to 1.0. * * Side effects: * None. * *-------------------------------------------------------------- */ static void GetScrollFractions( int screen1, int screen2, /* Min/max coordinates that are visible in * the window. */ int object1, int object2, /* Min/max coordinates of the scrollable * content (usually 0 to N where N is the * total width or height of the canvas). */ double fractions[2] /* Returned values. */ ) { double range, f1, f2; range = object2 - object1; if (range <= 0) { f1 = 0; f2 = 1.0; } else { f1 = (screen1 - object1) / range; if (f1 < 0) f1 = 0.0; f2 = (screen2 - object1) / range; if (f2 > 1.0) f2 = 1.0; if (f2 < f1) f2 = f1; } fractions[0] = f1; fractions[1] = f2; } /* *-------------------------------------------------------------- * * Tree_GetScrollFractionsX -- * * Return the fractions that may be passed to a scrollbar "set" * command for a horizontal scrollbar. * * Results: * Two fractions from 0 to 1.0. * * Side effects: * None. * *-------------------------------------------------------------- */ void Tree_GetScrollFractionsX( TreeCtrl *tree, /* Widget info. */ double fractions[2] /* Returned values. */ ) { int left = W2Cx(Tree_ContentLeft(tree)); int visWidth = Tree_ContentWidth(tree); int totWidth = Tree_CanvasWidth(tree); /* The tree is empty, or everything fits in the window */ if (visWidth < 0) visWidth = 0; if (totWidth <= visWidth) { fractions[0] = 0.0; fractions[1] = 1.0; return; } if (visWidth <= 1) { GetScrollFractions(left, left + 1, 0, totWidth, fractions); return; } totWidth = Tree_FakeCanvasWidth(tree); GetScrollFractions(left, left + visWidth, 0, totWidth, fractions); } /* *-------------------------------------------------------------- * * Tree_GetScrollFractionsY -- * * Return the fractions that may be passed to a scrollbar "set" * command for a vertical scrollbar. * * Results: * Two fractions from 0 to 1.0. * * Side effects: * None. * *-------------------------------------------------------------- */ void Tree_GetScrollFractionsY( TreeCtrl *tree, /* Widget info. */ double fractions[2] /* Returned values. */ ) { int top = W2Cy(Tree_ContentTop(tree)); int visHeight = Tree_ContentHeight(tree); int totHeight = Tree_CanvasHeight(tree); /* The tree is empty, or everything fits in the window */ if (visHeight < 0) visHeight = 0; if (totHeight <= visHeight) { fractions[0] = 0.0; fractions[1] = 1.0; return; } if (visHeight <= 1) { GetScrollFractions(top, top + 1, 0, totHeight, fractions); return; } totHeight = Tree_FakeCanvasHeight(tree); GetScrollFractions(top, top + visHeight, 0, totHeight, fractions); } void Tree_SetScrollSmoothingX( TreeCtrl *tree, /* Widget info. */ int smoothing /* TRUE or FALSE */ ) { if (smoothing && tree->xScrollSmoothing) tree->scrollSmoothing |= SMOOTHING_X; else tree->scrollSmoothing &= ~SMOOTHING_X; } void Tree_SetScrollSmoothingY( TreeCtrl *tree, /* Widget info. */ int smoothing /* TRUE or FALSE */ ) { if (smoothing && tree->yScrollSmoothing) tree->scrollSmoothing |= SMOOTHING_Y; else tree->scrollSmoothing &= ~SMOOTHING_Y; } /* *-------------------------------------------------------------- * * Tree_SetOriginX -- * * Change the horizontal scroll position. * * Results: * None. * * Side effects: * If the horizontal scroll position changes, then the widget is * redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_SetOriginX( TreeCtrl *tree, /* Widget info. */ int xOrigin /* The desired offset from the left edge * of the window to the left edge of the * canvas. The actual value will be clipped * to the nearest scroll increment. */ ) { int totWidth = Tree_CanvasWidth(tree); int visWidth = Tree_ContentWidth(tree); int index, indexMax, offset; /* The tree is empty, or everything fits in the window */ if (visWidth < 0) visWidth = 0; if (totWidth <= visWidth) { xOrigin = 0 - Tree_ContentLeft(tree); if (xOrigin != tree->xOrigin) { tree->xOrigin = xOrigin; Tree_EventuallyRedraw(tree); } return; } totWidth = Tree_FakeCanvasWidth(tree); if (visWidth > 1) { indexMax = Increment_FindX(tree, totWidth - visWidth); } else { indexMax = Increment_FindX(tree, totWidth); } xOrigin += Tree_ContentLeft(tree); /* origin -> canvas */ index = Increment_FindX(tree, xOrigin); /* Don't scroll too far left */ if (index < 0) index = 0; /* Don't scroll too far right */ if (index > indexMax) index = indexMax; offset = Increment_ToOffsetX(tree, index); xOrigin = offset - Tree_ContentLeft(tree); if (xOrigin == tree->xOrigin) return; tree->xOrigin = xOrigin; Tree_EventuallyRedraw(tree); } /* *-------------------------------------------------------------- * * Tree_SetOriginY -- * * Change the vertical scroll position. * * Results: * None. * * Side effects: * If the vertical scroll position changes, then the widget is * redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_SetOriginY( TreeCtrl *tree, /* Widget info. */ int yOrigin /* The desired offset from the top edge * of the window to the top edge of the * canvas. The actual value will be clipped * to the nearest scroll increment. */ ) { int visHeight = Tree_ContentHeight(tree); int totHeight = Tree_CanvasHeight(tree); int index, indexMax, offset; /* The tree is empty, or everything fits in the window */ if (visHeight < 0) visHeight = 0; if (totHeight <= visHeight) { yOrigin = 0 - Tree_ContentTop(tree); if (yOrigin != tree->yOrigin) { tree->yOrigin = yOrigin; Tree_EventuallyRedraw(tree); } return; } totHeight = Tree_FakeCanvasHeight(tree); if (visHeight > 1) { indexMax = Increment_FindY(tree, totHeight - visHeight); } else { indexMax = Increment_FindY(tree, totHeight); } yOrigin += Tree_ContentTop(tree); /* origin -> canvas */ index = Increment_FindY(tree, yOrigin); /* Don't scroll too far up */ if (index < 0) index = 0; /* Don't scroll too far down */ if (index > indexMax) index = indexMax; offset = Increment_ToOffsetY(tree, index); yOrigin = offset - Tree_ContentTop(tree); if (yOrigin == tree->yOrigin) return; tree->yOrigin = yOrigin; Tree_EventuallyRedraw(tree); } /* *-------------------------------------------------------------- * * Tree_GetOriginX -- * * Return the horizontal scroll position. * * Results: * None. * * Side effects: * May update the horizontal scroll position. * If the horizontal scroll position changes, then the widget is * redisplayed at idle time. * *-------------------------------------------------------------- */ int Tree_GetOriginX( TreeCtrl *tree /* Widget info. */ ) { /* Update the value if needed. */ Tree_SetOriginX(tree, tree->xOrigin); return tree->xOrigin; } /* *-------------------------------------------------------------- * * Tree_GetOriginY -- * * Return the vertical scroll position. * * Results: * None. * * Side effects: * May update the vertical scroll position. * If the vertical scroll position changes, then the widget is * redisplayed at idle time. * *-------------------------------------------------------------- */ int Tree_GetOriginY( TreeCtrl *tree /* Widget info. */ ) { /* Update the value if needed. */ Tree_SetOriginY(tree, tree->yOrigin); return tree->yOrigin; } /* *-------------------------------------------------------------- * * Tree_EventuallyRedraw -- * * Schedule an idle task to redisplay the widget, if one is not * already scheduled and the widget is mapped and the widget * hasn't been deleted. * * Results: * None. * * Side effects: * The widget may be redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_EventuallyRedraw( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; dInfo->requests++; if ((dInfo->flags & DINFO_REDRAW_PENDING) || tree->deleted || !Tk_IsMapped(tree->tkwin)) { return; } dInfo->flags |= DINFO_REDRAW_PENDING; Tcl_DoWhenIdle(Tree_Display, (ClientData) tree); } /* *-------------------------------------------------------------- * * Tree_RelayoutWindow -- * * Invalidate all the layout info for the widget and schedule a * redisplay at idle time. This gets called when certain config * options change and when the size of the widget changes. * * Results: * None. * * Side effects: * The widget will be redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_RelayoutWindow( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; FreeDItems(tree, NULL, dInfo->dItem, NULL); dInfo->dItem = NULL; FreeDItems(tree, NULL, dInfo->dItemHeader, NULL); dInfo->dItemHeader = NULL; dInfo->flags |= DINFO_REDO_RANGES | DINFO_OUT_OF_DATE | DINFO_CHECK_COLUMN_WIDTH | DINFO_DRAW_HEADER | DINFO_DRAW_HIGHLIGHT | DINFO_DRAW_BORDER | DINFO_SET_ORIGIN_X | DINFO_SET_ORIGIN_Y | DINFO_UPDATE_SCROLLBAR_X | DINFO_UPDATE_SCROLLBAR_Y; dInfo->xOrigin = tree->xOrigin; dInfo->yOrigin = tree->yOrigin; /* Needed if -background color changes. */ dInfo->flags |= DINFO_DRAW_WHITESPACE; if (tree->doubleBuffer != DOUBLEBUFFER_WINDOW) { if (dInfo->pixmapW.drawable != None) { Tk_FreePixmap(tree->display, dInfo->pixmapW.drawable); dInfo->pixmapW.drawable = None; } } if (tree->doubleBuffer == DOUBLEBUFFER_NONE) { if (dInfo->pixmapI.drawable != None) { Tk_FreePixmap(tree->display, dInfo->pixmapI.drawable); dInfo->pixmapI.drawable = None; } } if (tree->useTheme) { TreeTheme_Relayout(tree); TreeTheme_SetBorders(tree); } Tree_EventuallyRedraw(tree); } /* *-------------------------------------------------------------- * * Tree_FocusChanged -- * * This procedure handles the widget gaining or losing the input * focus. The state of every item has STATE_ITEM_FOCUS toggled on or * off. * * Results: * None. * * Side effects: * The widget may be redisplayed at idle time if -highlightthickness * is > 0, or if any Elements change appearance because of the * state change. * *-------------------------------------------------------------- */ void Tree_FocusChanged( TreeCtrl *tree, /* Widget info. */ int gotFocus /* TRUE if the widget has the focus, * otherwise FALSE. */ ) { TreeDInfo dInfo = tree->dInfo; TreeItem item; Tcl_HashEntry *hPtr; Tcl_HashSearch search; int stateOn, stateOff; tree->gotFocus = gotFocus; if (gotFocus) stateOff = 0, stateOn = STATE_HEADER_FOCUS; else stateOff = STATE_HEADER_FOCUS, stateOn = 0; /* Slow. Change state of every header */ item = tree->headerItems; while (item != NULL) { TreeItem_ChangeState(tree, item, stateOff, stateOn); item = TreeItem_GetNextSibling(tree, item); } if (gotFocus) stateOff = 0, stateOn = STATE_ITEM_FOCUS; else stateOff = STATE_ITEM_FOCUS, stateOn = 0; /* Slow. Change state of every item */ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); TreeItem_ChangeState(tree, item, stateOff, stateOn); hPtr = Tcl_NextHashEntry(&search); } #ifdef USE_TTK dInfo->flags |= DINFO_DRAW_HIGHLIGHT; Tree_EventuallyRedraw(tree); #else if (tree->highlightWidth > 0) { dInfo->flags |= DINFO_DRAW_HIGHLIGHT; Tree_EventuallyRedraw(tree); } #endif } /* *-------------------------------------------------------------- * * Tree_Activate -- * * This procedure handles the widget's toplevel being the "active" * foreground window (on Macintosh and Windows). Currently it just * redraws the header if -usetheme is TRUE and the header is * visible. * * Results: * None. * * Side effects: * The widget may be redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_Activate( TreeCtrl *tree, /* Widget info. */ int isActive /* TRUE if the widget's toplevel is the * active window, otherwise FALSE. */ ) { TreeDInfo dInfo = tree->dInfo; int stateOff, stateOn; TreeItem item; tree->isActive = isActive; /* Change the state of every header. */ if (isActive) stateOff = STATE_HEADER_BG, stateOn = 0; else stateOff = 0, stateOn = STATE_HEADER_BG; item = tree->headerItems; while (item != NULL) { TreeItem_ChangeState(tree, item, stateOff, stateOn); item = TreeItem_GetNextSibling(tree, item); } /* TODO: Like Tree_FocusChanged, change state of every item. */ /* Would need a new item state STATE_ACTIVEWINDOW or something. */ /* Would want to merge this with Tree_FocusChanged code to avoid * double-iteration of items. */ /* Aqua column header looks different when window is not active */ if (tree->useTheme && tree->showHeader) { dInfo->flags |= DINFO_DRAW_HEADER; Tree_EventuallyRedraw(tree); } } /* *-------------------------------------------------------------- * * Tree_FreeItemDInfo -- * * Free any DItem associated with each item in a range of items. * This is called when the size of an item changed or an item is * deleted. * * Results: * None. * * Side effects: * The widget will be redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_FreeItemDInfo( TreeCtrl *tree, /* Widget info. */ TreeItem item1, /* First item in the range. */ TreeItem item2 /* Last item in the range, or NULL. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItem, **dItemHeadPtr = &dInfo->dItem; TreeItem item = item1; int changed = 0; while (item != NULL) { if (TreeItem_GetHeader(tree, item) != NULL) { tree->headerHeight = -1; dInfo->flags |= DINFO_DRAW_HEADER; dItemHeadPtr = &dInfo->dItemHeader; } dItem = (DItem *) TreeItem_GetDInfo(tree, item); if (dItem != NULL) { FreeDItems(tree, dItemHeadPtr, dItem, dItem->next); changed = 1; } if (item == item2 || item2 == NULL) break; item = TreeItem_Next(tree, item); } changed = 1; if (changed) { if (TreeItem_GetHeader(tree, item1) == NULL) dInfo->flags |= DINFO_OUT_OF_DATE; Tree_EventuallyRedraw(tree); } } /* *-------------------------------------------------------------- * * Tree_InvalidateItemDInfo -- * * Mark as dirty any DItem associated with each item in a range * of items. This is called when the appearance of an item changed * (but not its size). * * Results: * None. * * Side effects: * The widget will be redisplayed at idle time if any of the items * had a DItem. * *-------------------------------------------------------------- */ void Tree_InvalidateItemDInfo( TreeCtrl *tree, /* Widget info. */ TreeColumn column, /* Column to invalidate, or NULL for all. */ TreeItem item1, /* First item in the range. */ TreeItem item2 /* Last item in the range, or NULL. */ ) { TreeDInfo dInfo = tree->dInfo; TreeColumn column2; DItem *dItem; TreeItem item = item1; int changed = 0; if (item != NULL && TreeItem_GetHeader(tree, item) != NULL) { dInfo->flags |= DINFO_DRAW_HEADER; } if (dInfo->flags & (DINFO_INVALIDATE | DINFO_REDO_COLUMN_WIDTH)) return; while (item != NULL) { dItem = (DItem *) TreeItem_GetDInfo(tree, item); if ((dItem == NULL) || DItemAllDirty(tree, dItem)) goto next; if (column == NULL) { dItem->area.flags |= (DITEM_DIRTY | DITEM_ALL_DIRTY); dItem->left.flags |= (DITEM_DIRTY | DITEM_ALL_DIRTY); dItem->right.flags |= (DITEM_DIRTY | DITEM_ALL_DIRTY); changed = 1; } else { TreeColumnDInfo dColumn = TreeColumn_GetDInfo(column); int columnIndex, left, width, i, extraWidth = 0; DItemArea *area = NULL; switch (TreeColumn_Lock(column)) { case COLUMN_LOCK_NONE: area = &dItem->area; break; case COLUMN_LOCK_LEFT: area = &dItem->left; break; case COLUMN_LOCK_RIGHT: area = &dItem->right; break; } if (area->flags & DITEM_ALL_DIRTY) goto next; columnIndex = TreeColumn_Index(column); left = dColumn->offset; if (TreeColumn_Lock(column) == COLUMN_LOCK_NONE) { if (TreeItem_GetHeader(tree, item) != NULL) { if (TreeColumn_VisIndex(column) == 0) { extraWidth = tree->canvasPadX[PAD_TOP_LEFT]; left = 0; } } else left -= tree->canvasPadX[PAD_TOP_LEFT]; /* canvas -> item coords */ } if (column == tree->columnTail) width = area->width - dColumn->offset; /* If only one column is visible, the width may be * different than the column width. */ else if ((TreeColumn_Lock(column) == COLUMN_LOCK_NONE) && (tree->columnCountVis == 1)) { width = area->width; /* All spans are 1. */ } else if (dItem->spans == NULL) { width = dColumn->width + extraWidth; /* If the column being redrawn is not the first in the span, * then do nothing. */ } else if (columnIndex != dItem->spans[columnIndex]) { goto next; /* Calculate the width of the entire span. */ /* Do NOT call TreeColumn_UseWidth() or another routine * that calls Tree_WidthOfColumns() because that may end * up recalculating the size of items whose display info * is currently being invalidated. */ } else { width = 0 + extraWidth; column2 = column; i = columnIndex; while (dItem->spans[i] == columnIndex) { width += TreeColumn_GetDInfo(column2)->width; if (++i == tree->columnCount) break; column2 = TreeColumn_Next(column2); } } #ifdef MAC_OSX_TK /* Aqua headers overlap one pixel on the left edge. */ if (TreeItem_GetHeader(tree, item) != NULL) { left -= 1; width += 2; } #endif if (width > 0) { InvalidateDItemX(dItem, area, 0, left, width); InvalidateDItemY(dItem, area, 0, 0, dItem->height); area->flags |= DITEM_DIRTY; changed = 1; } } next: if (item == item2 || item2 == NULL) break; item = TreeItem_Next(tree, item); } if (changed) { Tree_EventuallyRedraw(tree); } } /* *-------------------------------------------------------------- * * TreeDisplay_ItemDeleted -- * * Removes an item from the hash table of on-screen items. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void TreeDisplay_ItemDeleted( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item to remove. */ ) { TreeDInfo dInfo = tree->dInfo; Tcl_HashEntry *hPtr; hPtr = Tcl_FindHashEntry(&dInfo->itemVisHash, (char *) item); if (hPtr != NULL) { #ifdef DCOLUMN ckfree((char *) Tcl_GetHashValue(hPtr)); #endif Tcl_DeleteHashEntry(hPtr); } hPtr = Tcl_FindHashEntry(&dInfo->headerVisHash, (char *) item); if (hPtr != NULL) { #ifdef DCOLUMN ckfree((char *) Tcl_GetHashValue(hPtr)); #endif Tcl_DeleteHashEntry(hPtr); } } /* *-------------------------------------------------------------- * * TreeDisplay_ColumnDeleted -- * * Removes a column from the list of on-screen columns for * all on-screen items. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void TreeDisplay_ColumnDeleted( TreeCtrl *tree, /* Widget info. */ TreeColumn column /* Column to remove. */ ) { #ifdef DCOLUMN TreeDInfo dInfo = tree->dInfo; Tcl_HashTable *tablePtr = &dInfo->itemVisHash; Tcl_HashSearch search; Tcl_HashEntry *hPtr; TreeColumn *value; int i; hPtr = Tcl_FirstHashEntry(tablePtr, &search); if (hPtr == NULL) { tablePtr = &dInfo->headerVisHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } while (hPtr != NULL) { value = (TreeColumn *) Tcl_GetHashValue(hPtr); if (value == NULL) panic("TreeDisplay_ColumnDeleted value == NULL"); for (i = 0; value[i] != NULL; i++) { if (value[i] == column) { while (value[i] != NULL) { value[i] = value[i + 1]; ++i; } if (tree->debug.enable && tree->debug.span) dbwin("TreeDisplay_ColumnDeleted item %d column %d\n", TreeItem_GetID(tree, (TreeItem) Tcl_GetHashKey( tablePtr, hPtr)), TreeColumn_GetID(column)); break; } } hPtr = Tcl_NextHashEntry(&search); if (hPtr == NULL && tablePtr == &dInfo->itemVisHash) { tablePtr = &dInfo->headerVisHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } } #endif } /* *-------------------------------------------------------------- * * TreeDisplay_FreeColumnDInfo -- * * Free any display info associated with a column when it is * deleted. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void TreeDisplay_FreeColumnDInfo( TreeCtrl *tree, /* Widget info. */ TreeColumn column /* Column info. */ ) { TreeColumnDInfo dColumn = TreeColumn_GetDInfo(column); if (dColumn != NULL) ckfree((char *) dColumn); } /* *-------------------------------------------------------------- * * Tree_ShouldDisplayLockedColumns -- * * Figure out if we are allowed to draw any locked columns. * * Results: * TRUE if locked columns should be displayed, otherwise FALSE. * * Side effects: * None. * *-------------------------------------------------------------- */ int Tree_ShouldDisplayLockedColumns( TreeCtrl *tree /* Widget info. */ ) { if (!tree->vertical) return 0; if (tree->wrapMode != TREE_WRAP_NONE) return 0; Tree_UpdateItemIndex(tree); /* update tree->itemWrapCount */ if (tree->itemWrapCount > 0) return 0; return 1; } /* *-------------------------------------------------------------- * * Tree_DInfoChanged -- * * Set some DINFO_xxx flags and schedule a redisplay. * * Results: * None. * * Side effects: * The widget will be redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_DInfoChanged( TreeCtrl *tree, /* Widget info. */ int flags /* DINFO_xxx flags. */ ) { TreeDInfo dInfo = tree->dInfo; dInfo->flags |= flags; Tree_EventuallyRedraw(tree); } /* *-------------------------------------------------------------- * * Tree_InvalidateArea -- * * Mark as dirty parts of any DItems in the given area. If the given * area overlaps the borders they are marked as needing to be * redrawn. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void Tree_InvalidateArea( TreeCtrl *tree, /* Widget info. */ int x1, int y1, /* Left & top of dirty area in window * coordinates. */ int x2, int y2 /* Right & bottom of dirty area in window * coordinates. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItem; if (x1 >= x2 || y1 >= y2) return; if ((y2 > Tree_HeaderTop(tree)) && (y1 < Tree_HeaderBottom(tree))) { TreeRectangle boundsL, bounds, boundsR; int emptyL, empty, emptyR; dInfo->flags |= DINFO_DRAW_HEADER; emptyL = !Tree_AreaBbox(tree, TREE_AREA_HEADER_LEFT, &boundsL); empty = !Tree_AreaBbox(tree, TREE_AREA_HEADER_NONE, &bounds); emptyR = !Tree_AreaBbox(tree, TREE_AREA_HEADER_RIGHT, &boundsR); dItem = dInfo->dItemHeader; while (dItem != NULL) { if ((!empty && (dItem->area.flags & DITEM_DRAWN)) && !(dItem->area.flags & DITEM_ALL_DIRTY) && (x2 > dItem->area.x) && (x1 < dItem->area.x + dItem->area.width) && (y2 > dItem->y) && (y1 < dItem->y + dItem->height)) { InvalidateDItemX(dItem, &dItem->area, dItem->area.x, x1, x2 - x1); InvalidateDItemY(dItem, &dItem->area, dItem->y, y1, y2 - y1); dItem->area.flags |= DITEM_DIRTY; } if (!emptyL && !(dItem->left.flags & DITEM_ALL_DIRTY) && (x2 > TreeRect_Left(boundsL)) && (x1 < TreeRect_Right(boundsL)) && (y2 > dItem->y) && (y1 < dItem->y + dItem->height)) { InvalidateDItemX(dItem, &dItem->left, dItem->left.x, x1, x2 - x1); InvalidateDItemY(dItem, &dItem->left, dItem->y, y1, y2 - y1); dItem->left.flags |= DITEM_DIRTY; } if (!emptyR && !(dItem->right.flags & DITEM_ALL_DIRTY) && (x2 > TreeRect_Left(boundsR)) && (x1 < TreeRect_Right(boundsR)) && (y2 > dItem->y) && (y1 < dItem->y + dItem->height)) { InvalidateDItemX(dItem, &dItem->right, dItem->right.x, x1, x2 - x1); InvalidateDItemY(dItem, &dItem->right, dItem->y, y1, y2 - y1); dItem->right.flags |= DITEM_DIRTY; } dItem = dItem->next; } } dItem = dInfo->dItem; while (dItem != NULL) { if ((!dInfo->empty && (dItem->area.flags & DITEM_DRAWN)/*dInfo->rangeFirstD != NULL*/) && !(dItem->area.flags & DITEM_ALL_DIRTY) && (x2 > dItem->area.x) && (x1 < dItem->area.x + dItem->area.width) && (y2 > dItem->y) && (y1 < dItem->y + dItem->height)) { InvalidateDItemX(dItem, &dItem->area, dItem->area.x, x1, x2 - x1); InvalidateDItemY(dItem, &dItem->area, dItem->y, y1, y2 - y1); dItem->area.flags |= DITEM_DIRTY; } if (!dInfo->emptyL && !(dItem->left.flags & DITEM_ALL_DIRTY) && (x2 > TreeRect_Left(dInfo->boundsL)) && (x1 < TreeRect_Right(dInfo->boundsL)) && (y2 > dItem->y) && (y1 < dItem->y + dItem->height)) { InvalidateDItemX(dItem, &dItem->left, dItem->left.x, x1, x2 - x1); InvalidateDItemY(dItem, &dItem->left, dItem->y, y1, y2 - y1); dItem->left.flags |= DITEM_DIRTY; } if (!dInfo->emptyR && !(dItem->right.flags & DITEM_ALL_DIRTY) && (x2 > TreeRect_Left(dInfo->boundsR)) && (x1 < TreeRect_Right(dInfo->boundsR)) && (y2 > dItem->y) && (y1 < dItem->y + dItem->height)) { InvalidateDItemX(dItem, &dItem->right, dItem->right.x, x1, x2 - x1); InvalidateDItemY(dItem, &dItem->right, dItem->y, y1, y2 - y1); dItem->right.flags |= DITEM_DIRTY; } dItem = dItem->next; } if ((x1 < Tree_BorderLeft(tree)) || (y1 < Tree_BorderTop(tree)) || (x2 > Tree_BorderRight(tree)) || (y2 > Tree_BorderBottom(tree))) { dInfo->flags |= DINFO_DRAW_HIGHLIGHT; dInfo->flags |= DINFO_DRAW_BORDER; } /* Invalidate part of the whitespace */ InvalidateWhitespace(tree, x1, y1, x2, y2); if (tree->debug.enable && tree->debug.display && tree->debug.eraseColor) { XFillRectangle(tree->display, Tk_WindowId(tree->tkwin), tree->debug.gcErase, x1, y1, x2 - x1, y2 - y1); DisplayDelay(tree); } } /* *-------------------------------------------------------------- * * Tree_InvalidateRegion -- * * Mark as dirty parts of any DItems in the given area. If the given * area overlaps the borders they are marked as needing to be * redrawn. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void Tree_InvalidateRegion( TreeCtrl *tree, /* Widget info. */ TkRegion region /* Region to mark as dirty, in window * coordinates. */ ) { TreeDInfo dInfo = tree->dInfo; DItem *dItem; TreeRectangle rect; int x1, x2, y1, y2; TkRegion rgn; Tree_GetRegionBounds(region, &rect); if (!rect.width || !rect.height) return; /* FIXME: Should do for headers what I do for items, but this code isn't * even called with DOUBLEBUFFER_WINDOW. */ if (Tree_AreaBbox(tree, TREE_AREA_HEADER, &rect) && TkRectInRegion(region, TreeRect_Left(rect), TreeRect_Top(rect), TreeRect_Width(rect), TreeRect_Height(rect)) != RectangleOut) { dInfo->flags |= DINFO_DRAW_HEADER; } rgn = Tree_GetRegion(tree); dItem = dInfo->dItem; while (dItem != NULL) { if ((!dInfo->empty && (dItem->area.flags & DITEM_DRAWN)/*dInfo->rangeFirstD != NULL*/) && !(dItem->area.flags & DITEM_ALL_DIRTY)) { rect.x = dItem->area.x; rect.y = dItem->y; rect.width = dItem->area.width; rect.height = dItem->height; Tree_SetRectRegion(rgn, &rect); TkIntersectRegion(region, rgn, rgn); Tree_GetRegionBounds(rgn, &rect); if (rect.width > 0 && rect.height > 0) { InvalidateDItemX(dItem, &dItem->area, dItem->area.x, rect.x, rect.width); InvalidateDItemY(dItem, &dItem->area, dItem->y, rect.y, rect.height); dItem->area.flags |= DITEM_DIRTY; } } if (!dInfo->emptyL && !(dItem->left.flags & DITEM_ALL_DIRTY)) { rect.x = dItem->left.x; rect.y = dItem->y; rect.width = dItem->left.width; rect.height = dItem->height; Tree_SetRectRegion(rgn, &rect); TkIntersectRegion(region, rgn, rgn); Tree_GetRegionBounds(rgn, &rect); if (rect.width > 0 && rect.height > 0) { InvalidateDItemX(dItem, &dItem->left, dItem->left.x, rect.x, rect.width); InvalidateDItemY(dItem, &dItem->left, dItem->y, rect.y, rect.height); dItem->left.flags |= DITEM_DIRTY; } } if (!dInfo->emptyR && !(dItem->right.flags & DITEM_ALL_DIRTY)) { rect.x = dItem->right.x; rect.y = dItem->y; rect.width = dItem->right.width; rect.height = dItem->height; Tree_SetRectRegion(rgn, &rect); TkIntersectRegion(region, rgn, rgn); Tree_GetRegionBounds(rgn, &rect); if (rect.width > 0 && rect.height > 0) { InvalidateDItemX(dItem, &dItem->right, dItem->right.x, rect.x, rect.width); InvalidateDItemY(dItem, &dItem->right, dItem->y, rect.y, rect.height); dItem->right.flags |= DITEM_DIRTY; } } dItem = dItem->next; } Tree_GetRegionBounds(region, &rect); x1 = rect.x, x2 = rect.x + rect.width; y1 = rect.y, y2 = rect.y + rect.height; if ((x1 < Tree_BorderLeft(tree)) || (y1 < Tree_BorderTop(tree)) || (x2 > Tree_BorderRight(tree)) || (y2 > Tree_BorderBottom(tree))) { dInfo->flags |= DINFO_DRAW_HIGHLIGHT; dInfo->flags |= DINFO_DRAW_BORDER; } /* Invalidate part of the whitespace */ TkSubtractRegion(dInfo->wsRgn, region, dInfo->wsRgn); Tree_FreeRegion(tree, rgn); if (tree->debug.enable && tree->debug.display && tree->debug.eraseColor) { Tree_FillRegion(tree->display, Tk_WindowId(tree->tkwin), tree->debug.gcErase, region); DisplayDelay(tree); } } /* *-------------------------------------------------------------- * * Tree_InvalidateItemArea -- * * Mark as dirty parts of any DItems in the given area. This is * like Tree_InvalidateArea() but the given area is clipped inside * the borders/header. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void Tree_InvalidateItemArea( TreeCtrl *tree, /* Widget info. */ int x1, int y1, /* Left & top of dirty area in window * coordinates. */ int x2, int y2 /* Right & bottom of dirty area in window * coordinates. */ ) { if (x1 < Tree_ContentLeft(tree)) x1 = Tree_ContentLeft(tree); if (y1 < Tree_ContentTop(tree)) y1 = Tree_ContentTop(tree); if (x2 > Tree_ContentRight(tree)) x2 = Tree_ContentRight(tree); if (y2 > Tree_ContentBottom(tree)) y2 = Tree_ContentBottom(tree); Tree_InvalidateArea(tree, x1, y1, x2, y2); } /* *-------------------------------------------------------------- * * Tree_InvalidateItemOnScrollX -- * * Mark an item as needing to be redrawn completely if * the list scrolls horizontally. This is called when a * gradient whose coordinates aren't canvas-relative * is drawn in the item. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void Tree_InvalidateItemOnScrollX( TreeCtrl *tree, /* Widget info. */ TreeItem item ) { DItem *dItem = (DItem *) TreeItem_GetDInfo(tree, item); if ((dItem == NULL) || DItemAllDirty(tree, dItem)) return; dItem->flags |= DITEM_INVALIDATE_ON_SCROLL_X; } /* *-------------------------------------------------------------- * * Tree_InvalidateItemOnScrollY -- * * Mark an item as needing to be redrawn completely if * the list scrolls vertically. This is called when a * gradient whose coordinates aren't canvas-relative * is drawn in the item. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void Tree_InvalidateItemOnScrollY( TreeCtrl *tree, /* Widget info. */ TreeItem item ) { DItem *dItem = (DItem *) TreeItem_GetDInfo(tree, item); if ((dItem == NULL) || DItemAllDirty(tree, dItem)) return; dItem->flags |= DITEM_INVALIDATE_ON_SCROLL_Y; } /* *-------------------------------------------------------------- * * Tree_RedrawArea -- * * Mark as dirty parts of any DItems in the given area. If the given * area overlaps the borders they are marked as needing to be * redrawn. The given area is subtracted from the whitespace region * so that that part of the whitespace region will be redrawn. * * Results: * None. * * Side effects: * The widget will be redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_RedrawArea( TreeCtrl *tree, /* Widget info. */ int x1, int y1, /* Left & top of dirty area in window * coordinates. */ int x2, int y2 /* Right & bottom of dirty area in window * coordinates. */ ) { Tree_InvalidateArea(tree, x1, y1, x2, y2); Tree_EventuallyRedraw(tree); } /* *-------------------------------------------------------------- * * Tree_ExposeArea -- * * Called in response to events. Causes part of the window * to be redisplayed. With "-doublebuffer window", part of the * offscreen pixmap is marked as needing to be copied but no redrawing * of items is done. Without "-doublebuffer window", items will be * redrawn. * * Results: * None. * * Side effects: * The widget will be redisplayed at idle time. * *-------------------------------------------------------------- */ void Tree_ExposeArea( TreeCtrl *tree, /* Widget info. */ int x1, int y1, /* Left & top of dirty area in window * coordinates. */ int x2, int y2 /* Right & bottom of dirty area in window * coordinates. */ ) { TreeDInfo dInfo = tree->dInfo; if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW) { if ((x1 < Tree_BorderLeft(tree)) || (y1 < Tree_BorderTop(tree)) || (x2 > Tree_BorderRight(tree)) || (y2 > Tree_BorderBottom(tree))) { dInfo->flags |= DINFO_DRAW_HIGHLIGHT; dInfo->flags |= DINFO_DRAW_BORDER; Tree_EventuallyRedraw(tree); } if (x1 < Tree_BorderLeft(tree)) x1 = Tree_BorderLeft(tree); if (x2 > Tree_BorderRight(tree)) x2 = Tree_BorderRight(tree); if (y1 < Tree_BorderTop(tree)) y1 = Tree_BorderTop(tree); if (y2 > Tree_BorderBottom(tree)) y2 = Tree_BorderBottom(tree); /* Got some 0,0,0,0 expose events from Windows Tk. */ if (x1 >= x2 || y1 >= y2) return; DblBufWinDirty(tree, x1, y1, x2, y2); if (tree->debug.enable && tree->debug.display && tree->debug.eraseColor) { XFillRectangle(tree->display, Tk_WindowId(tree->tkwin), tree->debug.gcErase, x1, y1, x2 - x1, y2 - y1); DisplayDelay(tree); } } else { Tree_InvalidateArea(tree, x1, y1, x2, y2); } Tree_EventuallyRedraw(tree); } /* *-------------------------------------------------------------- * * TreeDisplay_InitWidget -- * * Perform display-related initialization when a new TreeCtrl is * created. * * Results: * None. * * Side effects: * Memory is allocated. * *-------------------------------------------------------------- */ void TreeDisplay_InitWidget( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo; XGCValues gcValues; dInfo = (TreeDInfo) ckalloc(sizeof(TreeDInfo_)); memset(dInfo, '\0', sizeof(TreeDInfo_)); gcValues.graphics_exposures = True; dInfo->scrollGC = Tk_GetGC(tree->tkwin, GCGraphicsExposures, &gcValues); dInfo->flags = DINFO_OUT_OF_DATE; dInfo->wsRgn = Tree_GetRegion(tree); dInfo->dirtyRgn = TkCreateRegion(); Tcl_InitHashTable(&dInfo->itemVisHash, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&dInfo->headerVisHash, TCL_ONE_WORD_KEYS); #if REDRAW_RGN == 1 dInfo->redrawRgn = TkCreateRegion(); #endif /* REDRAW_RGN */ tree->dInfo = dInfo; } /* *-------------------------------------------------------------- * * TreeDisplay_FreeWidget -- * * Free display-related resources for a deleted TreeCtrl. * * Results: * None. * * Side effects: * Memory is allocated. * *-------------------------------------------------------------- */ void TreeDisplay_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { TreeDInfo dInfo = tree->dInfo; Range *range = dInfo->rangeFirst; Tcl_HashEntry *hPtr; Tcl_HashSearch search; if (dInfo->rItem != NULL) ckfree((char *) dInfo->rItem); if (dInfo->rangeLock != NULL) ckfree((char *) dInfo->rangeLock); while (dInfo->dItem != NULL) { DItem *next = dInfo->dItem->next; WFREE(dInfo->dItem, DItem); dInfo->dItem = next; } while (dInfo->dItemHeader != NULL) { DItem *next = dInfo->dItemHeader->next; WFREE(dInfo->dItem, DItem); dInfo->dItemHeader = next; } while (dInfo->dItemFree != NULL) { DItem *next = dInfo->dItemFree->next; WFREE(dInfo->dItemFree, DItem); dInfo->dItemFree = next; } while (range != NULL) range = Range_Free(tree, range); Tk_FreeGC(tree->display, dInfo->scrollGC); if (dInfo->flags & DINFO_REDRAW_PENDING) Tcl_CancelIdleCall(Tree_Display, (ClientData) tree); if (dInfo->pixmapW.drawable != None) Tk_FreePixmap(tree->display, dInfo->pixmapW.drawable); if (dInfo->pixmapI.drawable != None) Tk_FreePixmap(tree->display, dInfo->pixmapI.drawable); if (dInfo->pixmapT.drawable != None) Tk_FreePixmap(tree->display, dInfo->pixmapT.drawable); #if CACHE_BG_IMG if (dInfo->pixmapBgImg.drawable != None) Tk_FreePixmap(tree->display, dInfo->pixmapBgImg.drawable); #endif if (dInfo->xScrollIncrements.increments != NULL) ckfree((char *) dInfo->xScrollIncrements.increments); if (dInfo->yScrollIncrements.increments != NULL) ckfree((char *) dInfo->yScrollIncrements.increments); Tree_FreeRegion(tree, dInfo->wsRgn); TkDestroyRegion(dInfo->dirtyRgn); #ifdef DCOLUMN hPtr = Tcl_FirstHashEntry(&dInfo->itemVisHash, &search); while (hPtr != NULL) { ckfree((char *) Tcl_GetHashValue(hPtr)); hPtr = Tcl_NextHashEntry(&search); } hPtr = Tcl_FirstHashEntry(&dInfo->headerVisHash, &search); while (hPtr != NULL) { ckfree((char *) Tcl_GetHashValue(hPtr)); hPtr = Tcl_NextHashEntry(&search); } #endif Tcl_DeleteHashTable(&dInfo->itemVisHash); Tcl_DeleteHashTable(&dInfo->headerVisHash); #if REDRAW_RGN == 1 TkDestroyRegion(dInfo->redrawRgn); #endif /* REDRAW_RGN */ WFREE(dInfo, TreeDInfo_); } int Tree_DumpDInfo( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tcl_Interp *interp = tree->interp; TreeDInfo dInfo = tree->dInfo; Tcl_DString dString; DItem *dItem; Range *range; RItem *rItem; int index; static CONST char *optionNames[] = { "alloc", "ditem", "onscreen", "range", (char *) NULL }; #undef DUMP_ALLOC /* [BUG 2233922] SunOS: build error */ enum { DUMP_ALLOC, DUMP_DITEM, DUMP_ONSCREEN, DUMP_RANGE }; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "option"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[3], optionNames, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } Tcl_DStringInit(&dString); if (index == DUMP_ALLOC) { int count = 0, size = 0; for (dItem = dInfo->dItem; dItem != NULL; dItem = dItem->next) { count += 1; } for (dItem = dInfo->dItemFree; dItem != NULL; dItem = dItem->next) { count += 1; } size = count * sizeof(DItem); DStringAppendf(&dString, "%-20s: %8d : %8d B %5d KB\n", "DItem", count, size, (size + 1023) / 1024); count = dInfo->rItemMax; size = count * sizeof(RItem); DStringAppendf(&dString, "%-20s: %8d : %8d B %5d KB\n", "RItem", count, size, (size + 1023) / 1024); } if (index == DUMP_DITEM) { DStringAppendf(&dString, "DumpDInfo: itemW,H %d,%d totalW,H %d,%d flags 0x%0x vertical %d itemVisCount %d\n", dInfo->itemWidth, dInfo->itemHeight, dInfo->totalWidth, dInfo->totalHeight, dInfo->flags, tree->vertical, tree->itemVisCount); DStringAppendf(&dString, " empty=%d bounds=%d,%d,%d,%d\n", dInfo->empty, dInfo->bounds.x, dInfo->bounds.y, TreeRect_Right(dInfo->bounds), TreeRect_Bottom(dInfo->bounds)); DStringAppendf(&dString, " emptyL=%d boundsL=%d,%d,%d,%d\n", dInfo->emptyL, dInfo->boundsL.x, dInfo->boundsL.y, TreeRect_Right(dInfo->boundsL), TreeRect_Bottom(dInfo->boundsL)); DStringAppendf(&dString, " emptyR=%d boundsR=%d,%d,%d,%d\n", dInfo->emptyR, dInfo->boundsR.x, dInfo->boundsR.y, TreeRect_Right(dInfo->boundsR), TreeRect_Bottom(dInfo->boundsR)); dItem = dInfo->dItem; while (dItem != NULL) { if (dItem->item == NULL) { DStringAppendf(&dString, " item NULL\n"); } else { DStringAppendf(&dString, " item %d x,y,w,h %d,%d,%d,%d dirty %d,%d,%d,%d flags %0X\n", TreeItem_GetID(tree, dItem->item), dItem->area.x, dItem->y, dItem->area.width, dItem->height, dItem->area.dirty[LEFT], dItem->area.dirty[TOP], dItem->area.dirty[RIGHT], dItem->area.dirty[BOTTOM], dItem->area.flags); DStringAppendf(&dString, " left: dirty %d,%d,%d,%d flags %0X\n", dItem->left.dirty[LEFT], dItem->left.dirty[TOP], dItem->left.dirty[RIGHT], dItem->left.dirty[BOTTOM], dItem->left.flags); DStringAppendf(&dString, " right: dirty %d,%d,%d,%d flags %0X\n", dItem->right.dirty[LEFT], dItem->right.dirty[TOP], dItem->right.dirty[RIGHT], dItem->right.dirty[BOTTOM], dItem->right.flags); } dItem = dItem->next; } } if (index == DUMP_ONSCREEN) { dItem = dInfo->dItem; while (dItem != NULL) { Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&dInfo->itemVisHash, (char *) dItem->item); TreeColumn *value = (TreeColumn *) Tcl_GetHashValue(hPtr); DStringAppendf(&dString, "item %d:", TreeItem_GetID(tree, dItem->item)); while (*value != NULL) { DStringAppendf(&dString, " %d", TreeColumn_GetID(*value)); ++value; } DStringAppendf(&dString, "\n"); dItem = dItem->next; } } if (index == DUMP_RANGE) { DStringAppendf(&dString, " dInfo.rangeFirstD %p dInfo.rangeLastD %p dInfo.rangeLock %p\n", dInfo->rangeFirstD, dInfo->rangeLastD, dInfo->rangeLock); for (range = dInfo->rangeFirstD ? dInfo->rangeFirstD : dInfo->rangeLock; range != NULL; range = range->next) { DStringAppendf(&dString, " Range: x,y,w,h %d,%d,%d,%d\n", range->offset.x, range->offset.y, range->totalWidth, range->totalHeight); if (range == dInfo->rangeLastD) break; } DStringAppendf(&dString, " dInfo.rangeFirst %p dInfo.rangeLast %p\n", dInfo->rangeFirst, dInfo->rangeLast); for (range = dInfo->rangeFirst; range != NULL; range = range->next) { DStringAppendf(&dString, " Range: first %p last %p x,y,w,h %d,%d,%d,%d\n", range->first, range->last, range->offset.x, range->offset.y, range->totalWidth, range->totalHeight, range->offset); rItem = range->first; while (1) { DStringAppendf(&dString, " RItem: item %d index %d offset %d size %d\n", TreeItem_GetID(tree, rItem->item), rItem->index, rItem->offset, rItem->size); if (rItem == range->last) break; rItem++; } } } Tcl_DStringResult(tree->interp, &dString); return TCL_OK; } tktreectrl-2.4.1/generic/tkTreeDrag.c0000644000076400010400000006750411562306372020050 0ustar TimAdministrators/* * tkTreeDrag.c -- * * This module implements outline dragging for treectrl widgets. * * Copyright (c) 2002-2011 Tim Baker */ #include "tkTreeCtrl.h" typedef struct TreeDragImage_ TreeDragImage_; typedef struct DragElem DragElem; /* * The following structure holds info about a single element of the drag * image. */ struct DragElem { int x, y, width, height; DragElem *next; }; /* * The following structure holds info about the drag image. There is one of * these per TreeCtrl. */ struct TreeDragImage_ { TreeCtrl *tree; Tk_OptionTable optionTable; int visible; int x, y; /* offset to draw at in canvas coords */ TreeRectangle bounds; /* bounds of all DragElems */ DragElem *elem; int onScreen; /* TRUE if is displayed */ int sx, sy; /* Window coords where displayed */ int sw, sh; /* Width/height of previously-displayed image */ #ifdef DRAG_PIXMAP int pixmapW, pixmapH; Pixmap pixmap; Tk_Image image; #endif /* DRAG_PIXMAP */ #ifdef DRAGIMAGE_STYLE TreeStyle masterStyle; /* Style to create the drag image from. */ TreeStyle instanceStyle; /* Style to create the drag image from. */ int styleX, styleY; /* Mouse cursor hotspot offset into dragimage. */ int styleW, styleH; /* Width/Height of dragimage style. */ int pixmapW, pixmapH; /* Width/Height of 'pixmap'. */ Pixmap pixmap; /* Pixmap -> Tk_Image. */ Tk_Image tkimage; /* Transparent image that is drawn in the widget. */ #endif /* DRAGIMAGE_STYLE */ }; #define DRAG_CONF_VISIBLE 0x0001 static Tk_OptionSpec optionSpecs[] = { #ifdef DRAGIMAGE_STYLE {TK_OPTION_CUSTOM, "-style", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeDragImage_, masterStyle), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_style, 0}, #endif /* DRAGIMAGE_STYLE */ {TK_OPTION_BOOLEAN, "-visible", (char *) NULL, (char *) NULL, "0", -1, Tk_Offset(TreeDragImage_, visible), 0, (ClientData) NULL, DRAG_CONF_VISIBLE}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, 0, 0} }; #ifdef DRAG_PIXMAP static void UpdateImage( TreeDragImage dragImage /* Drag image record. */ ) { TreeCtrl *tree = dragImage->tree; Tk_PhotoHandle photoH; XImage *ximage; int width = TreeRect_Width(dragImage->bounds); int height = TreeRect_Height(dragImage->bounds); int alpha = 128; XColor *colorPtr; if (dragImage->image != NULL) { Tk_FreeImage(dragImage->image); dragImage->image = NULL; } photoH = Tk_FindPhoto(tree->interp, "::TreeCtrl::ImageDrag"); if (photoH == NULL) { Tcl_GlobalEval(tree->interp, "image create photo ::TreeCtrl::ImageDrag"); photoH = Tk_FindPhoto(tree->interp, "::TreeCtrl::ImageDrag"); if (photoH == NULL) return; } /* Pixmap -> XImage */ ximage = XGetImage(tree->display, dragImage->pixmap, 0, 0, (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); if (ximage == NULL) panic("tkTreeDrag.c:UpdateImage() ximage is NULL"); /* XImage -> Tk_Image */ colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "pink"); Tree_XImage2Photo(tree->interp, photoH, ximage, colorPtr->pixel, alpha); XDestroyImage(ximage); dragImage->image = Tk_GetImage(tree->interp, tree->tkwin, "::TreeCtrl::ImageDrag", NULL, (ClientData) NULL); } static void UpdatePixmap( TreeDragImage dragImage /* Drag image record. */ ) { TreeCtrl *tree = dragImage->tree; int w, h; XColor *colorPtr; GC gc; DragElem *elem; unsigned long trans; w = TreeRect_Width(dragImage->bounds); h = TreeRect_Height(dragImage->bounds); if (w > dragImage->pixmapW || h > dragImage->pixmapH) { if (dragImage->pixmap != None) Tk_FreePixmap(tree->display, dragImage->pixmap); dragImage->pixmap = Tk_GetPixmap(tree->display, Tk_WindowId(tree->tkwin), w, h, Tk_Depth(tree->tkwin)); dragImage->pixmapW = w; dragImage->pixmapH = h; } colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "pink"); gc = Tk_GCForColor(colorPtr, Tk_WindowId(tree->tkwin)); XFillRectangle(tree->display, dragImage->pixmap, gc, 0, 0, w, h); trans = colorPtr->pixel; colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "gray50"); gc = Tk_GCForColor(colorPtr, Tk_WindowId(tree->tkwin)); for (elem = dragImage->elem; elem != NULL; elem = elem->next) { XFillRectangle(tree->display, dragImage->pixmap, gc, elem->x - TreeRect_Left(dragImage->bounds), elem->y - TreeRect_Top(dragImage->bounds), elem->width, elem->height); } if (dragImage->image != NULL) { Tk_FreeImage(dragImage->image); dragImage->image = NULL; } } static void DrawPixmap( TreeDragImage dragImage, /* Drag image record. */ TreeDrawable td ) { TreeCtrl *tree = dragImage->tree; int ix, iy, iw, ih; if (!dragImage->visible) return; if (dragImage->image == NULL) UpdateImage(dragImage); if (dragImage->image == NULL) return; ix = iy = 0; iw = TreeRect_Width(dragImage->bounds); ih = TreeRect_Height(dragImage->bounds); /* FIXME: clip src image to area to be redrawn */ Tree_RedrawImage(dragImage->image, ix, iy, iw, ih, td, dragImage->x + TreeRect_Left(dragImage->bounds) - tree->drawableXOrigin, dragImage->y + TreeRect_Top(dragImage->bounds) - tree->drawableYOrigin); } #endif /* DRAG_PIXMAP */ #ifdef DRAGIMAGE_STYLE void TreeDragImage_StyleDeleted( TreeDragImage dragImage, /* Drag image record. */ TreeStyle style /* Style that was deleted. */ ) { TreeCtrl *tree = dragImage->tree; if (dragImage->masterStyle == style) { TreeStyle_FreeResources(tree, dragImage->instanceStyle); dragImage->masterStyle = NULL; dragImage->instanceStyle = NULL; } } static void DragImage_UpdateStyleTkImage( TreeDragImage dragImage /* Drag image record. */ ) { TreeCtrl *tree = dragImage->tree; Tk_PhotoHandle photoH; XImage *ximage; int width = dragImage->styleW; int height = dragImage->styleH; int alpha = 128; XColor *colorPtr; if (dragImage->tkimage != NULL) { Tk_FreeImage(dragImage->tkimage); dragImage->tkimage = NULL; } photoH = Tk_FindPhoto(tree->interp, "::TreeCtrl::ImageDrag"); if (photoH == NULL) { Tcl_GlobalEval(tree->interp, "image create photo ::TreeCtrl::ImageDrag"); photoH = Tk_FindPhoto(tree->interp, "::TreeCtrl::ImageDrag"); if (photoH == NULL) return; } /* Pixmap -> XImage */ ximage = XGetImage(tree->display, dragImage->pixmap, 0, 0, (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); if (ximage == NULL) panic("tkTreeDrag.c:DragImage_UpdateStyleTkImage() ximage is NULL"); /* XImage -> Tk_Image */ colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "pink"); Tree_XImage2Photo(tree->interp, photoH, ximage, colorPtr->pixel, alpha); XDestroyImage(ximage); dragImage->tkimage = Tk_GetImage(tree->interp, tree->tkwin, "::TreeCtrl::ImageDrag", NULL, (ClientData) NULL); } static void DragImage_UpdateStylePixmap( TreeDragImage dragImage /* Drag image record. */ ) { TreeCtrl *tree = dragImage->tree; int w, h, state = 0; XColor *colorPtr; GC gc; StyleDrawArgs drawArgs; w = dragImage->styleW = TreeStyle_NeededWidth(tree, dragImage->instanceStyle, state); h = dragImage->styleH = TreeStyle_NeededHeight(tree, dragImage->instanceStyle, state); if (w > dragImage->pixmapW || h > dragImage->pixmapH) { if (dragImage->pixmap != None) Tk_FreePixmap(tree->display, dragImage->pixmap); dragImage->pixmap = Tk_GetPixmap(tree->display, Tk_WindowId(tree->tkwin), w, h, Tk_Depth(tree->tkwin)); dragImage->pixmapW = w; dragImage->pixmapH = h; } colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "pink"); gc = Tk_GCForColor(colorPtr, Tk_WindowId(tree->tkwin)); XFillRectangle(tree->display, dragImage->pixmap, gc, 0, 0, w, h); drawArgs.tree = tree; drawArgs.td.drawable = dragImage->pixmap; drawArgs.td.width = w; drawArgs.td.height = h; drawArgs.bounds[0] = drawArgs.bounds[1] = 0; drawArgs.bounds[2] = w; drawArgs.bounds[3] = h; drawArgs.state = state; drawArgs.style = dragImage->instanceStyle; drawArgs.indent = 0; drawArgs.x = drawArgs.y = 0; drawArgs.width = w; drawArgs.height = h; drawArgs.justify = TK_JUSTIFY_LEFT; TreeStyle_Draw(&drawArgs); if (dragImage->tkimage != NULL) { Tk_FreeImage(dragImage->tkimage); dragImage->tkimage = NULL; } } static void DragImage_DrawStyle( TreeDragImage dragImage, /* Drag image record. */ TreeDrawable td /* Where to draw. */ ) { TreeCtrl *tree = dragImage->tree; int ix, iy, iw, ih; if (dragImage->tkimage == NULL) DragImage_UpdateStyleTkImage(dragImage); if (dragImage->tkimage == NULL) return; ix = iy = 0; iw = dragImage->styleW; ih = dragImage->styleH; Tree_RedrawImage(dragImage->tkimage, ix, iy, iw, ih, td, dragImage->x + -dragImage->styleX - tree->drawableXOrigin, dragImage->y + -dragImage->styleY - tree->drawableYOrigin); } #endif /* DRAGIMAGE_STYLE */ /* *---------------------------------------------------------------------- * * TreeDragImage_Draw -- * * Draw the elements that make up the drag image if it is visible. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void TreeDragImage_Draw( TreeDragImage dragImage, /* Drag image record. */ TreeDrawable td /* Where to draw. */ ) { #ifdef DRAG_PIXMAP DrawPixmap(tree->dragImage, tdrawable); #elif 1 /* Use XOR dotted rectangles where possible. */ TreeCtrl *tree = dragImage->tree; if (!dragImage->visible) return; #ifdef DRAGIMAGE_STYLE if (dragImage->instanceStyle != NULL) { DragImage_DrawStyle(dragImage, td); return; } #endif /* DRAGIMAGE_STYLE */ /* Yes this is XOR drawing but we aren't erasing the previous * dragimage as when TreeDragImage_IsXOR() returns TRUE. */ TreeDragImage_DrawXOR(dragImage, td.drawable, 0 - tree->xOrigin, 0 - tree->yOrigin); #else /* */ TreeCtrl *tree = dragImage->tree; GC gc; DragElem *elem; #if 1 /* Stippled rectangles: BUG not clipped to contentbox. */ XGCValues gcValues; unsigned long mask; XPoint points[5]; if (!dragImage->visible) return; gcValues.stipple = Tk_GetBitmap(tree->interp, tree->tkwin, "gray50"); gcValues.fill_style = FillStippled; mask = GCStipple|GCFillStyle; gc = Tk_GetGC(tree->tkwin, mask, &gcValues); for (elem = dragImage->elem; elem != NULL; elem = elem->next) { XRectangle rect; rect.x = dragImage->x + elem->x /*- dragImage->bounds[0]*/ - tree->drawableXOrigin; rect.y = dragImage->y + elem->y /*- dragImage->bounds[1]*/ - tree->drawableYOrigin; rect.width = elem->width; rect.height = elem->height; #ifdef WIN32 /* XDrawRectangle ignores the stipple pattern. */ points[0].x = rect.x, points[0].y = rect.y; points[1].x = rect.x + rect.width - 1, points[1].y = rect.y; points[2].x = rect.x + rect.width - 1, points[2].y = rect.y + rect.height - 1; points[3].x = rect.x, points[3].y = rect.y + rect.height - 1; points[4] = points[0]; XDrawLines(tree->display, td.drawable, gc, points, 5, CoordModeOrigin); #else /* !WIN32 */ XDrawRectangle(tree->display, td.drawable, gc, rect.x, rect.y, rect.width - 1, rect.height - 1); #endif } Tk_FreeGC(tree->display, gc); #else /* Debug/test: gray rectangles */ XColor *colorPtr; TkRegion rgn; if (!dragImage->visible) return; colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "gray50"); gc = Tk_GCForColor(colorPtr, Tk_WindowId(tree->tkwin)); rgn = Tree_GetRegion(tree); for (elem = dragImage->elem; elem != NULL; elem = elem->next) { XRectangle rect; rect.x = dragImage->x + elem->x /*- dragImage->bounds[0]*/ - tree->drawableXOrigin; rect.y = dragImage->y + elem->y /*- dragImage->bounds[1]*/ - tree->drawableYOrigin; rect.width = elem->width; rect.height = elem->height; TkUnionRectWithRegion(&rect, rgn, rgn); } Tree_FillRegion(tree->display, td.drawable, gc, rgn); Tree_FreeRegion(tree, rgn); #endif /* Debug/test: gray rectangles */ #endif /* XOR */ } /* *---------------------------------------------------------------------- * * DragElem_Alloc -- * * Allocate and initialize a new DragElem record. Add the record * to the list of records for the drag image. * * Results: * Pointer to allocated DragElem. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ static DragElem * DragElem_Alloc( TreeDragImage dragImage /* Drag image record. */ ) { DragElem *elem = (DragElem *) ckalloc(sizeof(DragElem)); DragElem *walk = dragImage->elem; memset(elem, '\0', sizeof(DragElem)); if (dragImage->elem == NULL) dragImage->elem = elem; else { while (walk->next != NULL) walk = walk->next; walk->next = elem; } return elem; } /* *---------------------------------------------------------------------- * * DragElem_Free -- * * Free a DragElem. * * Results: * Pointer to the next DragElem. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ static DragElem * DragElem_Free( TreeDragImage dragImage, /* Drag image record. */ DragElem *elem /* Drag element to free. */ ) { DragElem *next = elem->next; WFREE(elem, DragElem); return next; } /* *---------------------------------------------------------------------- * * TreeDragImage_InitWidget -- * * Perform drag-image-related initialization when a new TreeCtrl is * created. * * Results: * A standard Tcl result. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ int TreeDragImage_InitWidget( TreeCtrl *tree /* Widget info. */ ) { TreeDragImage dragImage; dragImage = (TreeDragImage) ckalloc(sizeof(TreeDragImage_)); memset(dragImage, '\0', sizeof(TreeDragImage_)); dragImage->tree = tree; dragImage->optionTable = Tk_CreateOptionTable(tree->interp, optionSpecs); if (Tk_InitOptions(tree->interp, (char *) dragImage, dragImage->optionTable, tree->tkwin) != TCL_OK) { WFREE(dragImage, TreeDragImage_); return TCL_ERROR; } tree->dragImage = (TreeDragImage) dragImage; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeDragImage_FreeWidget -- * * Free drag-image-related resources when a TreeCtrl is deleted. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ void TreeDragImage_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { TreeDragImage dragImage = tree->dragImage; DragElem *elem = dragImage->elem; while (elem != NULL) elem = DragElem_Free(dragImage, elem); #ifdef DRAG_PIXMAP if (dragImage->image != NULL) Tk_FreeImage(dragImage->image); if (dragImage->pixmap != None) Tk_FreePixmap(dragImage->tree->display, dragImage->pixmap); #endif /* DRAG_PIXMAP */ Tk_FreeConfigOptions((char *) dragImage, dragImage->optionTable, dragImage->tree->tkwin); WFREE(dragImage, TreeDragImage_); } /* *---------------------------------------------------------------------- * * TreeDragImage_IsXOR -- * * Return true if the dragimage is being drawn with XOR. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeDragImage_IsXOR( TreeDragImage dragImage /* Drag image token. */ ) { #if defined(WIN32) return FALSE; /* TRUE on XP, FALSE on Win7 (lots of flickering) */ #elif defined(MAC_OSX_TK) return FALSE; /* Cocoa doesn't have XOR */ #else /* X11 */ /* With VirtualBox+Ubuntu get extreme lag if TRUE with Compiz. */ /* With VirtualBox+Ubuntu get lots of flickering if TRUE without Compiz. */ return FALSE; #endif } /* *---------------------------------------------------------------------- * * TreeDragImage_IsVisible -- * * Return true if the dragimage is being drawn. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeDragImage_IsVisible( TreeDragImage dragImage /* Drag image token. */ ) { return dragImage->visible; } /* *---------------------------------------------------------------------- * * TreeDragImage_Display -- * * Draw the drag image if it is not already displayed and if * it's -visible option is TRUE. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void TreeDragImage_Display( TreeDragImage dragImage /* Drag image token. */ ) { TreeCtrl *tree = dragImage->tree; if (!dragImage->onScreen && dragImage->visible) { if (TreeDragImage_IsXOR(dragImage) == FALSE) { dragImage->sx = dragImage->x + TreeRect_Left(dragImage->bounds) - tree->xOrigin; dragImage->sy = dragImage->y + TreeRect_Top(dragImage->bounds) - tree->yOrigin; dragImage->sw = TreeRect_Width(dragImage->bounds); dragImage->sh = TreeRect_Height(dragImage->bounds); /* Tree_InvalidateItemArea(tree, dragImage->sx, dragImage->sy, dragImage->sx + dragImage->sw, dragImage->sy + dragImage->sh);*/ Tree_EventuallyRedraw(tree); } else { dragImage->sx = 0 - tree->xOrigin; dragImage->sy = 0 - tree->yOrigin; TreeDragImage_DrawXOR(dragImage, Tk_WindowId(tree->tkwin), dragImage->sx, dragImage->sy); } dragImage->onScreen = TRUE; } } /* *---------------------------------------------------------------------- * * TreeDragImage_Undisplay -- * * Erase the drag image if it is displayed. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void TreeDragImage_Undisplay( TreeDragImage dragImage /* Drag image token. */ ) { TreeCtrl *tree = dragImage->tree; if (dragImage->onScreen) { if (TreeDragImage_IsXOR(dragImage) == FALSE) { /* Tree_InvalidateItemArea(tree, dragImage->sx, dragImage->sy, dragImage->sx + dragImage->sw, dragImage->sy + dragImage->sh);*/ Tree_EventuallyRedraw(tree); } else { TreeDragImage_DrawXOR(dragImage, Tk_WindowId(tree->tkwin), dragImage->sx, dragImage->sy); } dragImage->onScreen = FALSE; } } /* *---------------------------------------------------------------------- * * DragImage_Config -- * * This procedure is called to process an objc/objv list to set * configuration options for a DragImage. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then an error message is left in interp's result. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for dragImage; old resources get freed, if there * were any. Display changes may occur. * *---------------------------------------------------------------------- */ static int DragImage_Config( TreeDragImage dragImage, /* Drag image record. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = dragImage->tree; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; int mask; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tk_SetOptions(tree->interp, (char *) dragImage, dragImage->optionTable, objc, objv, tree->tkwin, &savedOptions, &mask) != TCL_OK) { mask = 0; continue; } /* xxx */ Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); /* xxx */ Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } if (mask & DRAG_CONF_VISIBLE) { TreeDragImage_Undisplay((TreeDragImage) dragImage); TreeDragImage_Display((TreeDragImage) dragImage); } #ifdef DRAGIMAGE_STYLE if (dragImage->instanceStyle != NULL) { TreeStyle_FreeResources(tree, dragImage->instanceStyle); dragImage->instanceStyle = NULL; } if (dragImage->masterStyle != NULL) { dragImage->instanceStyle = TreeStyle_NewInstance(tree, dragImage->masterStyle); DragImage_UpdateStylePixmap(dragImage); } #endif /* DRAGIMAGE_STYLE */ return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeDragImage_DrawXOR -- * * Draw (or erase) the elements that make up the drag image. * * Results: * None. * * Side effects: * Stuff is drawn (or erased, since this is XOR drawing). * *---------------------------------------------------------------------- */ void TreeDragImage_DrawXOR( TreeDragImage dragImage, /* Drag image record. */ Drawable drawable, /* Where to draw. */ int xOffset, /* Offset of the drawable from the top-left */ int yOffset /* of the canvas. */ ) { TreeCtrl *tree = dragImage->tree; DragElem *elem = dragImage->elem; DotState dotState; /* if (!dragImage->visible) return; */ if (elem == NULL) return; TreeDotRect_Setup(tree, drawable, &dotState); while (elem != NULL) { TreeDotRect_Draw(&dotState, xOffset + dragImage->x + elem->x, yOffset + dragImage->y + elem->y, elem->width, elem->height); elem = elem->next; } TreeDotRect_Restore(&dotState); } /* *---------------------------------------------------------------------- * * TreeDragImageCmd -- * * This procedure is invoked to process the [dragimage] widget * command. See the user documentation for details on what it * does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeDragImageCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; TreeDragImage dragImage = tree->dragImage; static CONST char *commandNames[] = { "add", "cget", "clear", "configure", "offset", #ifdef DRAGIMAGE_STYLE "stylehotspot", #endif /* DRAGIMAGE_STYLE */ (char *) NULL }; enum { COMMAND_ADD, COMMAND_CGET, COMMAND_CLEAR, COMMAND_CONFIGURE, COMMAND_OFFSET #ifdef DRAGIMAGE_STYLE , COMMAND_STYLEHOTSPOT #endif /* DRAGIMAGE_STYLE */ }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { /* T dragimage add I ?C? ?E ...? */ case COMMAND_ADD: { TreeItem item; TreeItemColumn itemColumn; TreeColumn treeColumn; TreeRectangle rects[128]; DragElem *elem; int i, count, result = TCL_OK; int minX, minY, maxX, maxY; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "item ?column? ?element ...?"); return TCL_ERROR; } if (TreeItem_FromObj(tree, objv[3], &item, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; TreeDragImage_Undisplay(tree->dragImage); /* Every element in every column. */ if (objc == 4) { treeColumn = tree->columns; itemColumn = TreeItem_GetFirstColumn(tree, item); while (itemColumn != NULL) { if (TreeItemColumn_GetStyle(tree, itemColumn) != NULL) { count = TreeItem_GetRects(tree, item, treeColumn, -1, NULL, rects); if (count == -1) { result = TCL_ERROR; goto doneADD; } for (i = 0; i < count; i++) { elem = DragElem_Alloc(dragImage); elem->x = rects[i].x; elem->y = rects[i].y; elem->width = rects[i].width; elem->height = rects[i].height; } } treeColumn = TreeColumn_Next(treeColumn); itemColumn = TreeItemColumn_GetNext(tree, itemColumn); } } else { if (TreeColumn_FromObj(tree, objv[4], &treeColumn, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) { result = TCL_ERROR; goto doneADD; } /* Every element in a column. */ if (objc == 5) { objc = -1; objv = NULL; /* List of elements in a column. */ } else { objc -= 5; objv += 5; } count = TreeItem_GetRects(tree, item, treeColumn, objc, objv, rects); if (count == -1) { result = TCL_ERROR; goto doneADD; } for (i = 0; i < count; i++) { elem = DragElem_Alloc(dragImage); elem->x = rects[i].x; elem->y = rects[i].y; elem->width = rects[i].width; elem->height = rects[i].height; } } doneADD: minX = 100000; minY = 100000; maxX = -100000; maxY = -100000; for (elem = dragImage->elem; elem != NULL; elem = elem->next) { if (elem->x < minX) minX = elem->x; if (elem->y < minY) minY = elem->y; if (elem->x + elem->width > maxX) maxX = elem->x + elem->width; if (elem->y + elem->height > maxY) maxY = elem->y + elem->height; } TreeRect_SetXYXY(dragImage->bounds, minX, minY, maxX, maxY); #ifdef DRAG_PIXMAP UpdatePixmap(dragImage); #endif /* DRAG_PIXMAP */ TreeDragImage_Display(tree->dragImage); return result; } /* T dragimage cget option */ case COMMAND_CGET: { Tcl_Obj *resultObjPtr; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "option"); return TCL_ERROR; } resultObjPtr = Tk_GetOptionValue(interp, (char *) dragImage, dragImage->optionTable, objv[3], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } /* T dragimage clear */ case COMMAND_CLEAR: { if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL); return TCL_ERROR; } if (dragImage->elem != NULL) { DragElem *elem = dragImage->elem; TreeDragImage_Undisplay(tree->dragImage); /* if (dragImage->visible) DragImage_Redraw(dragImage); */ while (elem != NULL) elem = DragElem_Free(dragImage, elem); dragImage->elem = NULL; } break; } /* T dragimage configure ?option? ?value? ?option value ...? */ case COMMAND_CONFIGURE: { Tcl_Obj *resultObjPtr; if (objc < 3) { Tcl_WrongNumArgs(interp, 3, objv, "?option? ?value?"); return TCL_ERROR; } if (objc <= 4) { resultObjPtr = Tk_GetOptionInfo(interp, (char *) dragImage, dragImage->optionTable, (objc == 3) ? (Tcl_Obj *) NULL : objv[3], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } return DragImage_Config(dragImage, objc - 3, objv + 3); } /* T dragimage offset ?x y? */ case COMMAND_OFFSET: { int x, y; if (objc != 3 && objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "?x y?"); return TCL_ERROR; } if (objc == 3) { FormatResult(interp, "%d %d", dragImage->x, dragImage->y); break; } if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) return TCL_ERROR; TreeDragImage_Undisplay(tree->dragImage); /* if (dragImage->visible) DragImage_Redraw(dragImage); */ dragImage->x = x; dragImage->y = y; TreeDragImage_Display(tree->dragImage); break; } #ifdef DRAGIMAGE_STYLE /* T dragimage stylehotspot ?x y? */ case COMMAND_STYLEHOTSPOT: { int x, y; if (objc != 3 && objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "?x y?"); return TCL_ERROR; } if (objc == 3) { FormatResult(interp, "%d %d", dragImage->styleX, dragImage->styleY); break; } if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) return TCL_ERROR; TreeDragImage_Undisplay(tree->dragImage); dragImage->styleX = x; dragImage->styleY = y; TreeDragImage_Display(tree->dragImage); break; } #endif /* DRAGIMAGE_STYLE */ } return TCL_OK; } tktreectrl-2.4.1/generic/tkTreeElem.c0000644000076400010400000047674311565571776020105 0ustar TimAdministrators/* * tkTreeElem.c -- * * This module implements elements for treectrl widgets. * * Copyright (c) 2002-2011 Tim Baker */ #include "tkTreeCtrl.h" #include "tkTreeElem.h" /* When a column header is in the pressed state, any bitmap, image, and text * elements are offset by 1,1. */ #define HEADER_OFFSET_HACK 1 /* *---------------------------------------------------------------------- * * DO_BooleanForState -- * DO_ColorForState -- * DO_FontForState -- * * Returns the value of a per-state option for an element. * * Results: * If the element has the dynamic option allocated, then the * per-state info is checked for a match. If an exact match for * the given state is not found, and if the element is an instance * (not a master), then the master element is checked. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int DO_BooleanForState( TreeCtrl *tree, /* Widget info. */ TreeElement elem, /* Element to examine. */ int id, /* Unique id of dynamic option. */ int state /* STATE_xxx flags. */ ) { int result = -1; PerStateInfo *psi; int match = MATCH_NONE; psi = DynamicOption_FindData(elem->options, id); if (psi != NULL) result = PerStateBoolean_ForState(tree, psi, state, &match); if ((match != MATCH_EXACT) && (elem->master != NULL)) { PerStateInfo *psi = DynamicOption_FindData(elem->master->options, id); if (psi != NULL) { int matchM; int resultM = PerStateBoolean_ForState(tree, psi, state, &matchM); if (matchM > match) result = resultM; } } return result; } static TreeColor * DO_ColorForState( TreeCtrl *tree, TreeElement elem, int id, int state ) { TreeColor *result = NULL; PerStateInfo *psi; int match = MATCH_NONE; psi = DynamicOption_FindData(elem->options, id); if (psi != NULL) result = PerStateColor_ForState(tree, psi, state, &match); if ((match != MATCH_EXACT) && (elem->master != NULL)) { PerStateInfo *psi = DynamicOption_FindData(elem->master->options, id); if (psi != NULL) { int matchM; TreeColor *resultM = PerStateColor_ForState(tree, psi, state, &matchM); if (matchM > match) result = resultM; } } return result; } static Tk_Font DO_FontForState( TreeCtrl *tree, TreeElement elem, int id, int state ) { Tk_Font result = NULL; PerStateInfo *psi; int match = MATCH_NONE; psi = DynamicOption_FindData(elem->options, id); if (psi != NULL) result = PerStateFont_ForState(tree, psi, state, &match); if ((match != MATCH_EXACT) && (elem->master != NULL)) { PerStateInfo *psi = DynamicOption_FindData(elem->master->options, id); if (psi != NULL) { int matchM; Tk_Font resultM = PerStateFont_ForState(tree, psi, state, &matchM); if (matchM > match) result = resultM; } } return result; } /* *---------------------------------------------------------------------- * * DO_ObjectForState -- * * Returns the object representation of a per-state option * for an element. * * Results: * If the element has the dynamic option allocated, then the * per-state info is checked for a match. If an exact match for * the given state is not found, and if the element is an instance * (not a master), then the master element is checked. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tcl_Obj * DO_ObjectForState( TreeCtrl *tree, /* Widget info. */ PerStateType *typePtr, /* Type-specific functions and values. */ TreeElement elem, /* Element to examine. */ int id, /* Unique id of dynamic option. */ int state /* STATE_xxx flags. */ ) { Tcl_Obj *result = NULL; PerStateInfo *psi; int match = MATCH_NONE; psi = DynamicOption_FindData(elem->options, id); if (psi != NULL) result = PerStateInfo_ObjForState(tree, typePtr, psi, state, &match); if ((match != MATCH_EXACT) && (elem->master != NULL)) { PerStateInfo *psi = DynamicOption_FindData(elem->master->options, id); if (psi != NULL) { int matchM; Tcl_Obj *resultM = PerStateInfo_ObjForState(tree, typePtr, psi, state, &matchM); if (matchM > match) result = resultM; } } return result; } /* BEGIN custom "boolean" option */ /* Just like TK_OPTION_BOOLEAN but supports TK_OPTION_NULL_OK */ /* Internal value is -1 for no-such-value */ static int BooleanSet( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags) { int objEmpty; int new, *internalPtr; if (internalOffset >= 0) internalPtr = (int *) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*value)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) (*value) = NULL; else { if (Tcl_GetBooleanFromObj(interp, (*value), &new) != TCL_OK) return TCL_ERROR; } if (internalPtr != NULL) { if ((*value) == NULL) new = -1; *((int *) saveInternalPtr) = *internalPtr; *internalPtr = new; } return TCL_OK; } static Tcl_Obj *BooleanGet( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset) { int value = *(int *) (recordPtr + internalOffset); if (value == -1) return NULL; return Tcl_NewBooleanObj(value); } static void BooleanRestore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr) { *(int *) internalPtr = *(int *) saveInternalPtr; } static Tk_ObjCustomOption booleanCO = { "boolean", BooleanSet, BooleanGet, BooleanRestore, NULL, (ClientData) NULL }; static void DynamicOptionInitBoolean( void *data ) { *((int *) data) = -1; } /* END custom "boolean" option */ /* BEGIN custom "integer" option */ /* Just like TK_OPTION_INT but supports TK_OPTION_NULL_OK and bounds checking */ typedef struct IntegerClientData { int min; int max; int empty; /* internal form if empty */ int flags; /* 0x01 - use min, 0x02 - use max */ } IntegerClientData; static int IntegerSet( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags) { IntegerClientData *cd = clientData; int objEmpty; int new, *internalPtr; if (internalOffset >= 0) internalPtr = (int *) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*value)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) (*value) = NULL; else { if (Tcl_GetIntFromObj(interp, (*value), &new) != TCL_OK) return TCL_ERROR; if ((cd->flags & 0x01) && (new < cd->min)) { FormatResult(interp, "bad integer value \"%d\": must be >= %d", new, cd->min); return TCL_ERROR; } if ((cd->flags & 0x02) && (new > cd->max)) { FormatResult(interp, "bad integer value \"%d\": must be <= %d", new, cd->max); return TCL_ERROR; } } if (internalPtr != NULL) { if ((*value) == NULL) new = cd->empty; *((int *) saveInternalPtr) = *internalPtr; *internalPtr = new; } return TCL_OK; } static Tcl_Obj *IntegerGet( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset) { IntegerClientData *cd = clientData; int value = *(int *) (recordPtr + internalOffset); if (value == cd->empty) return NULL; return Tcl_NewIntObj(value); } static void IntegerRestore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr) { *(int *) internalPtr = *(int *) saveInternalPtr; } /* END custom "integer" option */ /*****/ /* BEGIN custom "stringtable" option */ /* Just like TK_OPTION_STRING_TABLE but supports TK_OPTION_NULL_OK */ /* The integer rep is -1 if empty string specified */ typedef struct StringTableClientData { CONST char **tablePtr; /* NULL-termintated list of strings */ CONST char *msg; /* Tcl_GetIndexFromObj() message */ } StringTableClientData; static int StringTableSet( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags) { StringTableClientData *cd = clientData; int objEmpty; int new, *internalPtr; if (internalOffset >= 0) internalPtr = (int *) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*value)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) (*value) = NULL; else { if (Tcl_GetIndexFromObj(interp, (*value), cd->tablePtr, cd->msg, 0, &new) != TCL_OK) return TCL_ERROR; } if (internalPtr != NULL) { if ((*value) == NULL) new = -1; *((int *) saveInternalPtr) = *internalPtr; *internalPtr = new; } return TCL_OK; } static Tcl_Obj *StringTableGet( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset) { StringTableClientData *cd = clientData; int index = *(int *) (recordPtr + internalOffset); if (index == -1) return NULL; return Tcl_NewStringObj(cd->tablePtr[index], -1); } static void StringTableRestore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr) { *(int *) internalPtr = *(int *) saveInternalPtr; } /* END custom "stringtable" option */ static int BooleanCO_Init( Tk_OptionSpec *optionTable, CONST char *optionName) { Tk_OptionSpec *specPtr; specPtr = Tree_FindOptionSpec(optionTable, optionName); specPtr->clientData = &booleanCO; return TCL_OK; } static Tk_ObjCustomOption * IntegerCO_Alloc( CONST char *optionName, int min, int max, int empty, int flags ) { IntegerClientData *cd; Tk_ObjCustomOption *co; /* ClientData for the Tk custom option record */ cd = (IntegerClientData *) ckalloc(sizeof(IntegerClientData)); cd->min = min; cd->max = max; cd->empty = empty; cd->flags = flags; /* The Tk custom option record */ co = (Tk_ObjCustomOption *) ckalloc(sizeof(Tk_ObjCustomOption)); co->name = (char *) optionName + 1; co->setProc = IntegerSet; co->getProc = IntegerGet; co->restoreProc = IntegerRestore; co->freeProc = NULL; co->clientData = (ClientData) cd; return co; } #if 0 /* UNUSED, keep but shutup compiler warning */ static int IntegerCO_Init( Tk_OptionSpec *optionTable, CONST char *optionName, int min, int max, int empty, int flags ) { Tk_OptionSpec *specPtr; specPtr = Tree_FindOptionSpec(optionTable, optionName); if (specPtr->type != TK_OPTION_CUSTOM) panic("IntegerCO_Init: %s is not TK_OPTION_CUSTOM", optionName); if (specPtr->clientData != NULL) return TCL_OK; specPtr->clientData = IntegerCO_Alloc(optionName, min, max, empty, flags); return TCL_OK; } #endif static Tk_ObjCustomOption * StringTableCO_Alloc( CONST char *optionName, CONST char **tablePtr ) { StringTableClientData *cd; Tk_ObjCustomOption *co; /* ClientData for the Tk custom option record */ cd = (StringTableClientData *) ckalloc(sizeof(StringTableClientData)); cd->tablePtr = tablePtr; cd->msg = optionName + 1; /* The Tk custom option record */ co = (Tk_ObjCustomOption *) ckalloc(sizeof(Tk_ObjCustomOption)); co->name = (char *) optionName + 1; co->setProc = StringTableSet; co->getProc = StringTableGet; co->restoreProc = StringTableRestore; co->freeProc = NULL; co->clientData = (ClientData) cd; return co; } int StringTableCO_Init(Tk_OptionSpec *optionTable, CONST char *optionName, CONST char **tablePtr) { Tk_OptionSpec *specPtr; specPtr = Tree_FindOptionSpec(optionTable, optionName); if (specPtr->type != TK_OPTION_CUSTOM) panic("StringTableCO_Init: %s is not TK_OPTION_CUSTOM", optionName); if (specPtr->clientData != NULL) return TCL_OK; specPtr->clientData = StringTableCO_Alloc(optionName, tablePtr); return TCL_OK; } /*****/ int TreeStateFromObj(TreeCtrl *tree, int domain, Tcl_Obj *obj, int *stateOff, int *stateOn) { int states[3]; states[STATE_OP_ON] = states[STATE_OP_OFF] = states[STATE_OP_TOGGLE] = 0; if (Tree_StateFromObj(tree, domain, obj, states, NULL, SFO_NOT_TOGGLE) != TCL_OK) return TCL_ERROR; (*stateOn) |= states[STATE_OP_ON]; (*stateOff) |= states[STATE_OP_OFF]; return TCL_OK; } static void AdjustForSticky(int sticky, int cavityWidth, int cavityHeight, int expandX, int expandY, int *xPtr, int *yPtr, int *widthPtr, int *heightPtr) { int dx = 0; int dy = 0; if (cavityWidth > *widthPtr) { dx = cavityWidth - *widthPtr; } if (cavityHeight > *heightPtr) { dy = cavityHeight - *heightPtr; } if ((sticky & STICKY_W) && (sticky & STICKY_E)) { if (expandX) *widthPtr += dx; else sticky &= ~(STICKY_W | STICKY_E); } if ((sticky & STICKY_N) && (sticky & STICKY_S)) { if (expandY) *heightPtr += dy; else sticky &= ~(STICKY_N | STICKY_S); } if (!(sticky & STICKY_W)) { *xPtr += (sticky & STICKY_E) ? dx : dx / 2; } if (!(sticky & STICKY_N)) { *yPtr += (sticky & STICKY_S) ? dy : dy / 2; } } #define DO_COLOR_FOR_STATE(xVAR,xID,xSTATE) \ { \ TreeColor *tc = DO_ColorForState(tree, elem, xID, xSTATE); \ xVAR = (tc != NULL) ? tc->color : NULL; \ } /* This macro gets the value of a per-state option for an element, then * looks for a better match from the master element if it exists */ #define OPTION_FOR_STATE(xFUNC,xTYPE,xVAR,xFIELD,xSTATE) \ xVAR = xFUNC(tree, &elemX->xFIELD, xSTATE, &match); \ if ((match != MATCH_EXACT) && (masterX != NULL)) { \ xTYPE varM = xFUNC(tree, &masterX->xFIELD, xSTATE, &match2); \ if (match2 > match) \ xVAR = varM; \ } #define BITMAP_FOR_STATE(xVAR,xFIELD,xSTATE) \ OPTION_FOR_STATE(PerStateBitmap_ForState,Pixmap,xVAR,xFIELD,xSTATE) #define BOOLEAN_FOR_STATE(xVAR,xFIELD,xSTATE) \ OPTION_FOR_STATE(PerStateBoolean_ForState,int,xVAR,xFIELD,xSTATE) #define BORDER_FOR_STATE(xVAR,xFIELD,xSTATE) \ OPTION_FOR_STATE(PerStateBorder_ForState,Tk_3DBorder,xVAR,xFIELD,xSTATE) #define COLOR_FOR_STATE(xVAR,xFIELD,xSTATE) \ { \ TreeColor *tc; \ OPTION_FOR_STATE(PerStateColor_ForState,TreeColor*,tc,xFIELD,xSTATE) \ xVAR = (tc != NULL) ? tc->color : NULL; \ } #define TREECOLOR_FOR_STATE(xVAR,xFIELD,xSTATE) \ OPTION_FOR_STATE(PerStateColor_ForState,TreeColor*,xVAR,xFIELD,xSTATE) #define FLAGS_FOR_STATE(xVAR,xFIELD,xSTATE) \ OPTION_FOR_STATE(PerStateFlags_ForState,int,xVAR,xFIELD,xSTATE) #define FONT_FOR_STATE(xVAR,xFIELD,xSTATE) \ OPTION_FOR_STATE(PerStateFont_ForState,Tk_Font,xVAR,xFIELD,xSTATE) #define GRADIENT_FOR_STATE(xVAR,xFIELD,xSTATE) \ OPTION_FOR_STATE(PerStateGradient_ForState,TreeGradient,xVAR,xFIELD,xSTATE) #define IMAGE_FOR_STATE(xVAR,xFIELD,xSTATE) \ OPTION_FOR_STATE(PerStateImage_ForState,Tk_Image,xVAR,xFIELD,xSTATE) #define RELIEF_FOR_STATE(xVAR,xFIELD,xSTATE) \ OPTION_FOR_STATE(PerStateRelief_ForState,int,xVAR,xFIELD,xSTATE) /* This macro gets the object for a per-state option for an element, then * looks for a better match from the master element if it exists */ #define OBJECT_FOR_STATE(xVAR,xTYPE,xFIELD,xSTATE) \ xVAR = PerStateInfo_ObjForState(tree, &xTYPE, &elemX->xFIELD, xSTATE, &match); \ if ((match != MATCH_EXACT) && (masterX != NULL)) { \ Tcl_Obj *objM = PerStateInfo_ObjForState(tree, &xTYPE, &masterX->xFIELD, xSTATE, &matchM); \ if (matchM > match) \ xVAR = objM; \ } /*****/ typedef struct ElementBitmap ElementBitmap; struct ElementBitmap { TreeElement_ header; #ifdef DEPRECATED PerStateInfo draw; #endif PerStateInfo bitmap; PerStateInfo fg; PerStateInfo bg; }; #define BITMAP_CONF_BITMAP 0x0001 #define BITMAP_CONF_FG 0x0002 #define BITMAP_CONF_BG 0x0004 #ifdef DEPRECATED #define BITMAP_CONF_DRAW 0x0008 #endif static Tk_OptionSpec bitmapOptionSpecs[] = { {TK_OPTION_CUSTOM, "-background", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementBitmap, bg.obj), Tk_Offset(ElementBitmap, bg), TK_OPTION_NULL_OK, (ClientData) NULL, BITMAP_CONF_BG}, {TK_OPTION_CUSTOM, "-bitmap", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementBitmap, bitmap.obj), Tk_Offset(ElementBitmap, bitmap), TK_OPTION_NULL_OK, (ClientData) NULL, BITMAP_CONF_BITMAP}, #ifdef DEPRECATED {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementBitmap, draw.obj), Tk_Offset(ElementBitmap, draw), TK_OPTION_NULL_OK, (ClientData) NULL, BITMAP_CONF_DRAW}, #endif {TK_OPTION_CUSTOM, "-foreground", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementBitmap, fg.obj), Tk_Offset(ElementBitmap, fg), TK_OPTION_NULL_OK, (ClientData) NULL, BITMAP_CONF_FG}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} }; static void DeleteProcBitmap(TreeElementArgs *args) { /* TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBitmap *elemX = (ElementBitmap *) elem;*/ } static int WorldChangedProcBitmap(TreeElementArgs *args) { int flagM = args->change.flagMaster; int flagS = args->change.flagSelf; int mask = 0; if ((flagS | flagM) & BITMAP_CONF_BITMAP) mask |= CS_DISPLAY | CS_LAYOUT; if ((flagS | flagM) & ( #ifdef DEPRECATED BITMAP_CONF_DRAW | #endif BITMAP_CONF_FG | BITMAP_CONF_BG)) mask |= CS_DISPLAY; return mask; } static int ConfigProcBitmap(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBitmap *elemX = (ElementBitmap *) elem; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, elem->stateDomain, elemX, elem->typePtr->optionTable, args->config.objc, args->config.objv, &savedOptions, &args->config.flagSelf) != TCL_OK) { args->config.flagSelf = 0; continue; } Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } return TCL_OK; } static int CreateProcBitmap(TreeElementArgs *args) { return TCL_OK; } static void DisplayProcBitmap(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBitmap *elemX = (ElementBitmap *) elem; ElementBitmap *masterX = (ElementBitmap *) elem->master; int state = args->state; int x = args->display.x, y = args->display.y; int width, height; int match, match2; #ifdef DEPRECATED int draw; #endif Pixmap bitmap; XColor *fg, *bg; int imgW, imgH; int inHeader = elem->stateDomain == STATE_DOMAIN_HEADER; int columnState = COLUMN_STATE_NORMAL; #ifdef DEPRECATED BOOLEAN_FOR_STATE(draw, draw, state) if (!draw) return; #endif BITMAP_FOR_STATE(bitmap, bitmap, state) if (bitmap == None) return; COLOR_FOR_STATE(fg, fg, state) COLOR_FOR_STATE(bg, bg, state) Tk_SizeOfBitmap(tree->display, bitmap, &imgW, &imgH); width = imgW, height = imgH; AdjustForSticky(args->display.sticky, args->display.width, args->display.height, FALSE, FALSE, &x, &y, &width, &height); #if HEADER_OFFSET_HACK == 1 if (inHeader) { if (state & STATE_HEADER_ACTIVE) columnState = COLUMN_STATE_ACTIVE; else if (state & STATE_HEADER_PRESSED) columnState = COLUMN_STATE_PRESSED; } if (inHeader && columnState == COLUMN_STATE_PRESSED) { /* If this bitmap fills the whole header, don't offset it. */ /* FIXME: should have a layout option to control this. */ if (imgW < args->display.spanBbox.width || imgH < args->display.spanBbox.height) { x += 1, y += 1; } } #endif if (imgW > args->display.width) imgW = args->display.width; if (imgH > args->display.height) imgH = args->display.height; Tree_DrawBitmap(tree, bitmap, args->display.drawable, fg, bg, 0, 0, (unsigned int) imgW, (unsigned int) imgH, x, y); } static void NeededProcBitmap(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBitmap *elemX = (ElementBitmap *) elem; ElementBitmap *masterX = (ElementBitmap *) elem->master; int state = args->state; int width = 0, height = 0; int match, match2; Pixmap bitmap; BITMAP_FOR_STATE(bitmap, bitmap, state) if (bitmap != None) Tk_SizeOfBitmap(tree->display, bitmap, &width, &height); args->needed.width = width; args->needed.height = height; } static int StateProcBitmap(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBitmap *elemX = (ElementBitmap *) elem; ElementBitmap *masterX = (ElementBitmap *) elem->master; int match, match2; #ifdef DEPRECATED int draw1, draw2; #endif Pixmap bitmap1, bitmap2; XColor *fg1, *fg2; XColor *bg1, *bg2; if (!args->states.visible2) return 0; BITMAP_FOR_STATE(bitmap1, bitmap, args->states.state1) BITMAP_FOR_STATE(bitmap2, bitmap, args->states.state2) if (bitmap1 != bitmap2) { if ((bitmap1 != None) && (bitmap2 != None)) { int w1, h1, w2, h2; Tk_SizeOfBitmap(tree->display, bitmap1, &w1, &h1); Tk_SizeOfBitmap(tree->display, bitmap2, &w2, &h2); if ((w1 != w2) || (h1 != h2)) return CS_DISPLAY | CS_LAYOUT; return CS_DISPLAY; } return CS_DISPLAY | CS_LAYOUT; } /* Layout hasn't changed, and -draw layout option is false. */ if (!args->states.draw2) return 0; #ifdef DEPRECATED BOOLEAN_FOR_STATE(draw1, draw, args->states.state1) BOOLEAN_FOR_STATE(draw2, draw, args->states.state2) if ((draw1 != 0) != (draw2 != 0)) return CS_DISPLAY; if (draw2 == 0) return 0; #endif COLOR_FOR_STATE(fg1, fg, args->states.state1) COLOR_FOR_STATE(fg2, fg, args->states.state2) if (fg1 != fg2) return CS_DISPLAY; COLOR_FOR_STATE(bg1, bg, args->states.state1) COLOR_FOR_STATE(bg2, bg, args->states.state2) if (bg1 != bg2) return CS_DISPLAY; return 0; } static int UndefProcBitmap(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBitmap *elemX = (ElementBitmap *) elem; int modified = 0; #ifdef DEPRECATED modified |= PerStateInfo_Undefine(tree, &pstBoolean, &elemX->draw, elem->stateDomain, args->state); #endif modified |= PerStateInfo_Undefine(tree, &pstColor, &elemX->fg, elem->stateDomain, args->state); modified |= PerStateInfo_Undefine(tree, &pstColor, &elemX->bg, elem->stateDomain, args->state); modified |= PerStateInfo_Undefine(tree, &pstBitmap, &elemX->bitmap, elem->stateDomain, args->state); return modified; } static int ActualProcBitmap(TreeElementArgs *args) { TreeCtrl *tree = args->tree; ElementBitmap *elemX = (ElementBitmap *) args->elem; ElementBitmap *masterX = (ElementBitmap *) args->elem->master; static CONST char *optionName[] = { "-background", "-bitmap", #ifdef DEPRECATED "-draw", #endif "-foreground", (char *) NULL }; int index, match, matchM; Tcl_Obj *obj = NULL; if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, "option", 0, &index) != TCL_OK) return TCL_ERROR; switch (index) { case 0: { OBJECT_FOR_STATE(obj, pstColor, bg, args->state) break; } case 1: { OBJECT_FOR_STATE(obj, pstBitmap, bitmap, args->state) break; } #ifdef DEPRECATED case 2: { OBJECT_FOR_STATE(obj, pstBoolean, draw, args->state) break; } case 3: { OBJECT_FOR_STATE(obj, pstColor, fg, args->state) break; } #else case 2: { OBJECT_FOR_STATE(obj, pstColor, fg, args->state) break; } #endif } if (obj != NULL) Tcl_SetObjResult(tree->interp, obj); return TCL_OK; } TreeElementType treeElemTypeBitmap = { "bitmap", sizeof(ElementBitmap), bitmapOptionSpecs, NULL, CreateProcBitmap, DeleteProcBitmap, ConfigProcBitmap, DisplayProcBitmap, NeededProcBitmap, NULL, /* heightProc */ WorldChangedProcBitmap, StateProcBitmap, UndefProcBitmap, ActualProcBitmap, NULL /* onScreenProc */ }; /*****/ typedef struct ElementBorder ElementBorder; struct ElementBorder { TreeElement_ header; /* Must be first */ #ifdef DEPRECATED PerStateInfo draw; #endif PerStateInfo border; PerStateInfo relief; int thickness; Tcl_Obj *thicknessObj; int width; Tcl_Obj *widthObj; int height; Tcl_Obj *heightObj; int filled; }; #define BORDER_CONF_BG 0x0001 #define BORDER_CONF_RELIEF 0x0002 #define BORDER_CONF_SIZE 0x0004 #define BORDER_CONF_THICKNESS 0x0008 #define BORDER_CONF_FILLED 0x0010 #ifdef DEPRECATED #define BORDER_CONF_DRAW 0x0020 #endif static Tk_OptionSpec borderOptionSpecs[] = { {TK_OPTION_CUSTOM, "-background", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementBorder, border.obj), Tk_Offset(ElementBorder, border), TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_BG}, #ifdef DEPRECATED {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementBorder, draw.obj), Tk_Offset(ElementBorder, draw), TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_DRAW}, #endif {TK_OPTION_CUSTOM, "-filled", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementBorder, filled), TK_OPTION_NULL_OK, (ClientData) &booleanCO, BORDER_CONF_FILLED}, {TK_OPTION_PIXELS, "-height", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementBorder, heightObj), Tk_Offset(ElementBorder, height), TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_SIZE}, {TK_OPTION_CUSTOM, "-relief", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementBorder, relief.obj), Tk_Offset(ElementBorder, relief), TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_RELIEF}, {TK_OPTION_PIXELS, "-thickness", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementBorder, thicknessObj), Tk_Offset(ElementBorder, thickness), TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_THICKNESS}, {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementBorder, widthObj), Tk_Offset(ElementBorder, width), TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_SIZE}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} }; static void DeleteProcBorder(TreeElementArgs *args) { /* TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBorder *elemX = (ElementBorder *) elem;*/ } static int WorldChangedProcBorder(TreeElementArgs *args) { int flagM = args->change.flagMaster; int flagS = args->change.flagSelf; int mask = 0; if ((flagS | flagM) & BORDER_CONF_SIZE) mask |= CS_DISPLAY | CS_LAYOUT; if ((flagS | flagM) & ( #ifdef DEPRECATED BORDER_CONF_DRAW | #endif BORDER_CONF_BG | BORDER_CONF_RELIEF | BORDER_CONF_THICKNESS | BORDER_CONF_FILLED)) mask |= CS_DISPLAY; return mask; } static int ConfigProcBorder(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBorder *elemX = (ElementBorder *) elem; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, elem->stateDomain, elemX, elem->typePtr->optionTable, args->config.objc, args->config.objv, &savedOptions, &args->config.flagSelf) != TCL_OK) { args->config.flagSelf = 0; continue; } Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } return TCL_OK; } static int CreateProcBorder(TreeElementArgs *args) { TreeElement elem = args->elem; ElementBorder *elemX = (ElementBorder *) elem; elemX->filled = -1; return TCL_OK; } static void DisplayProcBorder(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBorder *elemX = (ElementBorder *) elem; ElementBorder *masterX = (ElementBorder *) elem->master; int state = args->state; int x = args->display.x, y = args->display.y; int width = args->display.width, height = args->display.height; int match, match2; #ifdef DEPRECATED int draw; #endif Tk_3DBorder border; int relief, filled = FALSE; int thickness = 0; #if USE_ITEM_PIXMAP == 0 TreeClip clip; #endif TreeRectangle tr1, tr2; #ifdef DEPRECATED BOOLEAN_FOR_STATE(draw, draw, state) if (!draw) return; #endif BORDER_FOR_STATE(border, border, state) if (border == NULL) return; RELIEF_FOR_STATE(relief, relief, state) if (relief == TK_RELIEF_NULL) relief = TK_RELIEF_FLAT; if (elemX->thicknessObj) thickness = elemX->thickness; else if ((masterX != NULL) && (masterX->thicknessObj != NULL)) thickness = masterX->thickness; if (elemX->filled != -1) filled = elemX->filled; else if ((masterX != NULL) && (masterX->filled != -1)) filled = masterX->filled; if (elemX->widthObj != NULL) width = elemX->width; else if ((masterX != NULL) && (masterX->widthObj != NULL)) width = masterX->width; if (elemX->heightObj != NULL) height = elemX->height; else if ((masterX != NULL) && (masterX->heightObj != NULL)) height = masterX->height; AdjustForSticky(args->display.sticky, args->display.width, args->display.height, TRUE, TRUE, &x, &y, &width, &height); /* X11 coordinates are 16-bit. */ TreeRect_SetXYWH(tr1, x, y, width, height); TreeRect_SetXYWH(tr2, -thickness, -thickness, args->display.td.width + thickness * 2, args->display.td.height + thickness * 2); TreeRect_Intersect(&tr1, &tr1, &tr2); #if USE_ITEM_PIXMAP == 0 /* Using a region instead of a rect because of how Tree_Fill3DRectangle * and Tree_Draw3DRectangle are implemented. */ clip.type = TREE_CLIP_REGION; clip.region = Tree_GetRectRegion(tree, &args->display.bounds); if (filled) { Tree_Fill3DRectangle(tree, args->display.td, &clip, border, tr1.x, tr1.y, tr1.width, tr1.height, thickness, relief); } else if (thickness > 0) { Tree_Draw3DRectangle(tree, args->display.td, &clip, border, tr1.x, tr1.y, tr1.width, tr1.height, thickness, relief); } Tree_FreeRegion(tree, clip.region); #else if (filled) { Tk_Fill3DRectangle(tree->tkwin, args->display.drawable, border, tr1.x, tr1.y, tr1.width, tr1.height, thickness, relief); } else if (thickness > 0) { Tk_Draw3DRectangle(tree->tkwin, args->display.drawable, border, tr1.x, tr1.y, tr1.width, tr1.height, thickness, relief); } #endif } static void NeededProcBorder(TreeElementArgs *args) { TreeElement elem = args->elem; ElementBorder *elemX = (ElementBorder *) elem; ElementBorder *masterX = (ElementBorder *) elem->master; int width = 0, height = 0; if (elemX->widthObj != NULL) width = elemX->width; else if ((masterX != NULL) && (masterX->widthObj != NULL)) width = masterX->width; if (elemX->heightObj != NULL) height = elemX->height; else if ((masterX != NULL) && (masterX->heightObj != NULL)) height = masterX->height; args->needed.width = width; args->needed.height = height; } static int StateProcBorder(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBorder *elemX = (ElementBorder *) elem; ElementBorder *masterX = (ElementBorder *) elem->master; int match, match2; #ifdef DEPRECATED int draw1, draw2; #endif Tk_3DBorder border1, border2; int relief1, relief2; if (!args->states.visible2 || !args->states.draw2) return 0; #ifdef DEPRECATED BOOLEAN_FOR_STATE(draw1, draw, args->states.state1) BOOLEAN_FOR_STATE(draw2, draw, args->states.state2) if ((draw1 != 0) != (draw2 != 0)) return CS_DISPLAY; if (draw2 == 0) return 0; #endif BORDER_FOR_STATE(border1, border, args->states.state1) BORDER_FOR_STATE(border2, border, args->states.state2) if (border1 != border2) return CS_DISPLAY; RELIEF_FOR_STATE(relief1, relief, args->states.state1) RELIEF_FOR_STATE(relief2, relief, args->states.state2) if (relief1 != relief2) return CS_DISPLAY; return 0; } static int UndefProcBorder(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBorder *elemX = (ElementBorder *) elem; int modified = 0; #ifdef DEPRECATED modified |= PerStateInfo_Undefine(tree, &pstBoolean, &elemX->draw, elem->stateDomain, args->state); #endif modified |= PerStateInfo_Undefine(tree, &pstBorder, &elemX->border, elem->stateDomain, args->state); modified |= PerStateInfo_Undefine(tree, &pstRelief, &elemX->relief, elem->stateDomain, args->state); return modified; } static int ActualProcBorder(TreeElementArgs *args) { TreeCtrl *tree = args->tree; ElementBorder *elemX = (ElementBorder *) args->elem; ElementBorder *masterX = (ElementBorder *) args->elem->master; static CONST char *optionName[] = { "-background", #ifdef DEPRECATED "-draw", #endif "-relief", (char *) NULL }; int index, match, matchM; Tcl_Obj *obj = NULL; if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, "option", 0, &index) != TCL_OK) return TCL_ERROR; switch (index) { case 0: { OBJECT_FOR_STATE(obj, pstBorder, border, args->state) break; } #ifdef DEPRECATED case 1: { OBJECT_FOR_STATE(obj, pstBoolean, draw, args->state) break; } case 2: { OBJECT_FOR_STATE(obj, pstRelief, relief, args->state) break; } #else case 1: { OBJECT_FOR_STATE(obj, pstRelief, relief, args->state) break; } #endif } if (obj != NULL) Tcl_SetObjResult(tree->interp, obj); return TCL_OK; } TreeElementType treeElemTypeBorder = { "border", sizeof(ElementBorder), borderOptionSpecs, NULL, CreateProcBorder, DeleteProcBorder, ConfigProcBorder, DisplayProcBorder, NeededProcBorder, NULL, /* heightProc */ WorldChangedProcBorder, StateProcBorder, UndefProcBorder, ActualProcBorder, NULL /* onScreenProc */ }; /*****/ #if 0 static CONST char *chkbutStateST[] = { "checked", "mixed", "normal", "active", "pressed", "disabled", (char *) NULL }; typedef struct ElementCheckButton ElementCheckButton; struct ElementCheckButton { TreeElement_ header; PerStateInfo image; int state; }; #define CHKBUT_CONF_IMAGE 0x0001 #define CHKBUT_CONF_STATE 0x0002 static Tk_OptionSpec chkbutOptionSpecs[] = { {TK_OPTION_STRING, "-image", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementCheckButton, image.obj), -1, TK_OPTION_NULL_OK, (ClientData) NULL, CHKBUT_CONF_IMAGE}, {TK_OPTION_STRING_TABLE, "-state", (char *) NULL, (char *) NULL, "normal", -1, Tk_Offset(ElementCheckButton, state), 0, (ClientData) chkbutStateST, CHKBUT_CONF_STATE}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} }; static void DeleteProcCheckButton(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementCheckButton *elemX = (ElementCheckButton *) elem; PerStateInfo_Free(tree, &pstImage, &elemX->image); } static int WorldChangedProcCheckButton(TreeElementArgs *args) { int flagM = args->change.flagMaster; int flagS = args->change.flagSelf; int mask = 0; if ((flagS | flagM) & (CHKBUT_CONF_IMAGE | CHKBUT_CONF_STATE)) mask |= CS_DISPLAY | CS_LAYOUT; return mask; } static int ChkButStateFromObj(TreeCtrl *tree, Tcl_Obj *obj, int *stateOff, int *stateOn) { Tcl_Interp *interp = tree->interp; int i, op = STATE_OP_ON, op2, op3, length, state = 0; char ch0, *string; int states[3]; states[STATE_OP_ON] = 0; states[STATE_OP_OFF] = 0; states[STATE_OP_TOGGLE] = 0; string = Tcl_GetStringFromObj(obj, &length); if (length == 0) goto unknown; ch0 = string[0]; if (ch0 == '!') { op = STATE_OP_OFF; ++string; ch0 = string[0]; } else if (ch0 == '~') { if (1) { FormatResult(interp, "can't specify '~' for this command"); return TCL_ERROR; } op = STATE_OP_TOGGLE; ++string; ch0 = string[0]; } for (i = 0; chkbutStateST[i] != NULL; i++) { if ((ch0 == chkbutStateST[i][0]) && !strcmp(string, chkbutStateST[i])) { state = 1L << i; break; } } if (state == 0) goto unknown; if (op == STATE_OP_ON) { op2 = STATE_OP_OFF; op3 = STATE_OP_TOGGLE; } else if (op == STATE_OP_OFF) { op2 = STATE_OP_ON; op3 = STATE_OP_TOGGLE; } else { op2 = STATE_OP_ON; op3 = STATE_OP_OFF; } states[op2] &= ~state; states[op3] &= ~state; states[op] |= state; *stateOn |= states[STATE_OP_ON]; *stateOff |= states[STATE_OP_OFF]; return TCL_OK; unknown: FormatResult(interp, "unknown state \"%s\"", string); return TCL_ERROR; } static int ConfigProcCheckButton(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementCheckButton *elemX = (ElementCheckButton *) elem; ElementCheckButton savedX; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, tree, elem->stateDomain, elem->typePtr->optionTable, args->config.objc, args->config.objv, &savedOptions, &args->config.flagSelf) != TCL_OK) { args->config.flagSelf = 0; continue; } if (args->config.flagSelf & CHKBUT_CONF_IMAGE) PSTSave(&elemX->image, &savedX.image); if (args->config.flagSelf & CHKBUT_CONF_IMAGE) { if (PerStateInfo_FromObj(tree, ChkButStateFromObj, &pstImage, &elemX->image) != TCL_OK) continue; } if (args->config.flagSelf & CHKBUT_CONF_IMAGE) PerStateInfo_Free(tree, &pstImage, &savedX.image); Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); if (args->config.flagSelf & CHKBUT_CONF_IMAGE) PSTRestore(tree, &pstImage, &elemX->image, &savedX.image); Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } return TCL_OK; } static int CreateProcCheckButton(TreeElementArgs *args) { return TCL_OK; } static void DisplayProcCheckButton(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementCheckButton *elemX = (ElementCheckButton *) elem; ElementCheckButton *masterX = (ElementCheckButton *) elem->master; int state = args->state; int match, matchM; Tk_Image image; int imgW, imgH; int dx = 0, dy = 0; image = PerStateImage_ForState(tree, &elemX->image, state, &match); if ((match != MATCH_EXACT) && (masterX != NULL)) { Tk_Image imageM = PerStateImage_ForState(tree, &masterX->image, state, &matchM); if (matchM > match) image = imageM; } if (image != NULL) { Tk_SizeOfImage(image, &imgW, &imgH); if (imgW < args->display.width) dx = (args->display.width - imgW) / 2; else if (imgW > args->display.width) imgW = args->display.width; if (imgH < args->display.height) dy = (args->display.height - imgH) / 2; else if (imgH > args->display.height) imgH = args->display.height; Tk_RedrawImage(image, 0, 0, imgW, imgH, args->display.drawable, args->display.x + dx, args->display.y + dy); } } static void NeededProcCheckButton(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementCheckButton *elemX = (ElementCheckButton *) elem; ElementCheckButton *masterX = (ElementCheckButton *) elem->master; int state = args->state; int match, match2; Tk_Image image; int width = 0, height = 0; image = PerStateImage_ForState(tree, &elemX->image, state, &match); if ((match != MATCH_EXACT) && (masterX != NULL)) { Tk_Image image2 = PerStateImage_ForState(tree, &masterX->image, state, &match2); if (match2 > match) image = image2; } if (image != NULL) Tk_SizeOfImage(image, &width, &height); args->layout.width = width; args->layout.height = height; } static int StateProcCheckButton(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementCheckButton *elemX = (ElementCheckButton *) elem; ElementCheckButton *masterX = (ElementCheckButton *) elem->master; int match, match2; Tk_Image image1, image2; int mask = 0; image1 = PerStateImage_ForState(tree, &elemX->image, args->states.state1, &match); if ((match != MATCH_EXACT) && (masterX != NULL)) { Tk_Image image = PerStateImage_ForState(tree, &masterX->image, args->states.state1, &match2); if (match2 > match) image1 = image; } image2 = PerStateImage_ForState(tree, &elemX->image, args->states.state2, &match); if ((match != MATCH_EXACT) && (masterX != NULL)) { Tk_Image image = PerStateImage_ForState(tree, &masterX->image, args->states.state2, &match2); if (match2 > match) image2 = image; } if (image1 != image2) { mask |= CS_DISPLAY; if ((image1 != NULL) && (image2 != NULL)) { int w1, h1, w2, h2; Tk_SizeOfImage(image1, &w1, &h1); Tk_SizeOfImage(image2, &w2, &h2); if ((w1 != w2) || (h1 != h2)) mask |= CS_LAYOUT; } else mask |= CS_LAYOUT; } return mask; } static int UndefProcCheckButton(TreeElementArgs *args) { TreeCtrl *tree = args->tree; ElementCheckButton *elemX = (ElementCheckButton *) args->elem; return PerStateInfo_Undefine(tree, &pstImage, &elemX->image, args->state); } static int ActualProcCheckButton(TreeElementArgs *args) { TreeCtrl *tree = args->tree; ElementCheckButton *elemX = (ElementCheckButton *) args->elem; ElementCheckButton *masterX = (ElementCheckButton *) args->elem->master; static CONST char *optionName[] = { "-image", (char *) NULL }; int index, match, matchM; Tcl_Obj *obj = NULL; if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, "option", 0, &index) != TCL_OK) return TCL_ERROR; switch (index) { case 0: { obj = PerStateInfo_ObjForState(tree, &pstImage, &elemX->image, args->state, &match); if ((match != MATCH_EXACT) && (masterX != NULL)) { objM = PerStateInfo_ObjForState(tree, &pstImage, &masterX->image, args->state, &matchM); if (matchM > match) obj = objM; } break; } } if (obj != NULL) Tcl_SetObjResult(tree->interp, obj); return TCL_OK; } TreeElementType treeElemTypeCheckButton = { "checkbutton", sizeof(ElementCheckButton), chkbutOptionSpecs, NULL, CreateProcCheckButton, DeleteProcCheckButton, ConfigProcCheckButton, DisplayProcCheckButton, NeededProcCheckButton, NULL, /* heightProc */ WorldChangedProcCheckButton, StateProcCheckButton, UndefProcCheckButton, ActualProcCheckButton, NULL /* onScreenProc */ }; #endif /*****/ typedef struct ElementHeader ElementHeader; struct ElementHeader { TreeElement_ header; /* Must be first */ PerStateInfo border; /* -background */ int borderWidth; /* -borderwidth */ Tcl_Obj *borderWidthObj; /* -borderwidth */ PerStateInfo arrowBitmap; /* -arrowbitmap */ PerStateInfo arrowImage; /* -arrowimage */ Tcl_Obj *arrowPadXObj; /* -arrowpadx */ int *arrowPadX; /* -arrowpadx */ Tcl_Obj *arrowPadYObj; /* -arrowpady */ int *arrowPadY; /* -arrowpady */ int arrow; /* -arrow */ #define SIDE_LEFT 0 #define SIDE_RIGHT 1 int arrowSide; /* -arrowside */ int arrowGravity; /* -arrowgravity */ int state; /* -state */ }; static CONST char *headerStateST[] = { "normal", "active", "pressed", (char *) NULL }; static CONST char *headerArrowST[] = { "none", "up", "down", (char *) NULL }; static CONST char *headerArrowSideST[] = { "left", "right", (char *) NULL }; #define HEADER_CONF_SIZE 0x0001 #define HEADER_CONF_DISPLAY 0x0002 static Tk_OptionSpec headerOptionSpecs[] = { {TK_OPTION_CUSTOM, "-arrow", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementHeader, arrow), TK_OPTION_NULL_OK, (ClientData) NULL, HEADER_CONF_DISPLAY | HEADER_CONF_SIZE}, {TK_OPTION_CUSTOM, "-arrowbitmap", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementHeader, arrowBitmap.obj), Tk_Offset(ElementHeader, arrowBitmap), TK_OPTION_NULL_OK, (ClientData) NULL, HEADER_CONF_DISPLAY | HEADER_CONF_SIZE}, {TK_OPTION_CUSTOM, "-arrowgravity", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementHeader, arrowGravity), TK_OPTION_NULL_OK, (ClientData) NULL, HEADER_CONF_DISPLAY | HEADER_CONF_SIZE}, {TK_OPTION_CUSTOM, "-arrowimage", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementHeader, arrowImage.obj), Tk_Offset(ElementHeader, arrowImage), TK_OPTION_NULL_OK, (ClientData) NULL, HEADER_CONF_DISPLAY | HEADER_CONF_SIZE}, {TK_OPTION_CUSTOM, "-arrowpadx", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementHeader, arrowPadXObj), Tk_Offset(ElementHeader, arrowPadX), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_pad, HEADER_CONF_DISPLAY | HEADER_CONF_SIZE}, {TK_OPTION_CUSTOM, "-arrowpady", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementHeader, arrowPadYObj), Tk_Offset(ElementHeader, arrowPadY), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_pad, HEADER_CONF_DISPLAY | HEADER_CONF_SIZE}, {TK_OPTION_CUSTOM, "-arrowside", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementHeader, arrowSide), TK_OPTION_NULL_OK, (ClientData) NULL, HEADER_CONF_DISPLAY | HEADER_CONF_SIZE}, {TK_OPTION_CUSTOM, "-background", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementHeader, border.obj), Tk_Offset(ElementHeader, border), TK_OPTION_NULL_OK, (ClientData) NULL, HEADER_CONF_DISPLAY}, {TK_OPTION_PIXELS, "-borderwidth", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementHeader, borderWidthObj), Tk_Offset(ElementHeader, borderWidth), TK_OPTION_NULL_OK, (ClientData) NULL, HEADER_CONF_SIZE | HEADER_CONF_DISPLAY}, {TK_OPTION_CUSTOM, "-state", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementHeader, state), TK_OPTION_NULL_OK, (ClientData) NULL, HEADER_CONF_DISPLAY}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} }; static void DeleteProcHeader(TreeElementArgs *args) { /* TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementHeader *elemX = (ElementHeader *) elem;*/ } static int WorldChangedProcHeader(TreeElementArgs *args) { int flagT = args->change.flagTree; int flagM = args->change.flagMaster; int flagS = args->change.flagSelf; int mask = 0; if (flagT & TREE_CONF_THEME) mask |= CS_DISPLAY | CS_LAYOUT; else if ((flagS | flagM) & HEADER_CONF_SIZE) mask |= CS_DISPLAY | CS_LAYOUT; else if ((flagS | flagM) & HEADER_CONF_DISPLAY) mask |= CS_DISPLAY; return mask; } static int ConfigProcHeader(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementHeader *elemX = (ElementHeader *) elem; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, elem->stateDomain, elemX, elem->typePtr->optionTable, args->config.objc, args->config.objv, &savedOptions, &args->config.flagSelf) != TCL_OK) { args->config.flagSelf = 0; continue; } Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } return TCL_OK; } static int CreateProcHeader(TreeElementArgs *args) { TreeElement elem = args->elem; ElementHeader *elemX = (ElementHeader *) elem; elemX->arrow = -1; elemX->arrowGravity = -1; elemX->arrowSide = -1; elemX->state = -1; return TCL_OK; } struct HeaderParams { int state; /* COLUMN_STATE_XXX */ int arrow; /* COLUMN_ARROW_XXX */ int borderWidth; int margins[4]; /* content margins, not including arrow */ int elemState; /* STATE_XXX */ int eUnionBbox[4]; int iUnionBbox[4]; }; static void HeaderGetParams( TreeCtrl *tree, ElementHeader *elemX, int state, struct HeaderParams *params ) { ElementHeader *masterX = (ElementHeader *) elemX->header.master; int i; params->elemState = state; params->state = COLUMN_STATE_NORMAL; if (elemX->state != -1) params->state = elemX->state; else if (masterX != NULL && masterX->state != -1) params->state = masterX->state; else if (elemX->header.stateDomain == STATE_DOMAIN_HEADER) { if (state & STATE_HEADER_ACTIVE) params->state = COLUMN_STATE_ACTIVE; if (state & STATE_HEADER_PRESSED) params->state = COLUMN_STATE_PRESSED; } params->arrow = COLUMN_ARROW_NONE; if (elemX->arrow != -1) params->arrow = elemX->arrow; else if (masterX != NULL && masterX->arrow != -1) params->arrow = masterX->arrow; else if (elemX->header.stateDomain == STATE_DOMAIN_HEADER) { if (state & STATE_HEADER_SORT_UP) params->arrow = COLUMN_ARROW_UP; if (state & STATE_HEADER_SORT_DOWN) params->arrow = COLUMN_ARROW_DOWN; } if (elemX->borderWidthObj) params->borderWidth = elemX->borderWidth; else if ((masterX != NULL) && (masterX->borderWidthObj != NULL)) params->borderWidth = masterX->borderWidth; else params->borderWidth = 2; /* Column header -borderwidth defaults to 2. */ if (params->borderWidth < 0) params->borderWidth = 2; if (tree->useTheme && (TreeTheme_GetHeaderContentMargins(tree, params->state, params->arrow, params->margins) == TCL_OK)) { #ifdef WIN32 /* I'm hacking these margins since the default XP theme does not give * reasonable ContentMargins for HP_HEADERITEM */ int bw = MAX(params->borderWidth, 3); params->margins[1] = MAX(params->margins[1], bw); params->margins[3] = MAX(params->margins[3], bw); #endif /* WIN32 */ } else { params->margins[0] = params->margins[2] = 0; params->margins[1] = params->margins[3] = params->borderWidth; } for (i = 0; i < 4; i++) params->eUnionBbox[i] = params->iUnionBbox[i] = -1; } struct ArrowLayout { int arrow; int arrowSide; int x; int y; int width; int height; int padX[2]; int padY[2]; }; static void HeaderLayoutArrow( TreeCtrl *tree, ElementHeader *elemX, struct HeaderParams *params, int x, int y, int width, int height, /* bounds of whole element */ int indent, struct ArrowLayout *layout ) { ElementHeader *masterX = (ElementHeader *) elemX->header.master; int state = params->elemState; int arrowSide, arrowWidth = -1, arrowGravity, arrowHeight; Tk_Image image; Pixmap bitmap; int defPadX[2] = {6, 6}, defPadY[2] = {0, 0}, *arrowPadX, *arrowPadY; int match, match2; int minX, maxX, padX[2]; #ifdef MAC_OSX_TK int margins[4]; #endif layout->arrow = params->arrow; if (layout->arrow == COLUMN_ARROW_NONE) { return; } arrowSide = elemX->arrowSide; if (arrowSide == -1 && masterX != NULL) arrowSide = masterX->arrowSide; if (arrowSide == -1) arrowSide = SIDE_RIGHT; arrowGravity = elemX->arrowGravity; if (arrowGravity == -1 && masterX != NULL) arrowGravity = masterX->arrowGravity; if (arrowGravity == -1) arrowGravity = SIDE_LEFT; arrowPadX = elemX->arrowPadX; if (arrowPadX == NULL && masterX != NULL) { arrowPadX = masterX->arrowPadX; } if (arrowPadX == NULL) { arrowPadX = defPadX; } arrowPadY = elemX->arrowPadY; if (arrowPadY == NULL && masterX != NULL) { arrowPadY = masterX->arrowPadY; } if (arrowPadY == NULL) { arrowPadY = defPadY; } #ifdef MAC_OSX_TK /* Under Aqua, the Appearance Manager draws the sort arrow as part of * the header background. */ if (tree->useTheme && TreeTheme_GetHeaderContentMargins(tree, params->state, params->arrow, margins) == TCL_OK) { layout->arrowSide = SIDE_RIGHT; layout->width = margins[2]; layout->x = width - layout->width; layout->y = 0; layout->height = 1; /* bogus value */ /* The content margins do not include padding on the left of the * sort arrow. */ layout->padX[PAD_TOP_LEFT] = arrowPadX[PAD_TOP_LEFT]; layout->padX[PAD_BOTTOM_RIGHT] = 0; layout->padY[PAD_TOP_LEFT] = layout->padY[PAD_BOTTOM_RIGHT] = 0; return; } #endif if (arrowWidth == -1) { IMAGE_FOR_STATE(image, arrowImage, state); if (image != NULL) { Tk_SizeOfImage(image, &arrowWidth, &arrowHeight); } } if (arrowWidth == -1) { BITMAP_FOR_STATE(bitmap, arrowBitmap, state); if (bitmap != None) { Tk_SizeOfBitmap(tree->display, bitmap, &arrowWidth, &arrowHeight); } } if ((arrowWidth == -1) && tree->useTheme && TreeTheme_GetArrowSize(tree, Tk_WindowId(tree->tkwin), params->arrow == COLUMN_ARROW_UP, &arrowWidth, &arrowHeight) == TCL_OK) { /* nothing */ } if (arrowWidth == -1) { #if 0 /* This is the original calculation of arrow size. */ Tk_Font tkfont = column->tkfont ? column->tkfont : tree->tkfont; Tk_FontMetrics fm; Tk_GetFontMetrics(tkfont, &fm); arrowWidth = (fm.linespace + column->textPadY[PAD_TOP_LEFT] + column->textPadY[PAD_BOTTOM_RIGHT] + column->borderWidth * 2) / 2; if (!(arrowWidth & 1)) arrowWidth--; arrowHeight = arrowWidth; #endif arrowWidth = 9; /* FIXME: -sortarrowwidth */ arrowHeight = arrowWidth; } minX = x + indent; maxX = x + width; padX[PAD_TOP_LEFT] = padX[PAD_BOTTOM_RIGHT] = 0; if (arrowSide == SIDE_LEFT) { if (params->iUnionBbox[0] != -1) { maxX = x + params->iUnionBbox[0]; padX[PAD_TOP_LEFT] = params->iUnionBbox[0] - params->eUnionBbox[0]; } } else { if (params->iUnionBbox[2] != -1) { minX = x + params->iUnionBbox[2]; padX[PAD_BOTTOM_RIGHT] = params->eUnionBbox[2] - params->iUnionBbox[2]; } } if (arrowGravity == SIDE_LEFT) { layout->x = minX + MAX(padX[PAD_BOTTOM_RIGHT], arrowPadX[PAD_TOP_LEFT]); layout->x = MIN(layout->x, (x + width) - arrowPadX[PAD_BOTTOM_RIGHT] - arrowWidth); } else { layout->x = maxX - MAX(padX[PAD_TOP_LEFT], arrowPadX[PAD_BOTTOM_RIGHT]) - arrowWidth; } /* Don't let the arrow go too far left when the column is very narrow. */ layout->x = MAX(layout->x, x + indent + arrowPadX[PAD_TOP_LEFT]); layout->width = arrowWidth; layout->y = y + (height - (arrowHeight + arrowPadY[PAD_TOP_LEFT] + arrowPadY[PAD_BOTTOM_RIGHT])) / 2 + arrowPadY[PAD_TOP_LEFT]; layout->height = arrowHeight; layout->arrowSide = arrowSide; layout->padX[0] = arrowPadX[0]; layout->padX[1] = arrowPadX[1]; layout->padY[0] = arrowPadY[0]; layout->padY[1] = arrowPadY[1]; } static void HeaderDrawArrow( TreeElementArgs *args, struct HeaderParams *params, int x, int y, int width, int height, /* bounds of whole element */ int indent ) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementHeader *elemX = (ElementHeader *) elem; ElementHeader *masterX = (ElementHeader *) elem->master; Tk_Image image; Pixmap bitmap; Tk_3DBorder border; int state = params->elemState; int sunken = params->state == COLUMN_STATE_PRESSED; struct ArrowLayout layout; int match, match2; if (params->arrow == COLUMN_ARROW_NONE) return; HeaderLayoutArrow(tree, elemX, params, x, y, width, height, indent, &layout); IMAGE_FOR_STATE(image, arrowImage, state); if (image != NULL) { Tree_RedrawImage(image, 0, 0, layout.width, layout.height, args->display.td, layout.x + sunken, layout.y + sunken); return; } BITMAP_FOR_STATE(bitmap, arrowBitmap, state); if (bitmap != None) { int bx, by; bx = layout.x + sunken; by = layout.y + sunken; Tree_DrawBitmap(tree, bitmap, args->display.drawable, NULL, NULL, 0, 0, (unsigned int) layout.width, (unsigned int) layout.height, bx, by); return; } if (tree->useTheme) { if (TreeTheme_DrawHeaderArrow(tree, args->display.td, params->state, layout.arrow == COLUMN_ARROW_UP, layout.x + sunken, layout.y + sunken, layout.width, layout.height) == TCL_OK) return; } if (1) { int arrowWidth = layout.width; int arrowHeight = layout.height; int arrowBottom = layout.y + arrowHeight; XPoint points[5]; int color1 = 0, color2 = 0; int i; switch (layout.arrow) { case COLUMN_ARROW_UP: points[0].x = layout.x; points[0].y = arrowBottom - 1; points[1].x = layout.x + arrowWidth / 2; points[1].y = layout.y - 1; color1 = TK_3D_DARK_GC; points[4].x = layout.x + arrowWidth / 2; points[4].y = layout.y - 1; points[3].x = layout.x + arrowWidth - 1; points[3].y = arrowBottom - 1; points[2].x = layout.x; points[2].y = arrowBottom - 1; color2 = TK_3D_LIGHT_GC; break; case COLUMN_ARROW_DOWN: points[0].x = layout.x + arrowWidth - 1; points[0].y = layout.y; points[1].x = layout.x + arrowWidth / 2; points[1].y = arrowBottom; color1 = TK_3D_LIGHT_GC; points[2].x = layout.x + arrowWidth - 1; points[2].y = layout.y; points[3].x = layout.x; points[3].y = layout.y; points[4].x = layout.x + arrowWidth / 2; points[4].y = arrowBottom; color2 = TK_3D_DARK_GC; break; } for (i = 0; i < 5; i++) { points[i].x += sunken; points[i].y += sunken; } BORDER_FOR_STATE(border, border, state) if (border == NULL) { Tk_Uid colorName = Tk_GetUid(DEF_BUTTON_BG_COLOR); if (params->state == COLUMN_STATE_ACTIVE) colorName = Tk_GetUid(DEF_BUTTON_ACTIVE_BG_COLOR); border = Tk_Get3DBorder(tree->interp, tree->tkwin, colorName); /* FIXME: cache it! */ if (border == NULL) border = tree->border; } XDrawLines(tree->display, args->display.drawable, Tk_3DBorderGC(tree->tkwin, border, color2), points + 2, 3, CoordModeOrigin); XDrawLines(tree->display, args->display.drawable, Tk_3DBorderGC(tree->tkwin, border, color1), points, 2, CoordModeOrigin); } } static void DisplayProcHeader(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementHeader *elemX = (ElementHeader *) elem; ElementHeader *masterX = (ElementHeader *) elem->master; /* int state = args->state;*/ int x = args->display.x, y = args->display.y; int width = args->display.width, height = args->display.height; int arrowIndent = 0; Tk_3DBorder border, borderDefault = NULL; int i, relief; int match, match2; struct HeaderParams params; TreeRectangle tr1, tr2; if (tree->useTheme && (tree->themeHeaderHeight > 0)) { height = tree->themeHeaderHeight; } AdjustForSticky(args->display.sticky, args->display.width, args->display.height, TRUE, TRUE, &x, &y, &width, &height); /* We want the right side of the header to match the right edge of the * column and not be clipped when the column width is less than the needed * width of the style. */ width = MIN(width, TreeRect_Right(args->display.spanBbox) - x); /* Don't draw the sort arrow in the canvasPadX space. */ if (x < args->display.spanBbox.x + args->display.indent) { arrowIndent = args->display.indent; } HeaderGetParams(tree, elemX, args->state, ¶ms); for (i = 0; i < 4; i++) { params.eUnionBbox[i] = args->display.eUnionBbox[i] - (x - args->display.spanBbox.x); params.iUnionBbox[i] = args->display.iUnionBbox[i] - (x - args->display.spanBbox.x); } if (tree->useTheme && TreeTheme_DrawHeaderItem(tree, args->display.td, params.state, params.arrow, args->display.spanIndex, x, y, width, height) == TCL_OK) { #if !defined(MAC_OSX_TK) /* Under Aqua, the Appearance Manager draws the sort arrow as part of * the header background. */ HeaderDrawArrow(args, ¶ms, x, y, width, height, arrowIndent); #endif return; } BORDER_FOR_STATE(border, border, params.elemState) if (border == NULL) { Tk_Uid colorName = Tk_GetUid(DEF_BUTTON_BG_COLOR); if (params.state != COLUMN_STATE_NORMAL) colorName = Tk_GetUid(DEF_BUTTON_ACTIVE_BG_COLOR); borderDefault = Tk_Get3DBorder(tree->interp, tree->tkwin, colorName); /* FIXME: cache it! */ if (borderDefault == NULL) return; border = borderDefault; } /* X11 coordinates are 16-bit. */ TreeRect_SetXYWH(tr1, x, y, width, height); TreeRect_SetXYWH(tr2, -params.borderWidth, -params.borderWidth, args->display.td.width + params.borderWidth * 2, args->display.td.height + params.borderWidth * 2); TreeRect_Intersect(&tr1, &tr1, &tr2); Tk_Fill3DRectangle(tree->tkwin, args->display.drawable, border, tr1.x, tr1.y, tr1.width, tr1.height, params.borderWidth, TK_RELIEF_FLAT); HeaderDrawArrow(args, ¶ms, x, y, width, height, arrowIndent); relief = (params.state == COLUMN_STATE_PRESSED) ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED; Tk_Draw3DRectangle(tree->tkwin, args->display.drawable, border, tr1. x, tr1.y, tr1.width, tr1.height, params.borderWidth, relief); if (borderDefault != NULL) Tk_Free3DBorder(borderDefault); } static void NeededProcHeader(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementHeader *elemX = (ElementHeader *) elem; /* ElementHeader *masterX = (ElementHeader *) elem->master;*/ struct HeaderParams params; struct ArrowLayout layout; TreeRectangle bounds = {0, 0, 100, 24}; int width = 0, height = 0, fixedHeight = -1; if (args->tree->useTheme && (tree->themeHeaderHeight > 0)) { fixedHeight = tree->themeHeaderHeight; } HeaderGetParams(tree, elemX, args->state, ¶ms); HeaderLayoutArrow(tree, elemX, ¶ms, TreeRect_Left(bounds), TreeRect_Top(bounds), TreeRect_Width(bounds), TreeRect_Height(bounds), 0, &layout); if (layout.arrow != COLUMN_ARROW_NONE) { width = layout.padX[0] + layout.width + layout.padX[1]; height = layout.padY[0] + layout.height + layout.padY[1]; } #if 0 /* Original header code never considered borderWidth or * TreeTheme_GetHeaderContentMargins when calculating needed width. */ width += params.margins[0] + params.margins[1]; #endif height += params.margins[1] + params.margins[3]; args->needed.width = width; args->needed.height = (fixedHeight > 0) ? fixedHeight : height; } static int StateProcHeader(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementHeader *elemX = (ElementHeader *) elem; ElementHeader *masterX = (ElementHeader *) elem->master; int match, match2; Tk_Image image1 = NULL, image2 = NULL; Pixmap bitmap1 = None, bitmap2 = None; Tk_3DBorder border1, border2; struct HeaderParams params1, params2; if (!args->states.visible2) return 0; HeaderGetParams(tree, elemX, args->states.state1, ¶ms1); HeaderGetParams(tree, elemX, args->states.state2, ¶ms2); /* Check for -arrow changing to/from "none" */ if ((params1.arrow != COLUMN_ARROW_NONE) ^ (params2.arrow != COLUMN_ARROW_NONE)) return CS_DISPLAY | CS_LAYOUT; if (params1.arrow != COLUMN_ARROW_NONE) { IMAGE_FOR_STATE(image1, arrowImage, args->states.state1) } if (params2.arrow != COLUMN_ARROW_NONE) { IMAGE_FOR_STATE(image2, arrowImage, args->states.state2) } if (image1 != image2) { if ((image1 != NULL) && (image2 != NULL)) { int w1, h1, w2, h2; Tk_SizeOfImage(image1, &w1, &h1); Tk_SizeOfImage(image2, &w2, &h2); if ((w1 != w2) || (h1 != h2)) return CS_DISPLAY | CS_LAYOUT; return CS_DISPLAY; } return CS_DISPLAY | CS_LAYOUT; } if (params1.arrow != COLUMN_ARROW_NONE) { BITMAP_FOR_STATE(bitmap1, arrowBitmap, args->states.state1) } if (params2.arrow != COLUMN_ARROW_NONE) { BITMAP_FOR_STATE(bitmap2, arrowBitmap, args->states.state2) } if (bitmap1 != bitmap2) { if ((bitmap1 != None) && (bitmap2 != None)) { int w1, h1, w2, h2; Tk_SizeOfBitmap(tree->display, bitmap1, &w1, &h1); Tk_SizeOfBitmap(tree->display, bitmap2, &w2, &h2); if ((w1 != w2) || (h1 != h2)) return CS_DISPLAY | CS_LAYOUT; return CS_DISPLAY; } return CS_DISPLAY | CS_LAYOUT; } if (!args->states.draw2) return 0; /* Headers look different on MacOSX in the background. */ if ((args->states.state1 & STATE_HEADER_BG) ^ (args->states.state2 & STATE_HEADER_BG)) return CS_DISPLAY; if (params1.state != params2.state) return CS_DISPLAY; if (params1.arrow != params2.arrow) return CS_DISPLAY; BORDER_FOR_STATE(border1, border, args->states.state1) BORDER_FOR_STATE(border2, border, args->states.state2) if (border1 != border2) return CS_DISPLAY; return 0; } static int UndefProcHeader(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementHeader *elemX = (ElementHeader *) elem; int modified = 0; modified |= PerStateInfo_Undefine(tree, &pstBitmap, &elemX->arrowBitmap, elem->stateDomain, args->state); modified |= PerStateInfo_Undefine(tree, &pstImage, &elemX->arrowImage, elem->stateDomain, args->state); modified |= PerStateInfo_Undefine(tree, &pstBorder, &elemX->border, elem->stateDomain, args->state); return modified; } static int ActualProcHeader(TreeElementArgs *args) { TreeCtrl *tree = args->tree; ElementHeader *elemX = (ElementHeader *) args->elem; ElementHeader *masterX = (ElementHeader *) args->elem->master; static CONST char *optionName[] = { "-arrowbitmap", "-arrowimage", "-background", (char *) NULL }; int index, match, matchM; Tcl_Obj *obj = NULL; if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, "option", 0, &index) != TCL_OK) return TCL_ERROR; switch (index) { case 0: { OBJECT_FOR_STATE(obj, pstBitmap, arrowBitmap, args->state) break; } case 1: { OBJECT_FOR_STATE(obj, pstImage, arrowImage, args->state) break; } case 2: { OBJECT_FOR_STATE(obj, pstBorder, border, args->state) break; } } if (obj != NULL) Tcl_SetObjResult(tree->interp, obj); return TCL_OK; } TreeElementType treeElemTypeHeader = { "header", sizeof(ElementHeader), headerOptionSpecs, NULL, CreateProcHeader, DeleteProcHeader, ConfigProcHeader, DisplayProcHeader, NeededProcHeader, NULL, /* heightProc */ WorldChangedProcHeader, StateProcHeader, UndefProcHeader, ActualProcHeader, NULL /* onScreenProc */ }; void TreeElement_GetContentMargins( TreeCtrl *tree, TreeElement elem, int state, int eMargins[4], int uMargins[4], int *arrowHeight ) { eMargins[0] = eMargins[1] = eMargins[2] = eMargins[3] = 0; uMargins[0] = uMargins[1] = uMargins[2] = uMargins[3] = 0; *arrowHeight = 0; if (ELEMENT_TYPE_MATCHES(elem->typePtr, &treeElemTypeHeader)) { ElementHeader *elemX = (ElementHeader *) elem; struct HeaderParams params; struct ArrowLayout layout; TreeRectangle bounds = {0, 0, 100, 24}; HeaderGetParams(tree, elemX, state, ¶ms); /* Added to ePadY of elements in the -union */ eMargins[1] = params.margins[1]; eMargins[3] = params.margins[3]; /* Added to iPadY of this element */ uMargins[1] = params.margins[1]; uMargins[3] = params.margins[3]; if (params.arrow == COLUMN_ARROW_NONE) return; HeaderLayoutArrow(tree, elemX, ¶ms, TreeRect_Left(bounds), TreeRect_Top(bounds), TreeRect_Width(bounds), TreeRect_Height(bounds), 0, &layout); if (layout.arrowSide == SIDE_LEFT) { uMargins[0] = layout.padX[PAD_TOP_LEFT] + layout.width + layout.padX[PAD_BOTTOM_RIGHT]; eMargins[0] = layout.padX[PAD_TOP_LEFT] + layout.width; } else { uMargins[2] = layout.padX[PAD_TOP_LEFT] + layout.width + layout.padX[PAD_BOTTOM_RIGHT]; eMargins[2] = layout.width + layout.padX[PAD_BOTTOM_RIGHT]; } *arrowHeight = layout.padY[0] + layout.height + layout.padY[1]; } } /*****/ typedef struct ElementImage ElementImage; struct ElementImage { TreeElement_ header; PerStateInfo image; }; typedef struct ElementImageSize { int width; Tcl_Obj *widthObj; int height; Tcl_Obj *heightObj; } ElementImageSize; #define IMAGE_CONF_IMAGE 0x0001 #define IMAGE_CONF_SIZE 0x0002 #define IMAGE_CONF_DISPLAY 0x0004 #ifdef DEPRECATED #define IMAGE_CONF_DRAW 0x0008 #endif static Tk_OptionSpec imageOptionSpecs[] = { #ifdef DEPRECATED {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_DRAW}, #endif {TK_OPTION_CUSTOM, "-height", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_SIZE}, {TK_OPTION_CUSTOM, "-image", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementImage, image.obj), Tk_Offset(ElementImage, image), TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_IMAGE}, {TK_OPTION_CUSTOM, "-tiled", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_DISPLAY}, {TK_OPTION_CUSTOM, "-width", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_SIZE}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} }; static void DeleteProcImage(TreeElementArgs *args) { /* TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementImage *elemX = (ElementImage *) elem;*/ } static int WorldChangedProcImage(TreeElementArgs *args) { int flagM = args->change.flagMaster; int flagS = args->change.flagSelf; int mask = 0; if ((flagS | flagM) & ( #ifdef DEPRECATED IMAGE_CONF_DRAW | #endif IMAGE_CONF_IMAGE | IMAGE_CONF_SIZE)) mask |= CS_DISPLAY | CS_LAYOUT; if ((flagS | flagM) & IMAGE_CONF_DISPLAY) mask |= CS_DISPLAY; return mask; } static int ConfigProcImage(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementImage *elemX = (ElementImage *) elem; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, elem->stateDomain, elemX, elem->typePtr->optionTable, args->config.objc, args->config.objv, &savedOptions, &args->config.flagSelf) != TCL_OK) { args->config.flagSelf = 0; continue; } Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } return TCL_OK; } static int CreateProcImage(TreeElementArgs *args) { /* ElementImage *elemX = (ElementImage *) args->elem;*/ return TCL_OK; } static void DisplayProcImage(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementImage *elemX = (ElementImage *) elem; ElementImage *masterX = (ElementImage *) elem->master; int state = args->state; int x = args->display.x, y = args->display.y; int width, height; int match, match2; #ifdef DEPRECATED int draw; #endif Tk_Image image; int imgW, imgH; int tiled = 0, *eit, *eitM = NULL; int inHeader = elem->stateDomain == STATE_DOMAIN_HEADER; int columnState = COLUMN_STATE_NORMAL; #ifdef DEPRECATED draw = DO_BooleanForState(tree, elem, 1002, state); if (!draw) return; #endif IMAGE_FOR_STATE(image, image, state) if (image == NULL) return; eit = DynamicOption_FindData(elem->options, 1003); if (masterX != NULL) eitM = DynamicOption_FindData(elem->master->options, 1003); if (eit != NULL && *eit != -1) tiled = *eit; else if ((eitM != NULL) && (*eitM != -1)) tiled = *eitM; if (tiled) { TreeRectangle tr; tr.x = x, tr.y = y; tr.width = args->display.width, tr.height = args->display.height; Tree_DrawTiledImage(tree, args->display.td, image, tr, x, y, TRUE, TRUE); return; } Tk_SizeOfImage(image, &imgW, &imgH); width = imgW, height = imgH; AdjustForSticky(args->display.sticky, args->display.width, args->display.height, FALSE, FALSE, &x, &y, &width, &height); #if HEADER_OFFSET_HACK == 1 if (inHeader) { if (state & STATE_HEADER_ACTIVE) columnState = COLUMN_STATE_ACTIVE; else if (state & STATE_HEADER_PRESSED) columnState = COLUMN_STATE_PRESSED; } if (inHeader && columnState == COLUMN_STATE_PRESSED) { /* If this image fills the whole header, don't offset it. */ /* FIXME: should have a layout option to control this. */ if (imgW < args->display.spanBbox.width || imgH < args->display.spanBbox.height) { x += 1, y += 1; } } #endif if (imgW > args->display.width) imgW = args->display.width; if (imgH > args->display.height) imgH = args->display.height; Tree_RedrawImage(image, 0, 0, imgW, imgH, args->display.td, x, y); } static void NeededProcImage(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementImage *elemX = (ElementImage *) elem; ElementImage *masterX = (ElementImage *) elem->master; int state = args->state; int width = 0, height = 0; int match, match2; Tk_Image image; ElementImageSize *eis, *eisM = NULL; IMAGE_FOR_STATE(image, image, state) if (image != NULL) Tk_SizeOfImage(image, &width, &height); eis = DynamicOption_FindData(elem->options, 1001); if (masterX != NULL) eisM = DynamicOption_FindData(elem->master->options, 1001); if (eis != NULL && eis->widthObj != NULL) width = eis->width; else if ((eisM != NULL) && (eisM->widthObj != NULL)) width = eisM->width; if (eis != NULL && eis->heightObj != NULL) height = eis->height; else if ((eisM != NULL) && (eisM->heightObj != NULL)) height = eisM->height; args->needed.width = width; args->needed.height = height; } static int StateProcImage(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementImage *elemX = (ElementImage *) elem; ElementImage *masterX = (ElementImage *) elem->master; int match, match2; #ifdef DEPRECATED int draw1, draw2; #endif Tk_Image image1, image2; if (!args->states.visible2) return 0; IMAGE_FOR_STATE(image1, image, args->states.state1) IMAGE_FOR_STATE(image2, image, args->states.state2) if (image1 != image2) { if ((image1 != NULL) && (image2 != NULL)) { int w1, h1, w2, h2; Tk_SizeOfImage(image1, &w1, &h1); Tk_SizeOfImage(image2, &w2, &h2); if ((w1 != w2) || (h1 != h2)) return CS_DISPLAY | CS_LAYOUT; return CS_DISPLAY; } return CS_DISPLAY | CS_LAYOUT; } if (!args->states.draw2) return 0; #ifdef DEPRECATED draw1 = DO_BooleanForState(tree, elem, 1002, args->states.state1); draw2 = DO_BooleanForState(tree, elem, 1002, args->states.state2); if ((draw1 != 0) != (draw2 != 0)) return CS_DISPLAY; #endif return 0; } static int UndefProcImage(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementImage *elemX = (ElementImage *) elem; int modified = 0; #ifdef DEPRECATED PerStateInfo *psi; #endif #ifdef DEPRECATED if ((psi = DynamicOption_FindData(elem->options, 1002)) != NULL) modified |= PerStateInfo_Undefine(tree, &pstBoolean, psi, elem->stateDomain, args->state); #endif modified |= PerStateInfo_Undefine(tree, &pstImage, &elemX->image, elem->stateDomain, args->state); return modified; } static int ActualProcImage(TreeElementArgs *args) { TreeCtrl *tree = args->tree; ElementImage *elemX = (ElementImage *) args->elem; ElementImage *masterX = (ElementImage *) args->elem->master; static CONST char *optionName[] = { #ifdef DEPRECATED "-draw", #endif "-image", (char *) NULL }; int index, match, matchM; Tcl_Obj *obj = NULL; if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, "option", 0, &index) != TCL_OK) return TCL_ERROR; switch (index) { #ifdef DEPRECATED case 0: { obj = DO_ObjectForState(tree, &pstBoolean, args->elem, 1002, args->state); break; } case 1: { OBJECT_FOR_STATE(obj, pstImage, image, args->state) break; } #else case 0: { OBJECT_FOR_STATE(obj, pstImage, image, args->state) break; } #endif } if (obj != NULL) Tcl_SetObjResult(tree->interp, obj); return TCL_OK; } TreeElementType treeElemTypeImage = { "image", sizeof(ElementImage), imageOptionSpecs, NULL, CreateProcImage, DeleteProcImage, ConfigProcImage, DisplayProcImage, NeededProcImage, NULL, /* heightProc */ WorldChangedProcImage, StateProcImage, UndefProcImage, ActualProcImage, NULL /* onScreenProc */ }; /*****/ typedef struct ElementRect ElementRect; struct ElementRect { TreeElement_ header; #ifdef DEPRECATED PerStateInfo draw; #endif int width; Tcl_Obj *widthObj; int height; Tcl_Obj *heightObj; PerStateInfo fill; PerStateInfo outline; int outlineWidth; Tcl_Obj *outlineWidthObj; PerStateInfo open; int showFocus; int rx; Tcl_Obj *rxObj; int ry; Tcl_Obj *ryObj; }; #define RECT_CONF_FILL 0x0001 #define RECT_CONF_OUTLINE 0x0002 #define RECT_CONF_OUTWIDTH 0x0004 #define RECT_CONF_OPEN 0x0008 #define RECT_CONF_SIZE 0x0010 #define RECT_CONF_FOCUS 0x0020 #define RECT_CONF_RADIUS 0x0040 #ifdef DEPRECATED #define RECT_CONF_DRAW 0x0080 #endif static Tk_OptionSpec rectOptionSpecs[] = { #ifdef DEPRECATED {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementRect, draw.obj), Tk_Offset(ElementRect, draw), TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_DRAW}, #endif {TK_OPTION_CUSTOM, "-fill", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementRect, fill.obj), Tk_Offset(ElementRect, fill), TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_FILL}, {TK_OPTION_PIXELS, "-height", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementRect, heightObj), Tk_Offset(ElementRect, height), TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_SIZE}, {TK_OPTION_CUSTOM, "-open", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementRect, open.obj), Tk_Offset(ElementRect, open), TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_OPEN}, {TK_OPTION_CUSTOM, "-outline", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementRect, outline.obj), Tk_Offset(ElementRect, outline), TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_OUTLINE}, {TK_OPTION_PIXELS, "-outlinewidth", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementRect, outlineWidthObj), Tk_Offset(ElementRect, outlineWidth), TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_OUTWIDTH}, {TK_OPTION_PIXELS, "-rx", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementRect, rxObj), Tk_Offset(ElementRect, rx), TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_RADIUS}, {TK_OPTION_PIXELS, "-ry", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementRect, ryObj), Tk_Offset(ElementRect, ry), TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_RADIUS}, {TK_OPTION_CUSTOM, "-showfocus", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementRect, showFocus), TK_OPTION_NULL_OK, (ClientData) &booleanCO, RECT_CONF_FOCUS}, {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementRect, widthObj), Tk_Offset(ElementRect, width), TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_SIZE}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} }; static void DeleteProcRect(TreeElementArgs *args) { /* TreeCtrl *tree = args->tree; ElementRect *elemX = (ElementRect *) args->elem;*/ } static int WorldChangedProcRect(TreeElementArgs *args) { int flagM = args->change.flagMaster; int flagS = args->change.flagSelf; int mask = 0; if ((flagS | flagM) & (RECT_CONF_SIZE | RECT_CONF_OUTWIDTH)) mask |= CS_DISPLAY | CS_LAYOUT; if ((flagS | flagM) & ( #ifdef DEPRECATED RECT_CONF_DRAW | #endif RECT_CONF_FILL | RECT_CONF_OUTLINE | RECT_CONF_OPEN | RECT_CONF_FOCUS | RECT_CONF_RADIUS)) mask |= CS_DISPLAY; return mask; } static int ConfigProcRect(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementRect *elemX = (ElementRect *) elem; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, elem->stateDomain, elemX, elem->typePtr->optionTable, args->config.objc, args->config.objv, &savedOptions, &args->config.flagSelf) != TCL_OK) { args->config.flagSelf = 0; continue; } Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } return TCL_OK; } static int CreateProcRect(TreeElementArgs *args) { ElementRect *elemX = (ElementRect *) args->elem; elemX->showFocus = -1; return TCL_OK; } static void DisplayProcRect(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementRect *elemX = (ElementRect *) elem; ElementRect *masterX = (ElementRect *) elem->master; int state = args->state; int x = args->display.x, y = args->display.y; int width = args->display.width, height = args->display.height; int match, match2; #ifdef DEPRECATED int draw; #endif TreeColor *tc; TreeRectangle tr; TreeRectangle trBrush; TreeClip clip, *clipPtr = &clip; int open = 0; int outlineWidth = 0; int showFocus = 0; int rx = 0, ry = 0; #ifdef DEPRECATED BOOLEAN_FOR_STATE(draw, draw, state) if (!draw) return; #endif if (elemX->outlineWidthObj != NULL) outlineWidth = elemX->outlineWidth; else if ((masterX != NULL) && (masterX->outlineWidthObj != NULL)) outlineWidth = masterX->outlineWidth; FLAGS_FOR_STATE(open, open, state) if (open == 0xFFFFFFFF) /* unspecified */ open = 0; if (elemX->showFocus != -1) showFocus = elemX->showFocus; else if ((masterX != NULL) && (masterX->showFocus != -1)) showFocus = masterX->showFocus; if (elemX->widthObj != NULL) width = elemX->width; else if ((masterX != NULL) && (masterX->widthObj != NULL)) width = masterX->width; if (elemX->heightObj != NULL) height = elemX->height; else if ((masterX != NULL) && (masterX->heightObj != NULL)) height = masterX->height; if (elemX->rxObj != NULL) rx = elemX->rx; else if ((masterX != NULL) && (masterX->rxObj != NULL)) rx = masterX->rx; if (elemX->ryObj != NULL) ry = elemX->ry; else if ((masterX != NULL) && (masterX->ryObj != NULL)) ry = masterX->ry; AdjustForSticky(args->display.sticky, args->display.width, args->display.height, TRUE, TRUE, &x, &y, &width, &height); TreeRect_SetXYWH(tr, x, y, width, height); #if USE_ITEM_PIXMAP == 0 clip.type = TREE_CLIP_RECT; clip.tr = args->display.bounds; #else clipPtr = NULL; #endif if (rx < 1 && ry < 1) rx = ry = 0; else if (ry < 1) ry = rx; else if (rx < 1) rx = ry; rx = MIN(rx, width/2); ry = MIN(ry, height/2); if (rx >= 1 && ry >= 1) { TREECOLOR_FOR_STATE(tc, fill, state) if (tc != NULL) { TreeColor_GetBrushBounds(tree, tc, tr, tree->drawableXOrigin, tree->drawableYOrigin, args->display.column, args->display.item, &trBrush); TreeColor_FillRoundRect(tree, args->display.td, clipPtr, tc, trBrush, tr, rx, ry, open); } TREECOLOR_FOR_STATE(tc, outline, state) if ((tc != NULL) && (outlineWidth > 0) && (open != RECT_OPEN_WNES)) { TreeColor_GetBrushBounds(tree, tc, tr, tree->drawableXOrigin, tree->drawableYOrigin, args->display.column, args->display.item, &trBrush); TreeColor_DrawRoundRect(tree, args->display.td, clipPtr, tc, trBrush, tr, outlineWidth, rx, ry, open); } /* FIXME: its not round! */ if (showFocus && (state & STATE_ITEM_FOCUS) && (state & STATE_ITEM_ACTIVE)) { Tree_DrawActiveOutline(tree, args->display.drawable, args->display.x, args->display.y, args->display.width, args->display.height, open); } return; } TREECOLOR_FOR_STATE(tc, fill, state) if (tc != NULL) { TreeColor_GetBrushBounds(tree, tc, tr, tree->drawableXOrigin, tree->drawableYOrigin, args->display.column, args->display.item, &trBrush); TreeColor_FillRect(tree, args->display.td, clipPtr, tc, trBrush, tr); } TREECOLOR_FOR_STATE(tc, outline, state) if ((tc != NULL) && (outlineWidth > 0) && (open != RECT_OPEN_WNES)) { TreeColor_GetBrushBounds(tree, tc, tr, tree->drawableXOrigin, tree->drawableYOrigin, args->display.column, args->display.item, &trBrush); TreeColor_DrawRect(tree, args->display.td, clipPtr, tc, trBrush, tr, outlineWidth, open); } if (showFocus && (state & STATE_ITEM_FOCUS) && (state & STATE_ITEM_ACTIVE)) { Tree_DrawActiveOutline(tree, args->display.drawable, args->display.x, args->display.y, args->display.width, args->display.height, open); } } static void NeededProcRect(TreeElementArgs *args) { TreeElement elem = args->elem; ElementRect *elemX = (ElementRect *) elem; ElementRect *masterX = (ElementRect *) elem->master; int width = 0, height = 0; int outlineWidth = 0; if (elemX->outlineWidthObj != NULL) outlineWidth = elemX->outlineWidth; else if ((masterX != NULL) && (masterX->outlineWidthObj != NULL)) outlineWidth = masterX->outlineWidth; if (elemX->widthObj != NULL) width = elemX->width; else if ((masterX != NULL) && (masterX->widthObj != NULL)) width = masterX->width; if (elemX->heightObj != NULL) height = elemX->height; else if ((masterX != NULL) && (masterX->heightObj != NULL)) height = masterX->height; args->needed.width = MAX(width, outlineWidth * 2); args->needed.height = MAX(height, outlineWidth * 2); } static int StateProcRect(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementRect *elemX = (ElementRect *) elem; ElementRect *masterX = (ElementRect *) elem->master; int match, match2; #ifdef DEPRECATED int draw1, draw2; #endif int open1, open2; XColor *c1, *c2; TreeColor *tc1, *tc2; int s1, s2; int showFocus = 0; /* If either the -draw or -visible layout option is false for the * current state, then changes to colors etc don't warrant a redisplay. */ if (!args->states.visible2 || !args->states.draw2) return 0; #ifdef DEPRECATED BOOLEAN_FOR_STATE(draw1, draw, args->states.state1) BOOLEAN_FOR_STATE(draw2, draw, args->states.state2) if ((draw1 != 0) != (draw2 != 0)) return CS_DISPLAY; /* If the element isn't drawn, then changes to colors etc don't * warrant a redisplay. */ if (draw2 == 0) return 0; #endif if (elemX->showFocus != -1) showFocus = elemX->showFocus; else if ((masterX != NULL) && (masterX->showFocus != -1)) showFocus = masterX->showFocus; s1 = showFocus && (args->states.state1 & STATE_ITEM_FOCUS) && (args->states.state1 & STATE_ITEM_ACTIVE); s2 = showFocus && (args->states.state2 & STATE_ITEM_FOCUS) && (args->states.state2 & STATE_ITEM_ACTIVE); if (s1 != s2) return CS_DISPLAY; TREECOLOR_FOR_STATE(tc1, fill, args->states.state1) TREECOLOR_FOR_STATE(tc2, fill, args->states.state2) if (TREECOLOR_CMP(tc1, tc2)) return CS_DISPLAY; FLAGS_FOR_STATE(open1, open, args->states.state1) FLAGS_FOR_STATE(open2, open, args->states.state2) if (open1 != open2) return CS_DISPLAY; COLOR_FOR_STATE(c1, outline, args->states.state1) COLOR_FOR_STATE(c2, outline, args->states.state2) if (c1 != c2) return CS_DISPLAY; return 0; } static int UndefProcRect(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementRect *elemX = (ElementRect *) elem; int modified = 0; #ifdef DEPRECATED modified |= PerStateInfo_Undefine(tree, &pstBoolean, &elemX->draw, elem->stateDomain, args->state); #endif modified |= PerStateInfo_Undefine(tree, &pstColor, &elemX->fill, elem->stateDomain, args->state); modified |= PerStateInfo_Undefine(tree, &pstFlags, &elemX->open, elem->stateDomain, args->state); modified |= PerStateInfo_Undefine(tree, &pstColor, &elemX->outline, elem->stateDomain, args->state); return modified; } static int ActualProcRect(TreeElementArgs *args) { TreeCtrl *tree = args->tree; ElementRect *elemX = (ElementRect *) args->elem; ElementRect *masterX = (ElementRect *) args->elem->master; static CONST char *optionName[] = { #ifdef DEPRECATED "-draw", #endif "-fill", "-open", "-outline", (char *) NULL }; enum optionEnum { #ifdef DEPRECATED OPT_DRAW, #endif OPT_FILL, OPT_OPEN, OPT_OUTLINE }; int index, match, matchM; Tcl_Obj *obj = NULL; if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, "option", 0, &index) != TCL_OK) return TCL_ERROR; switch ((enum optionEnum) index) { #ifdef DEPRECATED case OPT_DRAW: { OBJECT_FOR_STATE(obj, pstBoolean, draw, args->state) break; } #endif case OPT_FILL: { OBJECT_FOR_STATE(obj, pstColor, fill, args->state) break; } case OPT_OPEN: { OBJECT_FOR_STATE(obj, pstFlags, open, args->state) break; } case OPT_OUTLINE: { OBJECT_FOR_STATE(obj, pstColor, outline, args->state) break; } } if (obj != NULL) Tcl_SetObjResult(tree->interp, obj); return TCL_OK; } TreeElementType treeElemTypeRect = { "rect", sizeof(ElementRect), rectOptionSpecs, NULL, CreateProcRect, DeleteProcRect, ConfigProcRect, DisplayProcRect, NeededProcRect, NULL, /* heightProc */ WorldChangedProcRect, StateProcRect, UndefProcRect, ActualProcRect, NULL /* onScreenProc */ }; /*****/ typedef struct ElementText ElementText; struct ElementText { TreeElement_ header; char *textCfg; /* -text */ char *text; /* This will be the same as textCfg, or it * will be a dynamically allocated string * from any -data or -textvariable. */ #define STRINGREP_INVALID -1 int textLen; /* Number of bytes (not characters) in the * UTF-8 string. If -1, it means the string * representation is invalid. */ }; #define TEXTVAR /* for Tk_SetOptions() */ #define TEXT_CONF_LAYOUT 0x0001 #define TEXT_CONF_DISPLAY 0x0002 #define TEXT_CONF_STRINGREP 0x0040 #ifdef TEXTVAR #define TEXT_CONF_TEXTVAR 0x0080 #endif /* * Dynamic option ids for the text element. */ #define DOID_TEXT_VAR 1001 #define DOID_TEXT_DRAW 1002 #define DOID_TEXT_FILL 1003 #define DOID_TEXT_FONT 1004 #define DOID_TEXT_LAYOUT 1005 #define DOID_TEXT_DATA 1006 #define DOID_TEXT_LAYOUT2 1007 #define DOID_TEXT_STYLE 1008 #define DOID_TEXT_LAYOUT3 1009 typedef struct ElementTextData { Tcl_Obj *dataObj; /* -data */ #define TDT_NULL -1 #define TDT_DOUBLE 0 #define TDT_INTEGER 1 #define TDT_LONG 2 #define TDT_STRING 3 #define TDT_TIME 4 int dataType; /* -datatype */ Tcl_Obj *formatObj; /* -format */ } ElementTextData; typedef struct ElementTextLayout { #define TK_JUSTIFY_NULL -1 int justify; /* -justify */ int lines; /* -lines */ Tcl_Obj *widthObj; /* -width */ int width; /* -width */ #define TEXT_WRAP_NULL -1 #define TEXT_WRAP_CHAR 0 #define TEXT_WRAP_NONE 1 #define TEXT_WRAP_WORD 2 int wrap; /* -wrap */ } ElementTextLayout; /* This structure doesn't hold any option values, but it is managed by * the dynamic-option code. */ typedef struct ElementTextLayout2 { TextLayout layout; int layoutWidth; int neededWidth; int totalWidth; } ElementTextLayout2; typedef struct ElementTextLayout3 { Tcl_Obj *lMargin1Obj; /* -lmargin1 */ int lMargin1; /* -lmargin2 */ Tcl_Obj *lMargin2Obj; /* -lmargin1 */ int lMargin2; /* -lmargin2 */ } ElementTextLayout3; #define TEXT_STYLE #ifdef TEXT_STYLE typedef struct ElementTextStyle { int underline; /* -underline */ } ElementTextStyle; /* Called by the dynamic-option code when an ElementTextData is allocated. */ static void ElementTextStyleInit( void *data ) { ElementTextStyle *ets = data; #define TEXT_UNDERLINE_EMPTYVAL -100000 ets->underline = TEXT_UNDERLINE_EMPTYVAL; } #endif #ifdef TEXTVAR typedef struct ElementTextVar { Tcl_Obj *varNameObj; /* -textvariable */ TreeCtrl *tree; /* needed to redisplay */ TreeItem item; /* needed to redisplay */ TreeItemColumn column; /* needed to redisplay */ } ElementTextVar; #endif /* Called by the dynamic-option code when an ElementTextData is allocated. */ static void ElementTextDataInit( void *data ) { ElementTextData *etd = data; etd->dataType = TDT_NULL; } /* Called by the dynamic-option code when an ElementTextLayout is allocated. */ static void ElementTextLayoutInit( void *data ) { ElementTextLayout *etl = data; etl->justify = TK_JUSTIFY_NULL; etl->lines = -1; etl->wrap = TEXT_WRAP_NULL; } static CONST char *textDataTypeST[] = { "double", "integer", "long", "string", "time", (char *) NULL }; static CONST char *textJustifyST[] = { "left", "right", "center", (char *) NULL }; static CONST char *textWrapST[] = { "char", "none", "word", (char *) NULL }; static Tk_OptionSpec textOptionSpecs[] = { {TK_OPTION_CUSTOM, "-data", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_STRINGREP}, {TK_OPTION_CUSTOM, "-datatype", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_STRINGREP}, #ifdef DEPRECATED {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_DISPLAY}, #endif {TK_OPTION_CUSTOM, "-fill", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_DISPLAY}, {TK_OPTION_CUSTOM, "-font", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, {TK_OPTION_CUSTOM, "-format", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_STRINGREP}, {TK_OPTION_CUSTOM, "-justify", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, {TK_OPTION_CUSTOM, "-lines", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, {TK_OPTION_CUSTOM, "-lmargin1", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, {TK_OPTION_CUSTOM, "-lmargin2", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, {TK_OPTION_STRING, "-text", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementText, textCfg), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_STRINGREP}, #ifdef TEXTVAR {TK_OPTION_CUSTOM, "-textvariable", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_STRINGREP | TEXT_CONF_TEXTVAR}, #endif #ifdef TEXT_STYLE {TK_OPTION_CUSTOM, "-underline", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_DISPLAY}, #endif {TK_OPTION_CUSTOM, "-width", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, {TK_OPTION_CUSTOM, "-wrap", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeElement_, options), TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, 0, 0} }; static int WorldChangedProcText(TreeElementArgs *args) { /* TreeCtrl *tree = args->tree;*/ TreeElement elem = args->elem; ElementText *elemX = (ElementText *) elem; /* ElementText *masterX = (ElementText *) elem->master;*/ int flagT = args->change.flagTree; int flagM = args->change.flagMaster; int flagS = args->change.flagSelf; int mask = 0; if ((flagS | flagM) & TEXT_CONF_STRINGREP) { elemX->textLen = STRINGREP_INVALID; } if ((elemX->textLen == STRINGREP_INVALID) || ((flagS | flagM) & TEXT_CONF_LAYOUT) || /* Not needed if this element has its own font. */ (flagT & TREE_CONF_FONT)) { mask |= CS_DISPLAY | CS_LAYOUT; } if ((flagS | flagM) & TEXT_CONF_DISPLAY) mask |= CS_DISPLAY; return mask; } static void TextUpdateStringRep(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementText *elemX = (ElementText *) elem; ElementText *masterX = (ElementText *) elem->master; Tcl_Obj *dataObj, *formatObj; char *text; ElementTextData *etd, *etdM = NULL; #ifdef TEXTVAR ElementTextVar *etv; Tcl_Obj *varNameObj; #endif int dataType; /* Free any string allocated as a result of -data or -textvariable. */ if ((elemX->text != NULL) && (elemX->text != elemX->textCfg)) { ckfree(elemX->text); } /* Forget any string, and mark the string rep as no-longer invalid. */ elemX->text = NULL; elemX->textLen = 0; /* If -text is specified, then -data and -textvariable are ignored. */ if (elemX->textCfg != NULL) { elemX->text = elemX->textCfg; elemX->textLen = (int) strlen(elemX->textCfg); return; } #ifdef TEXTVAR etv = DynamicOption_FindData(elem->options, DOID_TEXT_VAR); varNameObj = etv ? etv->varNameObj : NULL; if (varNameObj != NULL) { Tcl_Obj *valueObj = Tcl_ObjGetVar2(tree->interp, varNameObj, NULL, TCL_GLOBAL_ONLY); if (valueObj == NULL) { /* not possible I think */ } else { /* FIXME: do I need to allocate a copy, or can I just point * to the internal rep of the string object? */ text = Tcl_GetStringFromObj(valueObj, &elemX->textLen); if (elemX->textLen > 0) { elemX->text = ckalloc(elemX->textLen); memcpy(elemX->text, text, elemX->textLen); } } return; } #endif etd = DynamicOption_FindData(elem->options, DOID_TEXT_DATA); if (masterX != NULL) etdM = DynamicOption_FindData(elem->master->options, DOID_TEXT_DATA); dataObj = etd ? etd->dataObj : NULL; if ((dataObj == NULL) && (etdM != NULL)) dataObj = etdM->dataObj; dataType = etd ? etd->dataType : TDT_NULL; if ((dataType == TDT_NULL) && (etdM != NULL)) dataType = etdM->dataType; formatObj = etd ? etd->formatObj : NULL; if ((formatObj == NULL) && (etdM != NULL)) formatObj = etdM->formatObj; /* Only create a string rep if elemX (not masterX) has dataObj, dataType or formatObj. */ if ((dataObj != NULL) && (dataType != TDT_NULL) && ((etd != NULL) && ((etd->dataObj != NULL) || (etd->dataType != TDT_NULL) || (etd->formatObj != NULL)))) { int objc = 0; Tcl_Obj *objv[5], *resultObj = NULL; Tcl_ObjCmdProc *clockObjCmd = NULL, *formatObjCmd = NULL; ClientData clockClientData = NULL, formatClientData = NULL; Tcl_CmdInfo cmdInfo; if (Tcl_GetCommandInfo(tree->interp, "::clock", &cmdInfo) == 1) { clockObjCmd = cmdInfo.objProc; clockClientData = cmdInfo.objClientData; } if (Tcl_GetCommandInfo(tree->interp, "::format", &cmdInfo) == 1) { formatObjCmd = cmdInfo.objProc; formatClientData = cmdInfo.objClientData; } /* Important to remove any shared result object, otherwise * calls like Tcl_SetStringObj(Tcl_GetObjResult()) fail. */ Tcl_ResetResult(tree->interp); switch (dataType) { case TDT_DOUBLE: if (formatObjCmd == NULL) break; if (formatObj == NULL) formatObj = tree->formatFloatObj; objv[objc++] = tree->stringFormatObj; objv[objc++] = formatObj; objv[objc++] = dataObj; if (formatObjCmd(formatClientData, tree->interp, objc, objv) == TCL_OK) resultObj = Tcl_GetObjResult(tree->interp); break; case TDT_INTEGER: if (formatObjCmd == NULL) break; if (formatObj == NULL) formatObj = tree->formatIntObj; objv[objc++] = tree->stringFormatObj; objv[objc++] = formatObj; objv[objc++] = dataObj; if (formatObjCmd(formatClientData, tree->interp, objc, objv) == TCL_OK) resultObj = Tcl_GetObjResult(tree->interp); break; case TDT_LONG: if (formatObjCmd == NULL) break; if (formatObj == NULL) formatObj = tree->formatLongObj;; objv[objc++] = tree->stringFormatObj; objv[objc++] = formatObj; objv[objc++] = dataObj; if (formatObjCmd(formatClientData, tree->interp, objc, objv) == TCL_OK) resultObj = Tcl_GetObjResult(tree->interp); break; case TDT_STRING: if (formatObjCmd == NULL) break; if (formatObj == NULL) formatObj = tree->formatStringObj;; objv[objc++] = tree->stringFormatObj; objv[objc++] = formatObj; objv[objc++] = dataObj; if (formatObjCmd(formatClientData, tree->interp, objc, objv) == TCL_OK) resultObj = Tcl_GetObjResult(tree->interp); break; case TDT_TIME: if (clockObjCmd == NULL) break; objv[objc++] = tree->stringClockObj; objv[objc++] = tree->stringFormatObj; objv[objc++] = dataObj; if (formatObj != NULL) { objv[objc++] = tree->optionFormatObj; objv[objc++] = formatObj; } if (clockObjCmd(clockClientData, tree->interp, objc, objv) == TCL_OK) resultObj = Tcl_GetObjResult(tree->interp); break; default: panic("unknown ElementText dataType"); break; } if (resultObj != NULL) { text = Tcl_GetStringFromObj(resultObj, &elemX->textLen); if (elemX->textLen > 0) { elemX->text = ckalloc(elemX->textLen); memcpy(elemX->text, text, elemX->textLen); } } } } static ElementTextLayout2 * TextUpdateLayout( char *func, TreeElementArgs *args, int fixedWidth, int maxWidth ) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementText *elemX = (ElementText *) elem; ElementText *masterX = (ElementText *) elem->master; int state = args->state; int inHeader = elem->stateDomain == STATE_DOMAIN_HEADER; Tk_Font tkfont; char *text = NULL; int textLen = 0; int justify = TK_JUSTIFY_LEFT; int lines = 0; int wrap = TEXT_WRAP_WORD; int width = 0; int flags = 0; int i, multiLine = FALSE; int textWidth; ElementTextLayout *etl, *etlM = NULL; ElementTextLayout2 *etl2; ElementTextLayout3 *etl3, *etl3M = NULL; DynamicOption *opt; int lMargin1 = 0, lMargin2 = 0; if (tree->debug.enable && tree->debug.textLayout) dbwin("TextUpdateLayout: %s %p (%s) %s\n fixedWidth %d maxWidth %d\n", Tk_PathName(tree->tkwin), elemX, masterX ? "instance" : "master", func, fixedWidth, maxWidth); etl2 = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT2); if (etl2 != NULL && etl2->layout != NULL) { if (tree->debug.enable && tree->debug.textLayout) dbwin(" FREE\n"); TextLayout_Free(etl2->layout); etl2->layout = NULL; } if (elemX->text != NULL) { text = elemX->text; textLen = elemX->textLen; } else if ((masterX != NULL) && (masterX->text != NULL)) { text = masterX->text; textLen = masterX->textLen; } if ((text == NULL) || (textLen == 0)) return etl2; etl = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT); if (masterX != NULL) etlM = DynamicOption_FindData(elem->master->options, DOID_TEXT_LAYOUT); if (etl != NULL && etl->lines != -1) lines = etl->lines; else if (etlM != NULL && etlM->lines != -1) lines = etlM->lines; if (lines == 1) return etl2; tkfont = DO_FontForState(tree, elem, DOID_TEXT_FONT, state); if (tkfont == NULL) tkfont = inHeader ? tree->tkfontHeader : tree->tkfont; if (etl != NULL && etl->wrap != TEXT_WRAP_NULL) wrap = etl->wrap; else if (etlM != NULL && etlM->wrap != TEXT_WRAP_NULL) wrap = etlM->wrap; if (wrap != TEXT_WRAP_NONE) { if (fixedWidth >= 0) width = fixedWidth; else if (maxWidth >= 0) width = maxWidth; if (etl != NULL && etl->widthObj != NULL) { if (!width || (etl->width < width)) width = etl->width; } else if ((etlM != NULL) && (etlM->widthObj != NULL)) { if (!width || (etlM->width < width)) width = etlM->width; } } for (i = 0; i < textLen; i++) { if ((text[i] == '\n') || (text[i] == '\r')) { multiLine = TRUE; break; } } if (tree->debug.enable && tree->debug.textLayout) dbwin(" lines %d multiLine %d width %d wrap %s\n", lines, multiLine, width, textWrapST[wrap]); if (!multiLine) { if (width == 0) return etl2; textWidth = Tk_TextWidth(tkfont, text, textLen); if (tree->debug.enable && tree->debug.textLayout) dbwin(" available width %d textWidth %d\n", width, textWidth); if (width >= textWidth) return etl2; } if (etl != NULL && etl->justify != TK_JUSTIFY_NULL) justify = etl->justify; else if (etlM != NULL && etlM->justify != TK_JUSTIFY_NULL) justify = etlM->justify; if (wrap == TEXT_WRAP_WORD) flags |= TK_WHOLE_WORDS; if (etl2 == NULL) { opt = (DynamicOption *) DynamicOption_AllocIfNeeded(tree, &elem->options, DOID_TEXT_LAYOUT2, sizeof(ElementTextLayout2), NULL); etl2 = (ElementTextLayout2 *) opt->data; /* It is possible that the needed size of this element does not * require a TextLayout, in which case neededWidth never gets * set. */ etl2->neededWidth = -1; } etl3 = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT3); if (masterX != NULL) etl3M = DynamicOption_FindData(elem->master->options, DOID_TEXT_LAYOUT3); if (etl3 != NULL && etl3->lMargin1Obj != NULL) lMargin1 = etl3->lMargin1; else if (etl3M != NULL && etl3M->lMargin1Obj != NULL) lMargin1 = etl3M->lMargin1; if (etl3 != NULL && etl3->lMargin2Obj != NULL) lMargin2 = etl3->lMargin2; else if (etl3M != NULL && etl3M->lMargin2Obj != NULL) lMargin2 = etl3M->lMargin2; etl2->layout = TextLayout_Compute(tkfont, text, Tcl_NumUtfChars(text, textLen), width, justify, lines, lMargin1, lMargin2, flags); if (tree->debug.enable && tree->debug.textLayout) dbwin(" ALLOC\n"); return etl2; } #ifdef TEXTVAR static Tcl_VarTraceProc VarTraceProc_Text; static void TextTraceSet(Tcl_Interp *interp, ElementText *elemX) { ElementTextVar *etv = DynamicOption_FindData(elemX->header.options, DOID_TEXT_VAR); Tcl_Obj *varNameObj = etv ? etv->varNameObj : NULL; if (varNameObj != NULL) { Tcl_TraceVar2(interp, Tcl_GetString(varNameObj), NULL, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, VarTraceProc_Text, (ClientData) elemX); } } static void TextTraceUnset(Tcl_Interp *interp, ElementText *elemX) { ElementTextVar *etv = DynamicOption_FindData(elemX->header.options, DOID_TEXT_VAR); Tcl_Obj *varNameObj = etv ? etv->varNameObj : NULL; if (varNameObj != NULL) { Tcl_UntraceVar2(interp, Tcl_GetString(varNameObj), NULL, TCL_GLOBAL_ONLY | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, VarTraceProc_Text, (ClientData) elemX); } } static char *VarTraceProc_Text(ClientData clientData, Tcl_Interp *interp, CONST char *name1, CONST char *name2, int flags) { ElementText *elemX = (ElementText *) clientData; ElementTextVar *etv = DynamicOption_FindData(elemX->header.options, DOID_TEXT_VAR); Tcl_Obj *varNameObj = etv ? etv->varNameObj : NULL; Tcl_Obj *valueObj; /* * If the variable is unset, then immediately recreate it unless * the whole interpreter is going away. */ if (flags & TCL_TRACE_UNSETS) { if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { /* Use the current string if it is valid. */ if (elemX->textLen > 0) { valueObj = Tcl_NewStringObj(elemX->text, elemX->textLen); } else { valueObj = Tcl_NewStringObj("", 0); } Tcl_IncrRefCount(valueObj); Tcl_ObjSetVar2(interp, varNameObj, NULL, valueObj, TCL_GLOBAL_ONLY); Tcl_DecrRefCount(valueObj); TextTraceSet(interp, elemX); } return (char *) NULL; } elemX->textLen = STRINGREP_INVALID; Tree_ElementChangedItself(etv->tree, etv->item, etv->column, (TreeElement) elemX, TEXT_CONF_LAYOUT | TEXT_CONF_TEXTVAR, CS_LAYOUT | CS_DISPLAY); return (char *) NULL; } #endif /* TEXTVAR */ static void DeleteProcText(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementText *elemX = (ElementText *) elem; ElementTextLayout2 *etl2; if ((elemX->textCfg == NULL) && (elemX->text != NULL)) { ckfree(elemX->text); elemX->text = NULL; } etl2 = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT2); if (etl2 != NULL && etl2->layout != NULL) TextLayout_Free(etl2->layout); DynamicOption_Free1(tree, &elem->options, DOID_TEXT_LAYOUT2, sizeof(ElementTextLayout2)); #ifdef TEXTVAR TextTraceUnset(tree->interp, elemX); #endif } static int ConfigProcText(TreeElementArgs *args) { TreeCtrl *tree = args->tree; Tcl_Interp *interp = tree->interp; TreeElement elem = args->elem; ElementText *elemX = (ElementText *) elem; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; char *textCfg = elemX->textCfg; #ifdef TEXTVAR ElementTextVar *etv; Tcl_Obj *varNameObj; #endif #ifdef TEXTVAR TextTraceUnset(interp, elemX); #endif for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, elem->stateDomain, elemX, elem->typePtr->optionTable, args->config.objc, args->config.objv, &savedOptions, &args->config.flagSelf) != TCL_OK) { args->config.flagSelf = 0; continue; } #ifdef TEXTVAR etv = DynamicOption_FindData(elem->options, DOID_TEXT_VAR); if (etv != NULL) { etv->tree = tree; etv->item = args->config.item; etv->column = args->config.column; varNameObj = etv->varNameObj; } else varNameObj = NULL; if (varNameObj != NULL) { Tcl_Obj *valueObj; valueObj = Tcl_ObjGetVar2(interp, varNameObj, NULL, TCL_GLOBAL_ONLY); if (valueObj == NULL) { valueObj = Tcl_NewStringObj("", 0); Tcl_IncrRefCount(valueObj); /* This validates the variable name. We get an error * if it is the name of an array */ if (Tcl_ObjSetVar2(interp, varNameObj, NULL, valueObj, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) { Tcl_DecrRefCount(valueObj); continue; } Tcl_DecrRefCount(valueObj); } } #endif Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); } } /* If -text was specified, then do not try to free the old value in * TextUpdateStringRep. */ if (textCfg != elemX->textCfg && elemX->text == textCfg) elemX->text = NULL; #ifdef TEXTVAR TextTraceSet(interp, elemX); #endif if (error) { Tcl_SetObjResult(interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } return TCL_OK; } static int CreateProcText(TreeElementArgs *args) { /* ElementText *elemX = (ElementText *) args->elem;*/ return TCL_OK; } static ElementTextLayout2 * TextRedoLayoutIfNeeded( char *func, TreeElementArgs *args, int fixedWidth ) { TreeElement elem = args->elem; /* ElementText *elemX = (ElementText *) elem;*/ ElementText *masterX = (ElementText *) elem->master; int doLayout = 0; int wrap = TEXT_WRAP_WORD; ElementTextLayout *etl, *etlM = NULL; ElementTextLayout2 *etl2; etl = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT); if (masterX != NULL) etlM = DynamicOption_FindData(elem->master->options, DOID_TEXT_LAYOUT); etl2 = DynamicOption_FindData(elem->options, DOID_TEXT_LAYOUT2); /* If text wrapping is disabled, the layout doesn't change */ if (etl != NULL && etl->wrap != TEXT_WRAP_NULL) wrap = etl->wrap; else if ((etlM != NULL) && (etlM->wrap != TEXT_WRAP_NULL)) wrap = etlM->wrap; if (wrap == TEXT_WRAP_NONE) return etl2; if (etl2 != NULL && etl2->layout != NULL) { /* See comment in NeededProc about totalWidth */ if ((etl2->neededWidth != -1) && (fixedWidth >= etl2->neededWidth)) fixedWidth = etl2->totalWidth; /* Already layed out at this width */ if (fixedWidth == etl2->layoutWidth) return etl2; } /* May switch from layout -> no layout or vice versa */ if (etl2 == NULL || etl2->layout == NULL) doLayout = 1; /* Width was constrained and we have more space now */ else if ((etl2->layoutWidth != -1) && (fixedWidth > etl2->layoutWidth)) doLayout = 1; /* Width was unconstrained or we have less space now */ else { int width; TextLayout_Size(etl2->layout, &width, NULL); /* Redo if we are narrower than the layout */ if (fixedWidth < width) doLayout = 1; } if (doLayout) etl2 = TextUpdateLayout(func, args, fixedWidth, -1); if (etl2 != NULL) etl2->layoutWidth = (etl2->layout != NULL) ? fixedWidth : -1; return etl2; } static void DisplayProcText(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementText *elemX = (ElementText *) elem; ElementText *masterX = (ElementText *) elem->master; int state = args->state; int x = args->display.x, y = args->display.y; int width, height; #ifdef DEPRECATED int draw; #endif XColor *color; char *text = elemX->text; int textLen = elemX->textLen; Tk_Font tkfont; TextLayout layout = NULL; Tk_FontMetrics fm; GC gc; int bytesThatFit, pixelsForText; char *ellipsis = "..."; TkRegion clipRgn = NULL; ElementTextLayout2 *etl2; #ifdef TEXT_STYLE ElementTextStyle *ets, *etsM = NULL; int underline = TEXT_UNDERLINE_EMPTYVAL; #endif #if USE_ITEM_PIXMAP == 0 TreeRectangle trClip, trElem; #endif int inHeader = elem->stateDomain == STATE_DOMAIN_HEADER; int columnState = COLUMN_STATE_NORMAL; #ifdef DEPRECATED draw = DO_BooleanForState(tree, elem, DOID_TEXT_DRAW, state); if (!draw) return; #endif if ((text == NULL) && (masterX != NULL)) { text = masterX->text; textLen = masterX->textLen; } if (text == NULL) /* always false (or layout sets height/width to zero) */ return; if (inHeader) { if (state & STATE_HEADER_ACTIVE) columnState = COLUMN_STATE_ACTIVE; else if (state & STATE_HEADER_PRESSED) columnState = COLUMN_STATE_PRESSED; } DO_COLOR_FOR_STATE(color, DOID_TEXT_FILL, state); /* If no color is specified and this element is in a header, get the * system theme color. If no theme color is provided then use the default * header text color. */ if ((color == NULL) && inHeader) { if (!tree->useTheme || TreeTheme_GetHeaderTextColor(tree, columnState, &color) != TCL_OK) { color = tree->defHeaderTextColor; } if (color->pixel == tree->defHeaderTextColor->pixel) color = NULL; } tkfont = DO_FontForState(tree, elem, DOID_TEXT_FONT, state); /* FIXME: -font {"" {state...}}*/ if ((color != NULL) || (tkfont != NULL)) { XGCValues gcValues; unsigned long gcMask = 0; if (color == NULL) color = inHeader ? tree->defHeaderTextColor : tree->fgColorPtr; gcValues.foreground = color->pixel; gcMask |= GCForeground; if (tkfont == NULL) tkfont = inHeader ? tree->tkfontHeader : tree->tkfont; gcValues.font = Tk_FontId(tkfont); gcMask |= GCFont; gcValues.graphics_exposures = False; gcMask |= GCGraphicsExposures; gc = Tree_GetGC(tree, gcMask, &gcValues); } else if (inHeader) { tkfont = tree->tkfontHeader; gc = tree->headerTextGC; } else { tkfont = tree->tkfont; gc = tree->textGC; } #ifdef TEXT_STYLE ets = DynamicOption_FindData(elem->options, DOID_TEXT_STYLE); if (ets != NULL && ets->underline != TEXT_UNDERLINE_EMPTYVAL) underline = ets->underline; else if (masterX != NULL) { etsM = DynamicOption_FindData(elem->master->options, DOID_TEXT_STYLE); if (etsM != NULL && etsM->underline != TEXT_UNDERLINE_EMPTYVAL) underline = etsM->underline; } #endif etl2 = TextRedoLayoutIfNeeded("DisplayProcText", args, args->display.width); if (etl2 != NULL && etl2->layout != NULL) layout = etl2->layout; if (layout != NULL) { TextLayout_Size(layout, &width, &height); pixelsForText = width; /* Hack -- The actual size of the text may be slightly smaller than * the available space when squeezed. If so we don't want to center * the text horizontally */ if ((etl2->neededWidth == -1) || (etl2->neededWidth > width)) width = args->display.width; AdjustForSticky(args->display.sticky, args->display.width, args->display.height, FALSE, FALSE, &x, &y, &width, &height); #if HEADER_OFFSET_HACK == 1 /* FIXME: should have a layout option to control this. */ if (inHeader && columnState == COLUMN_STATE_PRESSED) x += 1, y += 1; #endif #if USE_ITEM_PIXMAP == 0 /* Use clipping if text is larger than the display area. */ trElem.x = x, trElem.y = y, trElem.width = args->display.width, trElem.height = args->display.height; if (TreeRect_Intersect(&trClip, &trElem, &args->display.bounds)) { clipRgn = Tree_GetRectRegion(tree, &trClip); TkSetRegion(tree->display, gc, clipRgn); } else { return; } #else /* Use clipping if text is larger than the display area. */ if (pixelsForText > args->display.width || height > args->display.height) { XRectangle rect; clipRgn = Tree_GetRegion(tree); rect.x = x; rect.y = y; rect.width = args->display.width; rect.height = args->display.height; TkUnionRectWithRegion(&rect, clipRgn, clipRgn); TkSetRegion(tree->display, gc, clipRgn); } #endif TextLayout_Draw(tree->display, args->display.drawable, gc, layout, x, y, 0, -1, underline); if (clipRgn != NULL) { Tree_UnsetClipMask(tree, args->display.drawable, gc); Tree_FreeRegion(tree, clipRgn); } return; } Tk_GetFontMetrics(tkfont, &fm); pixelsForText = args->display.width; bytesThatFit = Tree_Ellipsis(tkfont, text, textLen, &pixelsForText, ellipsis, FALSE); width = pixelsForText, height = fm.linespace; /* Hack -- The actual size of the text may be slightly smaller than * the available space when squeezed. If so we don't want to center * the text horizontally */ if (bytesThatFit != textLen) width = args->display.width; AdjustForSticky(args->display.sticky, args->display.width, args->display.height, FALSE, FALSE, &x, &y, &width, &height); #if HEADER_OFFSET_HACK == 1 /* FIXME: should have a layout option to control this. */ if (inHeader && columnState == COLUMN_STATE_PRESSED) x += 1, y += 1; #endif #if USE_ITEM_PIXMAP == 0 /* Use clipping if text is larger than the display area. */ trElem.x = x, trElem.y = y, trElem.width = args->display.width, trElem.height = args->display.height; if (TreeRect_Intersect(&trClip, &trElem, &args->display.bounds)) { clipRgn = Tree_GetRectRegion(tree, &trClip); TkSetRegion(tree->display, gc, clipRgn); } else { return; } #else /* Use clipping if text is larger than the display area. */ if (pixelsForText > args->display.width || height > args->display.height) { XRectangle rect; clipRgn = Tree_GetRegion(tree); rect.x = x; rect.y = y; rect.width = args->display.width; rect.height = args->display.height; TkUnionRectWithRegion(&rect, clipRgn, clipRgn); TkSetRegion(tree->display, gc, clipRgn); } #endif if (bytesThatFit != textLen) { char staticStr[256], *buf = staticStr; int bufLen = abs(bytesThatFit); int ellipsisLen = (int) strlen(ellipsis); if (bufLen + ellipsisLen > sizeof(staticStr)) buf = ckalloc(bufLen + ellipsisLen); memcpy(buf, text, bufLen); if (bytesThatFit > 0) { memcpy(buf + bufLen, ellipsis, ellipsisLen); bufLen += ellipsisLen; } Tk_DrawChars(tree->display, args->display.drawable, gc, tkfont, buf, bufLen, x, y + fm.ascent); #ifdef TEXT_STYLE if (underline >= 0 && underline < Tcl_NumUtfChars(buf, abs(bytesThatFit))) { CONST char *fstBytePtr = Tcl_UtfAtIndex(buf, underline); CONST char *sndBytePtr = Tcl_UtfNext(fstBytePtr); Tk_UnderlineChars(tree->display, args->display.drawable, gc, tkfont, buf, x, y + fm.ascent, (int) (fstBytePtr - buf), (int) (sndBytePtr - buf)); } #endif if (buf != staticStr) ckfree(buf); } else { Tk_DrawChars(tree->display, args->display.drawable, gc, tkfont, text, textLen, x, y + fm.ascent); #ifdef TEXT_STYLE if (underline >= 0 && underline < Tcl_NumUtfChars(text, textLen)) { CONST char *fstBytePtr = Tcl_UtfAtIndex(text, underline); CONST char *sndBytePtr = Tcl_UtfNext(fstBytePtr); Tk_UnderlineChars(tree->display, args->display.drawable, gc, tkfont, text, x, y + fm.ascent, (int) (fstBytePtr - text), (int) (sndBytePtr - text)); } #endif } if (clipRgn != NULL) { Tree_UnsetClipMask(tree, args->display.drawable, gc); Tree_FreeRegion(tree, clipRgn); } } static void NeededProcText(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementText *elemX = (ElementText *) elem; ElementText *masterX = (ElementText *) elem->master; int state = args->state; char *text = NULL; int textLen = 0; Tk_Font tkfont; Tk_FontMetrics fm; int width = 0, height = 0; ElementTextLayout *etl, *etlM = NULL; ElementTextLayout2 *etl2; int inHeader = elem->stateDomain == STATE_DOMAIN_HEADER; etl = DynamicOption_FindData(args->elem->options, DOID_TEXT_LAYOUT); if (masterX != NULL) etlM = DynamicOption_FindData(args->elem->master->options, DOID_TEXT_LAYOUT); if ((masterX != NULL) && (masterX->textLen == STRINGREP_INVALID)) { args->elem = (TreeElement) masterX; TextUpdateStringRep(args); args->elem = elem; } if (elemX->textLen == STRINGREP_INVALID) { TextUpdateStringRep(args); } etl2 = TextUpdateLayout("NeededProcText", args, args->needed.fixedWidth, args->needed.maxWidth); if (etl2 != NULL) { etl2->layoutWidth = -1; etl2->neededWidth = -1; } if (etl2 != NULL && etl2->layout != NULL) { TextLayout_Size(etl2->layout, &width, &height); if (args->needed.fixedWidth >= 0) etl2->layoutWidth = args->needed.fixedWidth; else if (args->needed.maxWidth >= 0) etl2->layoutWidth = args->needed.maxWidth; etl2->neededWidth = width; /* * Hack -- If we call TextLayout_Compute() with the same width * returned by TextLayout_Size(), we may get a different layout. * I think this has to do with whitespace at the end of lines. * So if HeightProc or DisplayProc is given neededWidth, I do the * layout at totalWidth, not neededWidth. */ etl2->totalWidth = TextLayout_TotalWidth(etl2->layout); } else { if (elemX->text != NULL) { text = elemX->text; textLen = elemX->textLen; } else if ((masterX != NULL) && (masterX->text != NULL)) { text = masterX->text; textLen = masterX->textLen; } if (textLen > 0) { int maxWidth = -1; tkfont = DO_FontForState(tree, elem, DOID_TEXT_FONT, state); if (tkfont == NULL) tkfont = inHeader ? tree->tkfontHeader : tree->tkfont; width = Tk_TextWidth(tkfont, text, textLen); if (etl != NULL && etl->widthObj != NULL) maxWidth = etl->width; else if ((etlM != NULL) && (etlM->widthObj != NULL)) maxWidth = etlM->width; if ((maxWidth >= 0) && (maxWidth < width)) width = maxWidth; Tk_GetFontMetrics(tkfont, &fm); height = fm.linespace; } } args->needed.width = width; args->needed.height = height; } static void HeightProcText(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementText *elemX = (ElementText *) elem; ElementText *masterX = (ElementText *) elem->master; int inHeader = elem->stateDomain == STATE_DOMAIN_HEADER; int state = args->state; int height = 0; char *text = NULL; int textLen = 0; Tk_Font tkfont; Tk_FontMetrics fm; ElementTextLayout2 *etl2; etl2 = TextRedoLayoutIfNeeded("HeightProcText", args, args->height.fixedWidth); if (etl2 != NULL && etl2->layout != NULL) { TextLayout_Size(etl2->layout, NULL, &height); } else { if (elemX->text != NULL) { text = elemX->text; textLen = elemX->textLen; } else if ((masterX != NULL) && (masterX->text != NULL)) { text = masterX->text; textLen = masterX->textLen; } if (textLen > 0) { tkfont = DO_FontForState(tree, elem, DOID_TEXT_FONT, state); if (tkfont == NULL) tkfont = inHeader ? tree->tkfontHeader : tree->tkfont; Tk_GetFontMetrics(tkfont, &fm); height = fm.linespace; } } args->height.height = height; } int TreeElement_GetSortData( TreeCtrl *tree, TreeElement elem, int type, long *lv, double *dv, char **sv) { ElementText *elemX = (ElementText *) elem; ElementText *masterX = (ElementText *) elem->master; ElementTextData *etd, *etdM = NULL; Tcl_Obj *dataObj = NULL; int dataType = TDT_NULL; etd = DynamicOption_FindData(elem->options, DOID_TEXT_DATA); if (etd != NULL) { dataObj = etd->dataObj; dataType = etd->dataType; } if (dataType == TDT_NULL && masterX != NULL) { etdM = DynamicOption_FindData(elem->master->options, DOID_TEXT_DATA); /* FIXME: get dataObj from master? */ if (etdM != NULL) dataType = etdM->dataType; } switch (type) { case SORT_ASCII: case SORT_DICT: if (dataObj != NULL && dataType != TDT_NULL) (*sv) = Tcl_GetString(dataObj); else (*sv) = elemX->textCfg; break; case SORT_DOUBLE: if (dataObj != NULL && dataType == TDT_DOUBLE) { if (Tcl_GetDoubleFromObj(tree->interp, dataObj, dv) != TCL_OK) return TCL_ERROR; break; } if (elemX->textCfg != NULL) { if (Tcl_GetDouble(tree->interp, elemX->textCfg, dv) != TCL_OK) return TCL_ERROR; break; } FormatResult(tree->interp, "can't get a double from an empty -text value"); return TCL_ERROR; case SORT_LONG: if (dataObj != NULL && dataType != TDT_NULL) { if (dataType == TDT_LONG || dataType == TDT_TIME) { if (Tcl_GetLongFromObj(tree->interp, dataObj, lv) != TCL_OK) return TCL_ERROR; break; } if (dataType == TDT_INTEGER) { int iv; if (Tcl_GetIntFromObj(tree->interp, dataObj, &iv) != TCL_OK) return TCL_ERROR; (*lv) = iv; break; } } if (elemX->textCfg != NULL) { Tcl_Obj obj; obj.refCount = 1; obj.bytes = (char *) elemX->textCfg; obj.length = (int) strlen(elemX->textCfg); obj.typePtr = NULL; if (Tcl_GetLongFromObj(tree->interp, &obj, lv) != TCL_OK) return TCL_ERROR; break; } FormatResult(tree->interp, "can't get a long from an empty -text value"); return TCL_ERROR; } return TCL_OK; } static int StateProcText(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; /* ElementText *elemX = (ElementText *) elem; ElementText *masterX = (ElementText *) elem->master;*/ #ifdef DEPRECATED int draw1, draw2; #endif XColor *f1, *f2; Tk_Font tkfont1, tkfont2; if (!args->states.visible2) return 0; tkfont1 = DO_FontForState(tree, elem, DOID_TEXT_FONT, args->states.state1); tkfont2 = DO_FontForState(tree, elem, DOID_TEXT_FONT, args->states.state2); if (tkfont1 != tkfont2) return CS_DISPLAY | CS_LAYOUT; if (!args->states.draw2) return 0; #ifdef DEPRECATED draw1 = DO_BooleanForState(tree, elem, DOID_TEXT_DRAW, args->states.state1); draw2 = DO_BooleanForState(tree, elem, DOID_TEXT_DRAW, args->states.state2); if ((draw1 != 0) != (draw2 != 0)) return CS_DISPLAY; if (draw2 == 0) return 0; #endif DO_COLOR_FOR_STATE(f1, DOID_TEXT_FILL, args->states.state1); DO_COLOR_FOR_STATE(f2, DOID_TEXT_FILL, args->states.state2); if (f1 != f2) return CS_DISPLAY; return 0; } static int UndefProcText(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; /* ElementText *elemX = (ElementText *) elem;*/ int modified = 0; PerStateInfo *psi; if ((psi = DynamicOption_FindData(args->elem->options, DOID_TEXT_DRAW)) != NULL) modified |= PerStateInfo_Undefine(tree, &pstBoolean, psi, elem->stateDomain, args->state); if ((psi = DynamicOption_FindData(args->elem->options, DOID_TEXT_FILL)) != NULL) modified |= PerStateInfo_Undefine(tree, &pstColor, psi, elem->stateDomain, args->state); if ((psi = DynamicOption_FindData(args->elem->options, DOID_TEXT_FONT)) != NULL) modified |= PerStateInfo_Undefine(tree, &pstFont, psi, elem->stateDomain, args->state); return modified; } static int ActualProcText(TreeElementArgs *args) { TreeCtrl *tree = args->tree; /* ElementText *elemX = (ElementText *) args->elem; ElementText *masterX = (ElementText *) args->elem->master;*/ static CONST char *optionName[] = { #ifdef DEPRECATED "-draw", #endif "-fill", "-font", (char *) NULL }; int index; Tcl_Obj *obj = NULL; if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, "option", 0, &index) != TCL_OK) return TCL_ERROR; switch (index) { #ifdef DEPRECATED case 0: { obj = DO_ObjectForState(tree, &pstBoolean, args->elem, DOID_TEXT_DRAW, args->state); break; } case 1: { obj = DO_ObjectForState(tree, &pstColor, args->elem, DOID_TEXT_FILL, args->state); break; } case 2: { obj = DO_ObjectForState(tree, &pstFont, args->elem, DOID_TEXT_FONT, args->state); break; } #else case 0: { obj = DO_ObjectForState(tree, &pstColor, args->elem, DOID_TEXT_FILL, args->state); break; } case 1: { obj = DO_ObjectForState(tree, &pstFont, args->elem, DOID_TEXT_FONT, args->state); break; } #endif } if (obj != NULL) Tcl_SetObjResult(tree->interp, obj); return TCL_OK; } TreeElementType treeElemTypeText = { "text", sizeof(ElementText), textOptionSpecs, NULL, CreateProcText, DeleteProcText, ConfigProcText, DisplayProcText, NeededProcText, HeightProcText, WorldChangedProcText, StateProcText, UndefProcText, ActualProcText, NULL /* onScreenProc */ }; /*****/ typedef struct ElementWindow ElementWindow; struct ElementWindow { TreeElement_ header; #ifdef DEPRECATED PerStateInfo draw; /* -draw */ #endif TreeCtrl *tree; TreeItem item; /* Needed if window changes size */ TreeItemColumn column; /* Needed if window changes size */ Tk_Window tkwin; /* Window associated with item. NULL means * window has been destroyed. */ int destroy; /* Destroy window when element * is deleted */ #define CLIP_WINDOW 1 #ifdef CLIP_WINDOW int clip; /* TRUE if tkwin is a borderless frame * widget whose first child is the actual * window we want displayed. */ Tk_Window child; /* The first child of tkwin. tkwin is resized * so that it is never out-of-bounds, and * the child is positioned within tkwin to * provide clipping of the child. */ #endif }; #define EWIN_CONF_WINDOW 0x0001 #ifdef DEPRECATED #define EWIN_CONF_DRAW 0x0002 #endif static Tk_OptionSpec windowOptionSpecs[] = { #ifdef CLIP_WINDOW {TK_OPTION_CUSTOM, "-clip", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementWindow, clip), TK_OPTION_NULL_OK, (ClientData) &booleanCO, 0}, #endif {TK_OPTION_CUSTOM, "-destroy", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementWindow, destroy), TK_OPTION_NULL_OK, (ClientData) &booleanCO, 0}, #ifdef DEPRECATED {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementWindow, draw.obj), Tk_Offset(ElementWindow, draw), TK_OPTION_NULL_OK, (ClientData) NULL, EWIN_CONF_DRAW}, #endif {TK_OPTION_WINDOW, "-window", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementWindow, tkwin), TK_OPTION_NULL_OK, (ClientData) NULL, EWIN_CONF_WINDOW}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} }; static void WinItemStructureProc( ClientData clientData, /* Pointer to record describing window elem. */ XEvent *eventPtr) /* Describes what just happened. */ { ElementWindow *elemX = clientData; if (eventPtr->type == DestroyNotify) { elemX->tkwin = elemX->child = NULL; Tree_ElementChangedItself(elemX->tree, elemX->item, elemX->column, (TreeElement) elemX, EWIN_CONF_WINDOW, CS_LAYOUT | CS_DISPLAY); } } static void WinItemRequestProc( ClientData clientData, /* Pointer to record for window item. */ Tk_Window tkwin) /* Window that changed its desired * size. */ { ElementWindow *elemX = clientData; #ifdef CLIP_WINDOW /* We don't care about size changes for the clip window. */ if (elemX->child != NULL && tkwin != elemX->child) return; #endif Tree_ElementChangedItself(elemX->tree, elemX->item, elemX->column, (TreeElement) elemX, EWIN_CONF_WINDOW, CS_LAYOUT | CS_DISPLAY); } static void WinItemLostSlaveProc( ClientData clientData, /* WindowItem structure for slave window that * was stolen away. */ Tk_Window tkwin) /* Tk's handle for the slave window. */ { ElementWindow *elemX = clientData; TreeCtrl *tree = elemX->tree; #ifdef CLIP_WINDOW /* If either window is lost to another geometry manager, forget * about both windows. */ if (elemX->child != NULL) { Tk_DeleteEventHandler(elemX->child, StructureNotifyMask, WinItemStructureProc, (ClientData) elemX); if (tkwin != elemX->child) { Tk_ManageGeometry(elemX->child, (Tk_GeomMgr *) NULL, (ClientData) NULL); Tk_UnmapWindow(elemX->child); } elemX->child = NULL; } if (elemX->tkwin != NULL) { Tk_DeleteEventHandler(elemX->tkwin, StructureNotifyMask, WinItemStructureProc, (ClientData) elemX); if (tkwin != elemX->tkwin) { Tk_ManageGeometry(elemX->tkwin, (Tk_GeomMgr *) NULL, (ClientData) NULL); if (tree->tkwin != Tk_Parent(elemX->tkwin)) { Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); } Tk_UnmapWindow(elemX->tkwin); } elemX->tkwin = NULL; } #else Tk_DeleteEventHandler(elemX->tkwin, StructureNotifyMask, WinItemStructureProc, (ClientData) elemX); if (tree->tkwin != Tk_Parent(elemX->tkwin)) { Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); } Tk_UnmapWindow(elemX->tkwin); elemX->tkwin = NULL; #endif Tree_ElementChangedItself(elemX->tree, elemX->item, elemX->column, (TreeElement) elemX, EWIN_CONF_WINDOW, CS_LAYOUT | CS_DISPLAY); } static Tk_GeomMgr winElemGeomType = { "treectrl", /* name */ WinItemRequestProc, /* requestProc */ WinItemLostSlaveProc, /* lostSlaveProc */ }; static void DeleteProcWindow(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementWindow *elemX = (ElementWindow *) elem; ElementWindow *masterX = (ElementWindow *) elem->master; if (elemX->tkwin != NULL) { #ifdef CLIP_WINDOW if (elemX->child != NULL) { Tk_DeleteEventHandler(elemX->child, StructureNotifyMask, WinItemStructureProc, (ClientData) elemX); Tk_ManageGeometry(elemX->child, (Tk_GeomMgr *) NULL, (ClientData) NULL); Tk_UnmapWindow(elemX->child); elemX->child = NULL; } #endif Tk_DeleteEventHandler(elemX->tkwin, StructureNotifyMask, WinItemStructureProc, (ClientData) elemX); Tk_ManageGeometry(elemX->tkwin, (Tk_GeomMgr *) NULL, (ClientData) NULL); if (tree->tkwin != Tk_Parent(elemX->tkwin)) { Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); } Tk_UnmapWindow(elemX->tkwin); if ((elemX->destroy == 1) || ((masterX != NULL) && (masterX->destroy == 1))) { Tk_DestroyWindow(elemX->tkwin); } elemX->tkwin = NULL; } } static int WorldChangedProcWindow(TreeElementArgs *args) { int flagM = args->change.flagMaster; int flagS = args->change.flagSelf; int mask = 0; #ifdef DEPRECATED if ((flagS | flagM) & (EWIN_CONF_DRAW)) mask |= CS_DISPLAY; #endif if ((flagS | flagM) & (EWIN_CONF_WINDOW)) mask |= CS_DISPLAY | CS_LAYOUT; return mask; } static int ConfigProcWindow(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementWindow *elemX = (ElementWindow *) elem; ElementWindow *masterX = (ElementWindow *) elem->master; ElementWindow savedX; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; savedX.tkwin = elemX->tkwin; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, elem->stateDomain, elemX, elem->typePtr->optionTable, args->config.objc, args->config.objv, &savedOptions, &args->config.flagSelf) != TCL_OK) { args->config.flagSelf = 0; continue; } if (args->config.flagSelf & EWIN_CONF_WINDOW) { if ((elem->master == NULL) && (elemX->tkwin != NULL)){ FormatResult(tree->interp, "can't specify -window for a master element"); continue; } } Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } if (savedX.tkwin != elemX->tkwin) { if (savedX.tkwin != NULL) { #ifdef CLIP_WINDOW if (elemX->child != NULL) { Tk_DeleteEventHandler(elemX->child, StructureNotifyMask, WinItemStructureProc, (ClientData) elemX); Tk_ManageGeometry(elemX->child, (Tk_GeomMgr *) NULL, (ClientData) NULL); Tk_UnmapWindow(elemX->child); elemX->child = NULL; } #endif Tk_DeleteEventHandler(savedX.tkwin, StructureNotifyMask, WinItemStructureProc, (ClientData) elemX); Tk_ManageGeometry(savedX.tkwin, (Tk_GeomMgr *) NULL, (ClientData) NULL); Tk_UnmaintainGeometry(savedX.tkwin, tree->tkwin); Tk_UnmapWindow(savedX.tkwin); } if (elemX->tkwin != NULL) { Tk_Window ancestor, parent; /* * Make sure that the treectrl is either the parent of the * window associated with the element or a descendant of that * parent. Also, don't allow a top-of-hierarchy window to be * managed inside a treectrl. */ parent = Tk_Parent(elemX->tkwin); for (ancestor = tree->tkwin; ; ancestor = Tk_Parent(ancestor)) { if (ancestor == parent) { break; } if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_HIERARCHY) { badWindow: FormatResult(tree->interp, "can't use %s in a window element of %s", Tk_PathName(elemX->tkwin), Tk_PathName(tree->tkwin)); elemX->tkwin = NULL; return TCL_ERROR; } } if (((Tk_FakeWin *) (elemX->tkwin))->flags & TK_TOP_HIERARCHY) { goto badWindow; } if (elemX->tkwin == tree->tkwin) { goto badWindow; } #ifdef CLIP_WINDOW if ((elemX->clip == 1) || ((masterX != NULL) && (masterX->clip == 1))) { elemX->child = (Tk_Window) ((TkWindow *) elemX->tkwin)->childList; if (elemX->child != NULL) { Tk_CreateEventHandler(elemX->child, StructureNotifyMask, WinItemStructureProc, (ClientData) elemX); Tk_ManageGeometry(elemX->child, &winElemGeomType, (ClientData) elemX); } } #endif Tk_CreateEventHandler(elemX->tkwin, StructureNotifyMask, WinItemStructureProc, (ClientData) elemX); Tk_ManageGeometry(elemX->tkwin, &winElemGeomType, (ClientData) elemX); } } #if 0 if ((elemX->tkwin != NULL) && (itemPtr->state == TK_STATE_HIDDEN)) { if (tree->tkwin == Tk_Parent(elemX->tkwin)) { Tk_UnmapWindow(elemX->tkwin); } else { Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); } } #endif return TCL_OK; } static int CreateProcWindow(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementWindow *elemX = (ElementWindow *) elem; elemX->tree = tree; elemX->item = args->create.item; elemX->column = args->create.column; elemX->destroy = -1; #ifdef CLIP_WINDOW elemX->clip = -1; #endif return TCL_OK; } static void DisplayProcWindow(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementWindow *elemX = (ElementWindow *) elem; ElementWindow *masterX = (ElementWindow *) elem->master; int state = args->state; int x = args->display.x, y = args->display.y; int minX, maxX, minY, maxY; int width, height; int match, match2; #ifdef DEPRECATED int draw; #endif int requests; #ifdef DEPRECATED BOOLEAN_FOR_STATE(draw, draw, state); if (!draw) goto hideIt; #endif if (elemX->tkwin == NULL) return; #ifdef CLIP_WINDOW if (elemX->child != NULL) { width = Tk_ReqWidth(elemX->child); height = Tk_ReqHeight(elemX->child); } else { width = Tk_ReqWidth(elemX->tkwin); height = Tk_ReqHeight(elemX->tkwin); } if (width < 1 || height < 1) goto hideIt; #else width = Tk_ReqWidth(elemX->tkwin); height = Tk_ReqHeight(elemX->tkwin); #endif AdjustForSticky(args->display.sticky, args->display.width, args->display.height, TRUE, TRUE, &x, &y, &width, &height); x += tree->drawableXOrigin - tree->xOrigin; y += tree->drawableYOrigin - tree->yOrigin; /* -squeeze layout may give the element less space than requested. */ if (width > args->display.width) width = args->display.width; if (height > args->display.height) height = args->display.height; TreeRect_XYXY(args->display.bounds, &minX, &minY, &maxX, &maxY); /* * If the window is completely out of the visible area of the treectrl * then unmap it. The window could suddenly reappear if the treectrl * window gets resized. */ if (((x + width) <= minX) || ((y + height) <= minY) || (x >= maxX) || (y >= maxY)) { hideIt: if (tree->tkwin == Tk_Parent(elemX->tkwin)) { Tk_UnmapWindow(elemX->tkwin); } else { Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); } return; } TreeDisplay_GetReadyForTrouble(tree, &requests); #ifdef CLIP_WINDOW if (elemX->child != NULL) { int cx = x, cy = y, cw = width, ch = height; /* clip win coords */ if (cx < minX) { cw -= minX - cx; cx = minX; } if (cy < minY) { ch -= minY - cy; cy = minY; } if (cx + cw > maxX) cw = maxX - cx; if (cy + ch > maxY) ch = maxY - cy; /* * Reposition and map the window (but in different ways depending * on whether the treectrl is the window's parent). */ if (tree->tkwin == Tk_Parent(elemX->tkwin)) { if ((cx != Tk_X(elemX->tkwin)) || (cy != Tk_Y(elemX->tkwin)) || (cw != Tk_Width(elemX->tkwin)) || (ch != Tk_Height(elemX->tkwin))) { Tk_MoveResizeWindow(elemX->tkwin, cx, cy, cw, ch); if (TreeDisplay_WasThereTrouble(tree, requests)) return; } Tk_MapWindow(elemX->tkwin); } else { Tk_MaintainGeometry(elemX->tkwin, tree->tkwin, cx, cy, cw, ch); } if (TreeDisplay_WasThereTrouble(tree, requests)) return; /* * Position the child window within the clip window. */ x -= cx; y -= cy; if ((x != Tk_X(elemX->child)) || (y != Tk_Y(elemX->child)) || (width != Tk_Width(elemX->child)) || (height != Tk_Height(elemX->child))) { Tk_MoveResizeWindow(elemX->child, x, y, width, height); if (TreeDisplay_WasThereTrouble(tree, requests)) return; } Tk_MapWindow(elemX->child); return; } #endif /* CLIP_WINDOW */ /* * Reposition and map the window (but in different ways depending * on whether the treectrl is the window's parent). */ if (tree->tkwin == Tk_Parent(elemX->tkwin)) { if ((x != Tk_X(elemX->tkwin)) || (y != Tk_Y(elemX->tkwin)) || (width != Tk_Width(elemX->tkwin)) || (height != Tk_Height(elemX->tkwin))) { Tk_MoveResizeWindow(elemX->tkwin, x, y, width, height); if (TreeDisplay_WasThereTrouble(tree, requests)) return; } Tk_MapWindow(elemX->tkwin); } else { Tk_MaintainGeometry(elemX->tkwin, tree->tkwin, x, y, width, height); } } static void NeededProcWindow(TreeElementArgs *args) { /* TreeCtrl *tree = args->tree;*/ TreeElement elem = args->elem; ElementWindow *elemX = (ElementWindow *) elem; /* ElementWindow *masterX = (ElementWindow *) elem->master; int state = args->state;*/ int width = 0, height = 0; #ifdef CLIP_WINDOW if (elemX->child != NULL) { width = Tk_ReqWidth(elemX->child); if (width <= 0) { width = 1; } height = Tk_ReqHeight(elemX->child); if (height <= 0) { height = 1; } } else #endif if (elemX->tkwin) { width = Tk_ReqWidth(elemX->tkwin); if (width <= 0) { width = 1; } height = Tk_ReqHeight(elemX->tkwin); if (height <= 0) { height = 1; } } args->needed.width = width; args->needed.height = height; } static int StateProcWindow(TreeElementArgs *args) { #ifdef DEPRECATED TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementBitmap *elemX = (ElementBitmap *) elem; ElementBitmap *masterX = (ElementBitmap *) elem->master; int match, match2; int draw1, draw2; if (!args->states.visible2 || !args->states.draw2) return 0; BOOLEAN_FOR_STATE(draw1, draw, args->states.state1) BOOLEAN_FOR_STATE(draw2, draw, args->states.state2) if ((draw1 != 0) != (draw2 != 0)) return CS_DISPLAY; #endif return 0; } static int UndefProcWindow(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementWindow *elemX = (ElementWindow *) elem; int modified = 0; #ifdef DEPRECATED modified |= PerStateInfo_Undefine(tree, &pstBoolean, &elemX->draw, elem->stateDomain, args->state); #endif return modified; } static int ActualProcWindow(TreeElementArgs *args) { #ifdef DEPRECATED TreeCtrl *tree = args->tree; ElementWindow *elemX = (ElementWindow *) args->elem; ElementWindow *masterX = (ElementWindow *) args->elem->master; static CONST char *optionName[] = { "-draw", (char *) NULL }; int index, match, matchM; Tcl_Obj *obj = NULL; if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, "option", 0, &index) != TCL_OK) return TCL_ERROR; switch (index) { case 0: { OBJECT_FOR_STATE(obj, pstBoolean, draw, args->state) break; } } if (obj != NULL) Tcl_SetObjResult(tree->interp, obj); #endif return TCL_OK; } static void OnScreenProcWindow(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementWindow *elemX = (ElementWindow *) elem; if (!args->screen.visible && (elemX->tkwin != NULL)) { if (tree->tkwin == Tk_Parent(elemX->tkwin)) { Tk_UnmapWindow(elemX->tkwin); } else { Tk_UnmaintainGeometry(elemX->tkwin, tree->tkwin); } } } TreeElementType treeElemTypeWindow = { "window", sizeof(ElementWindow), windowOptionSpecs, NULL, CreateProcWindow, DeleteProcWindow, ConfigProcWindow, DisplayProcWindow, NeededProcWindow, NULL, /* heightProc */ WorldChangedProcWindow, StateProcWindow, UndefProcWindow, ActualProcWindow, OnScreenProcWindow }; /*****/ /* This structure holds the list of element types for an interpreter. * Each element type has a Tk_OptionTable that is per-interp. */ typedef struct ElementAssocData ElementAssocData; struct ElementAssocData { TreeElementType *typeList; }; int TreeElement_TypeFromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeElementType **typePtrPtr) { Tcl_Interp *interp = tree->interp; ElementAssocData *assocData; char *typeStr; int length; TreeElementType *typeList; TreeElementType *typePtr, *matchPtr = NULL; assocData = Tcl_GetAssocData(interp, "TreeCtrlElementTypes", NULL); typeList = assocData->typeList; typeStr = Tcl_GetStringFromObj(objPtr, &length); if (!length) { FormatResult(interp, "invalid element type \"\""); return TCL_ERROR; } for (typePtr = typeList; typePtr != NULL; typePtr = typePtr->next) { if ((typeStr[0] == typePtr->name[0]) && !strncmp(typeStr, typePtr->name, length)) { if (matchPtr != NULL) { FormatResult(interp, "ambiguous element type \"%s\"", typeStr); return TCL_ERROR; } matchPtr = typePtr; } } if (matchPtr == NULL) { FormatResult(interp, "unknown element type \"%s\"", typeStr); return TCL_ERROR; } *typePtrPtr = matchPtr; return TCL_OK; } int TreeCtrl_RegisterElementType(Tcl_Interp *interp, TreeElementType *newTypePtr) { ElementAssocData *assocData; TreeElementType *typeList; TreeElementType *prevPtr, *typePtr, *nextPtr; assocData = Tcl_GetAssocData(interp, "TreeCtrlElementTypes", NULL); typeList = assocData->typeList; for (typePtr = typeList, prevPtr = NULL; typePtr != NULL; prevPtr = typePtr, typePtr = nextPtr) { nextPtr = typePtr->next; /* Remove duplicate type */ if (!strcmp(typePtr->name, newTypePtr->name)) { if (prevPtr == NULL) typeList = typePtr->next; else prevPtr->next = typePtr->next; ckfree((char *) typePtr); } } typePtr = (TreeElementType *) ckalloc(sizeof(TreeElementType)); memcpy(typePtr, newTypePtr, sizeof(TreeElementType)); typePtr->next = typeList; typeList = typePtr; typePtr->optionTable = Tk_CreateOptionTable(interp, newTypePtr->optionSpecs); assocData->typeList = typeList; return TCL_OK; } static TreeCtrlStubs stubs = { #ifdef TREECTRL_DEBUG sizeof(TreeCtrl), sizeof(TreeCtrlStubs), sizeof(TreeElement), sizeof(TreeElementArgs), #endif TreeCtrl_RegisterElementType, Tree_RedrawElement, Tree_ElementIterateBegin, Tree_ElementIterateNext, Tree_ElementIterateGet, Tree_ElementIterateChanged, PerStateInfo_Free, PerStateInfo_FromObj, PerStateInfo_ForState, PerStateInfo_ObjForState, PerStateInfo_Undefine, &pstBoolean, PerStateBoolean_ForState, PSTSave, PSTRestore, TreeStateFromObj, BooleanCO_Init, StringTableCO_Init, PerStateCO_Init }; /* *---------------------------------------------------------------------- * * TreeElement_InitWidget -- * * Element-related initialization when a treectrl is created. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeElement_InitWidget( TreeCtrl *tree ) { /* These options are used by the text element. Originally these were * static globals but that isn't thread safe. */ tree->formatFloatObj = Tcl_NewStringObj("%g", -1); tree->formatIntObj = Tcl_NewStringObj("%d", -1); tree->formatLongObj = Tcl_NewStringObj("%ld", -1); tree->formatStringObj = Tcl_NewStringObj("%s", -1); Tcl_IncrRefCount(tree->formatFloatObj); Tcl_IncrRefCount(tree->formatIntObj); Tcl_IncrRefCount(tree->formatLongObj); Tcl_IncrRefCount(tree->formatStringObj); tree->stringClockObj = Tcl_NewStringObj("clock", -1); tree->stringFormatObj = Tcl_NewStringObj("format", -1); tree->optionFormatObj = Tcl_NewStringObj("-format", -1); Tcl_IncrRefCount(tree->stringClockObj); Tcl_IncrRefCount(tree->stringFormatObj); Tcl_IncrRefCount(tree->optionFormatObj); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeElement_FreeWidget -- * * Free element-related resources for a deleted TreeCtrl. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeElement_FreeWidget( TreeCtrl *tree ) { Tcl_DecrRefCount(tree->formatFloatObj); Tcl_DecrRefCount(tree->formatIntObj); Tcl_DecrRefCount(tree->formatLongObj); Tcl_DecrRefCount(tree->formatStringObj); Tcl_DecrRefCount(tree->stringClockObj); Tcl_DecrRefCount(tree->stringFormatObj); Tcl_DecrRefCount(tree->optionFormatObj); } static void FreeAssocData(ClientData clientData, Tcl_Interp *interp) { ElementAssocData *assocData = clientData; TreeElementType *typeList = assocData->typeList; TreeElementType *next; while (typeList != NULL) { next = typeList->next; /* The ElementType.optionTables are freed when the interp is deleted */ ckfree((char *) typeList); typeList = next; } ckfree((char *) assocData); } /* *---------------------------------------------------------------------- * * TreeElement_InitInterp -- * * Element-related initialization when the package is loaded. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeElement_InitInterp( Tcl_Interp *interp ) { ElementAssocData *assocData; /* FIXME: memory leak with dynamically-allocated ClientData. */ /* * bitmap */ PerStateCO_Init(treeElemTypeBitmap.optionSpecs, "-background", &pstColor, TreeStateFromObj); PerStateCO_Init(treeElemTypeBitmap.optionSpecs, "-bitmap", &pstBitmap, TreeStateFromObj); #ifdef DEPRECATED PerStateCO_Init(treeElemTypeBitmap.optionSpecs, "-draw", &pstBoolean, TreeStateFromObj); #endif PerStateCO_Init(treeElemTypeBitmap.optionSpecs, "-foreground", &pstColor, TreeStateFromObj); /* * border */ #ifdef DEPRECATED PerStateCO_Init(treeElemTypeBorder.optionSpecs, "-draw", &pstBoolean, TreeStateFromObj); #endif PerStateCO_Init(treeElemTypeBorder.optionSpecs, "-background", &pstBorder, TreeStateFromObj); PerStateCO_Init(treeElemTypeBorder.optionSpecs, "-relief", &pstRelief, TreeStateFromObj); /* * header */ StringTableCO_Init(treeElemTypeHeader.optionSpecs, "-arrow", headerArrowST); PerStateCO_Init(treeElemTypeHeader.optionSpecs, "-arrowbitmap", &pstBitmap, TreeStateFromObj); StringTableCO_Init(treeElemTypeHeader.optionSpecs, "-arrowgravity", headerArrowSideST); PerStateCO_Init(treeElemTypeHeader.optionSpecs, "-arrowimage", &pstImage, TreeStateFromObj); StringTableCO_Init(treeElemTypeHeader.optionSpecs, "-arrowside", headerArrowSideST); PerStateCO_Init(treeElemTypeHeader.optionSpecs, "-background", &pstBorder, TreeStateFromObj); StringTableCO_Init(treeElemTypeHeader.optionSpecs, "-state", headerStateST); /* * image */ #ifdef DEPRECATED DynamicCO_Init(treeElemTypeImage.optionSpecs, "-draw", 1002, sizeof(PerStateInfo), Tk_Offset(PerStateInfo, obj), 0, PerStateCO_Alloc("-draw", &pstBoolean, TreeStateFromObj), (DynamicOptionInitProc *) NULL); #endif PerStateCO_Init(treeElemTypeImage.optionSpecs, "-image", &pstImage, TreeStateFromObj); /* 2 options in the same structure. */ DynamicCO_Init(treeElemTypeImage.optionSpecs, "-height", 1001, sizeof(ElementImageSize), Tk_Offset(ElementImageSize, heightObj), Tk_Offset(ElementImageSize, height), &TreeCtrlCO_pixels, (DynamicOptionInitProc *) NULL); DynamicCO_Init(treeElemTypeImage.optionSpecs, "-width", 1001, sizeof(ElementImageSize), Tk_Offset(ElementImageSize, widthObj), Tk_Offset(ElementImageSize, width), &TreeCtrlCO_pixels, (DynamicOptionInitProc *) NULL); DynamicCO_Init(treeElemTypeImage.optionSpecs, "-tiled", 1003, sizeof(int), -1, 0, &booleanCO, DynamicOptionInitBoolean); /* * rect */ #ifdef DEPRECATED PerStateCO_Init(treeElemTypeRect.optionSpecs, "-draw", &pstBoolean, TreeStateFromObj); #endif PerStateCO_Init(treeElemTypeRect.optionSpecs, "-fill", &pstColor, TreeStateFromObj); PerStateCO_Init(treeElemTypeRect.optionSpecs, "-open", &pstFlags, TreeStateFromObj); PerStateCO_Init(treeElemTypeRect.optionSpecs, "-outline", &pstColor, TreeStateFromObj); /* * text */ /* 3 options in the same structure. */ DynamicCO_Init(treeElemTypeText.optionSpecs, "-data", DOID_TEXT_DATA, sizeof(ElementTextData), Tk_Offset(ElementTextData, dataObj), -1, &TreeCtrlCO_string, ElementTextDataInit); DynamicCO_Init(treeElemTypeText.optionSpecs, "-datatype", DOID_TEXT_DATA, sizeof(ElementTextData), -1, Tk_Offset(ElementTextData, dataType), StringTableCO_Alloc("-datatype", textDataTypeST), ElementTextDataInit); DynamicCO_Init(treeElemTypeText.optionSpecs, "-format", DOID_TEXT_DATA, sizeof(ElementTextData), Tk_Offset(ElementTextData, formatObj), -1, &TreeCtrlCO_string, ElementTextDataInit); /* 4 options in the same structure. */ DynamicCO_Init(treeElemTypeText.optionSpecs, "-justify", DOID_TEXT_LAYOUT, sizeof(ElementTextLayout), -1, Tk_Offset(ElementTextLayout, justify), StringTableCO_Alloc("-justify", textJustifyST), ElementTextLayoutInit); DynamicCO_Init(treeElemTypeText.optionSpecs, "-lines", DOID_TEXT_LAYOUT, sizeof(ElementTextLayout), -1, Tk_Offset(ElementTextLayout, lines), IntegerCO_Alloc("-lines", 0, /* min */ 0, /* max (ignored) */ -1, /* empty */ 0x01), /* flags: min */ ElementTextLayoutInit); DynamicCO_Init(treeElemTypeText.optionSpecs, "-width", DOID_TEXT_LAYOUT, sizeof(ElementTextLayout), Tk_Offset(ElementTextLayout, widthObj), Tk_Offset(ElementTextLayout, width), &TreeCtrlCO_pixels, ElementTextLayoutInit); DynamicCO_Init(treeElemTypeText.optionSpecs, "-wrap", DOID_TEXT_LAYOUT, sizeof(ElementTextLayout), -1, Tk_Offset(ElementTextLayout, wrap), StringTableCO_Alloc("-wrap", textWrapST), ElementTextLayoutInit); #ifdef DEPRECATED DynamicCO_Init(treeElemTypeText.optionSpecs, "-draw", DOID_TEXT_DRAW, sizeof(PerStateInfo), Tk_Offset(PerStateInfo, obj), 0, PerStateCO_Alloc("-draw", &pstBoolean, TreeStateFromObj), (DynamicOptionInitProc *) NULL); #endif DynamicCO_Init(treeElemTypeText.optionSpecs, "-fill", DOID_TEXT_FILL, sizeof(PerStateInfo), Tk_Offset(PerStateInfo, obj), 0, PerStateCO_Alloc("-fill", &pstColor, TreeStateFromObj), (DynamicOptionInitProc *) NULL); DynamicCO_Init(treeElemTypeText.optionSpecs, "-font", DOID_TEXT_FONT, sizeof(PerStateInfo), Tk_Offset(PerStateInfo, obj), 0, PerStateCO_Alloc("-font", &pstFont, TreeStateFromObj), (DynamicOptionInitProc *) NULL); #ifdef TEXTVAR DynamicCO_Init(treeElemTypeText.optionSpecs, "-textvariable", DOID_TEXT_VAR, sizeof(ElementTextVar), Tk_Offset(struct ElementTextVar, varNameObj), -1, &TreeCtrlCO_string, (DynamicOptionInitProc *) NULL); #endif #ifdef TEXT_STYLE DynamicCO_Init(treeElemTypeText.optionSpecs, "-underline", DOID_TEXT_STYLE, sizeof(ElementTextStyle), -1, Tk_Offset(ElementTextStyle, underline), IntegerCO_Alloc("-underline", 0, /* min (ignored) */ 0, /* max (ignored) */ TEXT_UNDERLINE_EMPTYVAL, /* empty */ 0x00), /* flags */ ElementTextStyleInit); #endif /* 2 options in the same structure */ DynamicCO_Init(treeElemTypeText.optionSpecs, "-lmargin1", DOID_TEXT_LAYOUT3, sizeof(ElementTextLayout3), Tk_Offset(ElementTextLayout3, lMargin1Obj), Tk_Offset(ElementTextLayout3, lMargin1), &TreeCtrlCO_pixels, (DynamicOptionInitProc *) NULL); DynamicCO_Init(treeElemTypeText.optionSpecs, "-lmargin2", DOID_TEXT_LAYOUT3, sizeof(ElementTextLayout3), Tk_Offset(ElementTextLayout3, lMargin2Obj), Tk_Offset(ElementTextLayout3, lMargin2), &TreeCtrlCO_pixels, (DynamicOptionInitProc *) NULL); /* * window */ #ifdef DEPRECATED PerStateCO_Init(treeElemTypeWindow.optionSpecs, "-draw", &pstBoolean, TreeStateFromObj); #endif assocData = (ElementAssocData *) ckalloc(sizeof(ElementAssocData)); assocData->typeList = NULL; Tcl_SetAssocData(interp, "TreeCtrlElementTypes", FreeAssocData, assocData); TreeCtrl_RegisterElementType(interp, &treeElemTypeBitmap); TreeCtrl_RegisterElementType(interp, &treeElemTypeBorder); /* TreeCtrl_RegisterElementType(interp, &treeElemTypeCheckButton);*/ TreeCtrl_RegisterElementType(interp, &treeElemTypeHeader); TreeCtrl_RegisterElementType(interp, &treeElemTypeImage); TreeCtrl_RegisterElementType(interp, &treeElemTypeRect); TreeCtrl_RegisterElementType(interp, &treeElemTypeText); TreeCtrl_RegisterElementType(interp, &treeElemTypeWindow); Tcl_SetAssocData(interp, "TreeCtrlStubs", NULL, &stubs); return TCL_OK; } tktreectrl-2.4.1/generic/tkTreeElem.h0000644000076400010400000001461011562306407020047 0ustar TimAdministrators/* * tkTreeElem.h -- * * This module is the header for elements in treectrl widgets. * * Copyright (c) 2002-2011 Tim Baker */ typedef struct TreeElementType TreeElementType; typedef struct TreeElement_ TreeElement_; typedef struct TreeElementArgs TreeElementArgs; struct TreeElementArgs { TreeCtrl *tree; TreeElement elem; int state; struct { TreeItem item; TreeItemColumn column; } create; struct { int noop; } delete; struct { int objc; Tcl_Obj *CONST *objv; int flagSelf; TreeItem item; TreeItemColumn column; } config; struct { int x; /* Display area of the element. */ int y; /* ^ */ int width; /* ^ */ int height; /* ^ */ #define STICKY_W 0x1000 /* These values must match ELF_STICKY_xxx */ #define STICKY_N 0x2000 #define STICKY_E 0x4000 #define STICKY_S 0x8000 int sticky; /* How to stretch/position the element within * its display area. */ int indent; /* Distance the style is indented from the * left of spanBbox. */ int spanIndex; /* 0-based index in the list of visible spans. */ TreeDrawable td; /* Where to draw. */ Drawable drawable; /* Where to draw. */ TreeRectangle bounds; /* TREE_AREA_XXX bounds. */ TreeRectangle spanBbox; /* Bounds of the span. */ int eUnionBbox[4]; /* Bounds of elements in a this element's */ int iUnionBbox[4]; /* -union. */ TreeColumn column; /* needed for gradients */ TreeItem item; /* needed for gradients */ } display; struct { int fixedWidth; int fixedHeight; int maxWidth; int maxHeight; int width; int height; } needed; struct { int fixedWidth; int height; } height; struct { int flagTree; int flagMaster; int flagSelf; } change; struct { int state1; int state2; int draw1; int draw2; int visible1; int visible2; } states; struct { Tcl_Obj *obj; } actual; struct { int visible; } screen; }; struct TreeElementType { char *name; /* "image", "text" */ int size; /* size of an TreeElement */ Tk_OptionSpec *optionSpecs; Tk_OptionTable optionTable; int (*createProc)(TreeElementArgs *args); void (*deleteProc)(TreeElementArgs *args); int (*configProc)(TreeElementArgs *args); void (*displayProc)(TreeElementArgs *args); void (*neededProc)(TreeElementArgs *args); void (*heightProc)(TreeElementArgs *args); int (*changeProc)(TreeElementArgs *args); int (*stateProc)(TreeElementArgs *args); int (*undefProc)(TreeElementArgs *args); int (*actualProc)(TreeElementArgs *args); void (*onScreenProc)(TreeElementArgs *args); TreeElementType *next; }; /* list of these for each style */ struct TreeElement_ { Tk_Uid name; /* "elem2", "eText" etc */ TreeElementType *typePtr; TreeElement master; /* NULL if this is master */ int stateDomain; /* STATE_DOMAIN_XXX index. */ int hidden; /* Hackish flag for hidden header styles. */ DynamicOption *options; /* Dynamically-allocated options. */ /* type-specific data here */ }; MODULE_SCOPE TreeElementType treeElemTypeBitmap; MODULE_SCOPE TreeElementType treeElemTypeBorder; MODULE_SCOPE TreeElementType treeElemTypeCheckButton; MODULE_SCOPE TreeElementType treeElemTypeHeader; MODULE_SCOPE TreeElementType treeElemTypeImage; MODULE_SCOPE TreeElementType treeElemTypeRect; MODULE_SCOPE TreeElementType treeElemTypeText; MODULE_SCOPE TreeElementType treeElemTypeWindow; #define ELEMENT_TYPE_MATCHES(t1,t2) ((t1)->name == (t2)->name) /***** ***** *****/ MODULE_SCOPE int TreeElement_GetSortData(TreeCtrl *tree, TreeElement elem, int type, long *lv, double *dv, char **sv); typedef struct TreeIterate_ *TreeIterate; MODULE_SCOPE int TreeElement_TypeFromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeElementType **typePtrPtr); MODULE_SCOPE void Tree_RedrawElement(TreeCtrl *tree, TreeItem item, TreeElement elem); MODULE_SCOPE TreeIterate Tree_ElementIterateBegin(TreeCtrl *tree, TreeElementType *elemTypePtr); MODULE_SCOPE TreeIterate Tree_ElementIterateNext(TreeIterate iter_); MODULE_SCOPE TreeElement Tree_ElementIterateGet(TreeIterate iter_); MODULE_SCOPE void Tree_ElementIterateChanged(TreeIterate iter_, int mask); MODULE_SCOPE void Tree_ElementChangedItself(TreeCtrl *tree, TreeItem item, TreeItemColumn column, TreeElement elem, int flags, int mask); MODULE_SCOPE int TreeCtrl_RegisterElementType(Tcl_Interp *interp, TreeElementType *newTypePtr); MODULE_SCOPE void TreeElement_GetContentMargins(TreeCtrl *tree, TreeElement elem, int state, int eMargins[4], int uMargins[4], int *arrowHeight); typedef struct TreeCtrlStubs TreeCtrlStubs; struct TreeCtrlStubs { #ifdef TREECTRL_DEBUG int sizeofTreeCtrl; int sizeofTreeCtrlStubs; int sizeofTreeElement; int sizeofTreeElementArgs; #endif int (*TreeCtrl_RegisterElementType)(Tcl_Interp *interp, TreeElementType *typePtr); void (*Tree_RedrawElement)(TreeCtrl *tree, TreeItem item, TreeElement elem); TreeIterate (*Tree_ElementIterateBegin)(TreeCtrl *tree, TreeElementType *elemTypePtr); TreeIterate (*Tree_ElementIterateNext)(TreeIterate iter_); TreeElement (*Tree_ElementIterateGet)(TreeIterate iter_); void (*Tree_ElementIterateChanged)(TreeIterate iter_, int mask); void (*PerStateInfo_Free)(TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo); int (*PerStateInfo_FromObj)(TreeCtrl *tree, int domain, StateFromObjProc proc, PerStateType *typePtr, PerStateInfo *pInfo); PerStateData *(*PerStateInfo_ForState)(TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo, int state, int *match); Tcl_Obj *(*PerStateInfo_ObjForState)(TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo, int state, int *match); int (*PerStateInfo_Undefine)(TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo, int domain, int state); PerStateType *pstBoolean; int (*PerStateBoolean_ForState)(TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match); void (*PSTSave)(PerStateInfo *pInfo, PerStateInfo *pSave); void (*PSTRestore)(TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo, PerStateInfo *pSave); int (*TreeStateFromObj)(TreeCtrl *tree, int domain, Tcl_Obj *obj, int *stateOff, int *stateOn); int (*BooleanCO_Init)(Tk_OptionSpec *optionTable, CONST char *optionName); int (*StringTableCO_Init)(Tk_OptionSpec *optionTable, CONST char *optionName, CONST char **tablePtr); int (*PerStateCO_Init)(Tk_OptionSpec *optionTable, CONST char *optionName, PerStateType *typePtr, StateFromObjProc proc); }; tktreectrl-2.4.1/generic/tkTreeHeader.c0000644000076400010400000026572111571766173020375 0ustar TimAdministrators/* * tkTreeHeader.c -- * * This module implements treectrl widget's column headers. * * Copyright (c) 2011 Tim Baker */ #include "tkTreeCtrl.h" typedef struct TreeHeader_ TreeHeader_; typedef struct TreeHeaderColumn_ HeaderColumn; #define IS_TAIL(C) (C == tree->columnTail) /* * The following structure holds information about a single column header * of a TreeHeader. */ struct TreeHeaderColumn_ { TreeItemColumn itemColumn; Tcl_Obj *textObj; /* -text */ char *text; /* -text */ Tk_Font tkfont; /* -font */ Tk_Justify justify; /* -justify */ PerStateInfo border; /* -background */ Tcl_Obj *borderWidthObj; /* -borderwidth */ int borderWidth; /* -borderwidth */ PerStateInfo textColor; /* -textcolor */ char *imageString; /* -image */ PerStateInfo arrowBitmap; /* -arrowbitmap */ PerStateInfo arrowImage; /* -arrowimage */ Pixmap bitmap; /* -bitmap */ int button; /* -button */ Tcl_Obj *textPadXObj; /* -textpadx */ int *textPadX; /* -textpadx */ Tcl_Obj *textPadYObj; /* -textpady */ int *textPadY; /* -textpady */ Tcl_Obj *imagePadXObj; /* -imagepadx */ int *imagePadX; /* -imagepadx */ Tcl_Obj *imagePadYObj; /* -imagepady */ int *imagePadY; /* -imagepady */ Tcl_Obj *arrowPadXObj; /* -arrowpadx */ int *arrowPadX; /* -arrowpadx */ Tcl_Obj *arrowPadYObj; /* -arrowpady */ int *arrowPadY; /* -arrowpady */ int arrow; /* -arrow */ #define SIDE_LEFT 0 #define SIDE_RIGHT 1 int arrowSide; /* -arrowside */ int arrowGravity; /* -arrowgravity */ int state; /* -state */ int textLen; Tk_Image image; #define TEXT_WRAP_NULL -1 #define TEXT_WRAP_CHAR 0 #define TEXT_WRAP_WORD 1 int textWrap; /* -textwrap */ int textLines; /* -textlines */ Tk_Image dragImage; /* Used during drag-and-drop. */ int imageEpoch; /* If this value doesn't match * tree->columnDrag.imageEpoch the drag image * for this column is recreated. */ Tk_Uid dragImageName; /* Name needed to delete the drag image. */ }; /* * The following structure holds [dragconfigure] option info for a TreeHeader. */ struct TreeHeaderDrag { int enable; /* -enable */ int draw; /* -draw */ }; /* * The following structure holds information about a single TreeHeader. */ struct TreeHeader_ { TreeCtrl *tree; TreeItem item; struct TreeHeaderDrag columnDrag; }; static CONST char *arrowST[] = { "none", "up", "down", (char *) NULL }; static CONST char *arrowSideST[] = { "left", "right", (char *) NULL }; static CONST char *stateST[] = { "normal", "active", "pressed", (char *) NULL }; #define COLU_CONF_IMAGE 0x0001 #define COLU_CONF_NWIDTH 0x0002 /* neededWidth */ #define COLU_CONF_NHEIGHT 0x0004 /* neededHeight */ #define COLU_CONF_STATE 0x0008 /* -arrow and -state */ #define COLU_CONF_DISPLAY 0x0040 #define COLU_CONF_JUSTIFY 0x0080 #define COLU_CONF_TEXT 0x0200 #define COLU_CONF_BITMAP 0x0400 #define COLU_CONF_TAIL 0x0800 /* options affecting tail's HeaderStyle */ #define ELEM_HEADER 0x00010000 #define ELEM_BITMAP 0x00020000 #define ELEM_IMAGE 0x00040000 #define ELEM_TEXT 0x00080000 static Tk_OptionSpec columnSpecs[] = { {TK_OPTION_STRING_TABLE, "-arrow", (char *) NULL, (char *) NULL, "none", -1, Tk_Offset(HeaderColumn, arrow), 0, (ClientData) arrowST, COLU_CONF_STATE | ELEM_HEADER}, {TK_OPTION_CUSTOM, "-arrowbitmap", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(HeaderColumn, arrowBitmap.obj), Tk_Offset(HeaderColumn, arrowBitmap), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY | ELEM_HEADER}, {TK_OPTION_STRING_TABLE, "-arrowgravity", (char *) NULL, (char *) NULL, "left", -1, Tk_Offset(HeaderColumn, arrowGravity), 0, (ClientData) arrowSideST, COLU_CONF_DISPLAY | ELEM_HEADER}, {TK_OPTION_CUSTOM, "-arrowimage", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(HeaderColumn, arrowImage.obj), Tk_Offset(HeaderColumn, arrowImage), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY | ELEM_HEADER}, {TK_OPTION_CUSTOM, "-arrowpadx", (char *) NULL, (char *) NULL, "6", Tk_Offset(HeaderColumn, arrowPadXObj), Tk_Offset(HeaderColumn, arrowPadX), 0, (ClientData) &TreeCtrlCO_pad, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY | ELEM_HEADER}, {TK_OPTION_CUSTOM, "-arrowpady", (char *) NULL, (char *) NULL, "0", Tk_Offset(HeaderColumn, arrowPadYObj), Tk_Offset(HeaderColumn, arrowPadY), 0, (ClientData) &TreeCtrlCO_pad, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY | ELEM_HEADER}, {TK_OPTION_STRING_TABLE, "-arrowside", (char *) NULL, (char *) NULL, "right", -1, Tk_Offset(HeaderColumn, arrowSide), 0, (ClientData) arrowSideST, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY | ELEM_HEADER}, {TK_OPTION_CUSTOM, "-background", (char *) NULL, (char *) NULL, (char *) NULL, /* DEFAULT VALUE IS INITIALIZED LATER */ Tk_Offset(HeaderColumn, border.obj), Tk_Offset(HeaderColumn, border), 0, (ClientData) NULL, COLU_CONF_DISPLAY | COLU_CONF_TAIL | ELEM_HEADER}, {TK_OPTION_BITMAP, "-bitmap", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(HeaderColumn, bitmap), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_BITMAP | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY | ELEM_BITMAP}, {TK_OPTION_PIXELS, "-borderwidth", (char *) NULL, (char *) NULL, "2", Tk_Offset(HeaderColumn, borderWidthObj), Tk_Offset(HeaderColumn, borderWidth), 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY | COLU_CONF_TAIL | ELEM_HEADER}, {TK_OPTION_BOOLEAN, "-button", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(HeaderColumn, button), 0, (ClientData) NULL, 0}, {TK_OPTION_FONT, "-font", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(HeaderColumn, tkfont), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY | COLU_CONF_TEXT | ELEM_TEXT}, {TK_OPTION_STRING, "-image", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(HeaderColumn, imageString), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_IMAGE | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY | ELEM_IMAGE}, {TK_OPTION_CUSTOM, "-imagepadx", (char *) NULL, (char *) NULL, "6", Tk_Offset(HeaderColumn, imagePadXObj), Tk_Offset(HeaderColumn, imagePadX), 0, (ClientData) &TreeCtrlCO_pad, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY}, {TK_OPTION_CUSTOM, "-imagepady", (char *) NULL, (char *) NULL, "0", Tk_Offset(HeaderColumn, imagePadYObj), Tk_Offset(HeaderColumn, imagePadY), 0, (ClientData) &TreeCtrlCO_pad, COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY}, {TK_OPTION_JUSTIFY, "-justify", (char *) NULL, (char *) NULL, "left", -1, Tk_Offset(HeaderColumn, justify), 0, (ClientData) NULL, COLU_CONF_DISPLAY | COLU_CONF_JUSTIFY}, {TK_OPTION_STRING_TABLE, "-state", (char *) NULL, (char *) NULL, "normal", -1, Tk_Offset(HeaderColumn, state), 0, (ClientData) stateST, COLU_CONF_STATE | ELEM_HEADER}, {TK_OPTION_STRING, "-text", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(HeaderColumn, textObj), Tk_Offset(HeaderColumn, text), TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TEXT | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY | ELEM_TEXT}, {TK_OPTION_CUSTOM, "-textcolor", (char *) NULL, (char *) NULL, (char *) NULL, /* DEFAULT VALUE IS INITIALIZED LATER */ Tk_Offset(HeaderColumn, textColor.obj), Tk_Offset(HeaderColumn, textColor), 0, (ClientData) NULL, COLU_CONF_DISPLAY | ELEM_TEXT}, {TK_OPTION_INT, "-textlines", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(HeaderColumn, textLines), 0, (ClientData) NULL, COLU_CONF_TEXT | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY | ELEM_TEXT}, {TK_OPTION_CUSTOM, "-textpadx", (char *) NULL, (char *) NULL, "6", Tk_Offset(HeaderColumn, textPadXObj), Tk_Offset(HeaderColumn, textPadX), 0, (ClientData) &TreeCtrlCO_pad, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY}, {TK_OPTION_CUSTOM, "-textpady", (char *) NULL, (char *) NULL, "0", Tk_Offset(HeaderColumn, textPadYObj), Tk_Offset(HeaderColumn, textPadY), 0, (ClientData) &TreeCtrlCO_pad, COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, 0, 0} }; static Tk_OptionSpec dragSpecs[] = { {TK_OPTION_BOOLEAN, "-draw", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeHeader_, columnDrag.draw), 0, (ClientData) NULL, 0}, {TK_OPTION_BOOLEAN, "-enable", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeHeader_, columnDrag.enable), 0, (ClientData) NULL, 0}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, 0, 0} }; /* We can also configure -height, -tags and -visible item options */ static Tk_OptionSpec headerSpecs[] = { {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, 0, 0} }; /* *---------------------------------------------------------------------- * * HeaderCO_Set -- * * Tk_ObjCustomOption.setProc(). Converts a Tcl_Obj holding a * header description into a TreeHeader. * * Results: * A standard Tcl result. * * Side effects: * May store a TreeHeader pointer into the internal representation * pointer. May change the pointer to the Tcl_Obj to NULL to indicate * that the specified string was empty and that is acceptable. * *---------------------------------------------------------------------- */ static int HeaderCO_Set( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ Tk_Window tkwin, /* Window for which option is being set. */ Tcl_Obj **value, /* Pointer to the pointer to the value object. * We use a pointer to the pointer because * we may need to return a value (NULL). */ char *recordPtr, /* Pointer to storage for the widget record. */ int internalOffset, /* Offset within *recordPtr at which the * internal value is to be stored. */ char *saveInternalPtr, /* Pointer to storage for the old value. */ int flags /* Flags for the option, set Tk_SetOptions. */ ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; int objEmpty; TreeHeader new, *internalPtr; if (internalOffset >= 0) internalPtr = (TreeHeader *) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*value)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) (*value) = NULL; else { if (TreeHeader_FromObj(tree, (*value), &new) != TCL_OK) return TCL_ERROR; } if (internalPtr != NULL) { if ((*value) == NULL) new = NULL; *((TreeHeader *) saveInternalPtr) = *internalPtr; *internalPtr = new; } return TCL_OK; } /* *---------------------------------------------------------------------- * * HeaderCO_Get -- * * Tk_ObjCustomOption.getProc(). Converts a TreeHeader into a * Tcl_Obj string representation. * * Results: * Tcl_Obj containing the string representation of the header. * Returns NULL if the TreeHeader is NULL. * * Side effects: * May create a new Tcl_Obj. * *---------------------------------------------------------------------- */ static Tcl_Obj * HeaderCO_Get( ClientData clientData, /* Not used. */ Tk_Window tkwin, /* Window for which option is being set. */ char *recordPtr, /* Pointer to widget record. */ int internalOffset /* Offset within *recordPtr containing the * sticky value. */ ) { TreeHeader value = *(TreeHeader *) (recordPtr + internalOffset); /* TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData;*/ if (value == NULL) return NULL; #if 0 if (value == COLUMN_ALL) return Tcl_NewStringObj("all", -1); #endif return TreeHeader_ToObj(value); } /* *---------------------------------------------------------------------- * * HeaderCO_Restore -- * * Tk_ObjCustomOption.restoreProc(). Restores a TreeHeader value * from a saved value. * * Results: * None. * * Side effects: * Restores the old value. * *---------------------------------------------------------------------- */ static void HeaderCO_Restore( ClientData clientData, /* Not used. */ Tk_Window tkwin, /* Not used. */ char *internalPtr, /* Where to store old value. */ char *saveInternalPtr) /* Pointer to old value. */ { *(TreeHeader *) internalPtr = *(TreeHeader *) saveInternalPtr; } /* * The following structure contains pointers to functions used for processing * a custom config option that handles Tcl_Obj<->TreeHeader conversion. * A header description must refer to a single header. */ Tk_ObjCustomOption TreeCtrlCO_header = { "header", HeaderCO_Set, HeaderCO_Get, HeaderCO_Restore, NULL, (ClientData) 0 }; /* *---------------------------------------------------------------------- * * LookupOption -- * * Find the configuration option that matches the given * possibly-truncated name. This code was copied from the Tk * sources, but doesn't handle chained option tables. * * Results: * Pointer to the matching option record, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ static Tk_OptionSpec* LookupOption( Tk_OptionSpec *tablePtr, CONST char *name ) { Tk_OptionSpec *specPtr = tablePtr, *bestPtr = NULL; CONST char *p1, *p2; while (specPtr->type != TK_OPTION_END) { for (p1 = name, p2 = specPtr->optionName; *p1 == *p2; p1++, p2++) { if (*p1 == 0) { /* * This is an exact match. We're done. */ bestPtr = specPtr; return bestPtr; } } if (*p1 == 0) { /* * The name is an abbreviation for this option. Keep * to make sure that the abbreviation only matches one * option name. If we've already found a match in the * past, then it is an error unless the full names for * the two options are identical; in this case, the first * option overrides the second. */ if (bestPtr == NULL) { bestPtr = specPtr; } else { if (strcmp(bestPtr->optionName, specPtr->optionName) != 0) { return NULL; } } } specPtr++; } return bestPtr; } /* *---------------------------------------------------------------------- * * TreeHeaderColumn_ConfigureHeaderStyle -- * * Passes configuration option/value pairs to the appropriate * element in the underlying style for a column header. * * If the column header is not using one of the default header * styles, or if this is the tail column, then nothing is done. * * Results: * A standard Tcl result. * * Side effects: * May cause layout changes and a redraw of the widget. * *---------------------------------------------------------------------- */ int TreeHeaderColumn_ConfigureHeaderStyle( TreeHeader header, /* Header containing the column. */ TreeHeaderColumn column, /* Column that was configured. */ TreeColumn treeColumn, /* The tree-column. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Option/value pairs. */ ) { TreeCtrl *tree = header->tree; Tcl_Interp *interp = tree->interp; Tk_OptionSpec *specPtr = columnSpecs; Tk_OptionSpec *staticSpecs[STATIC_SIZE], **specs = staticSpecs; int i, j, infoObjC = 0, elemObjC[4], eMask, iMask = 0; Tcl_Obj *staticInfoObjV[STATIC_SIZE], **infoObjV = staticInfoObjV; Tcl_Obj *staticElemObjV[4][STATIC_SIZE], **elemObjV[4]; Tcl_Obj *textFillObj = NULL, *textLinesObj = NULL, *textFontObj = NULL; int allocSpecs = 0, allocInfoObjV = 0, allocElemObjV[4]; HeaderStyleParams params; int result; /* TODO: If the column header uses a user-defined style, generate a * event. */ if (!TreeStyle_IsHeaderStyle(tree, TreeItemColumn_GetStyle(tree, column->itemColumn))) return TCL_OK; params.text = column->textLen > 0; params.image = column->image != NULL; params.bitmap = !params.image && (column->bitmap != None); /* With no arguments, it means the style was (re)created, so gotta * configure all non-layout options. */ if (objc == 0) { Tcl_Obj *optionNameObj = Tcl_NewObj(); Tcl_IncrRefCount(optionNameObj); for (i = 0; i < 4; i++) elemObjC[i] = 0; while (specPtr->type != TK_OPTION_END) { if (IS_TAIL(treeColumn) && !(specPtr->typeMask & COLU_CONF_TAIL)) { specPtr++; continue; } if (specPtr->typeMask & ELEM_HEADER) { elemObjC[0] += 2; objc += 2; } if (specPtr->typeMask & ELEM_IMAGE) { if (params.image) elemObjC[1] += 2; objc += 2; } if (specPtr->typeMask & ELEM_TEXT) { if (params.text) elemObjC[2] += 2; objc += 2; } if (specPtr->typeMask & ELEM_BITMAP) { if (params.bitmap) elemObjC[3] += 2; objc += 2; } specPtr++; } allocInfoObjV = objc / 2; STATIC_ALLOC(infoObjV, Tcl_Obj *, allocInfoObjV); for (i = 0; i < 4; i++) { elemObjV[i] = staticElemObjV[i]; allocElemObjV[i] = elemObjC[i]; STATIC_ALLOC(elemObjV[i], Tcl_Obj *, allocElemObjV[i]); elemObjC[i] = 0; } specPtr = columnSpecs; while (specPtr->type != TK_OPTION_END) { if (IS_TAIL(treeColumn) && !(specPtr->typeMask & COLU_CONF_TAIL)) { specPtr++; continue; } if (specPtr->typeMask & (ELEM_HEADER | ELEM_IMAGE | ELEM_TEXT | ELEM_BITMAP)) { int listC; Tcl_Obj *infoObj, **listObjV; Tcl_SetStringObj(optionNameObj, specPtr->optionName, -1); infoObj = Tk_GetOptionInfo(interp, (char *) column, tree->headerColumnOptionTable, optionNameObj, tree->tkwin); Tcl_IncrRefCount(infoObj); Tcl_ListObjGetElements(interp, infoObj, &listC, &listObjV); if (specPtr->typeMask & ELEM_HEADER) { elemObjV[0][elemObjC[0]++] = listObjV[0]; /* name */ elemObjV[0][elemObjC[0]++] = listObjV[4]; /* value */ } if (specPtr->typeMask & ELEM_IMAGE) { if (params.image) { elemObjV[1][elemObjC[1]++] = listObjV[0]; /* name */ elemObjV[1][elemObjC[1]++] = listObjV[4]; /* value */ } } if (specPtr->typeMask & ELEM_TEXT) { if (params.text) { if (!strcmp(specPtr->optionName, "-textcolor")) { if (textFillObj == NULL) { textFillObj = Tcl_NewStringObj("-fill", -1); Tcl_IncrRefCount(textFillObj); } elemObjV[2][elemObjC[2]++] = textFillObj; } else if (!strcmp(specPtr->optionName, "-textlines")) { if (textLinesObj == NULL) { textLinesObj = Tcl_NewStringObj("-lines", -1); Tcl_IncrRefCount(textLinesObj); } elemObjV[2][elemObjC[2]++] = textLinesObj; } else { elemObjV[2][elemObjC[2]++] = listObjV[0]; /* name */ } /* Text element -font is per-state. */ if (!strcmp(specPtr->optionName, "-font")) { textFontObj = Tcl_NewListObj(1, &listObjV[4]); Tcl_IncrRefCount(textFontObj); elemObjV[2][elemObjC[2]++] = textFontObj; /* value */ } else { elemObjV[2][elemObjC[2]++] = listObjV[4]; /* value */ } } } if (specPtr->typeMask & ELEM_BITMAP) { if (params.bitmap) { elemObjV[3][elemObjC[3]++] = listObjV[0]; /* name */ elemObjV[3][elemObjC[3]++] = listObjV[4]; /* value */ } } infoObjV[infoObjC++] = infoObj; } specPtr++; } Tcl_DecrRefCount(optionNameObj); objc = 0; /* Some option/value pairs were given. */ } else { for (i = 0; i < 4; i++) { elemObjV[i] = staticElemObjV[i]; allocElemObjV[i] = objc; STATIC_ALLOC(elemObjV[i], Tcl_Obj *, allocElemObjV[i]); elemObjC[i] = 0; } /* Remove duplicate options (see use of textFontObj). */ allocSpecs = objc; STATIC_ALLOC(specs, Tk_OptionSpec *, allocSpecs); for (i = 0; i < objc; i += 2) { specs[i] = LookupOption(columnSpecs, Tcl_GetString(objv[i])); for (j = 0; j < i; j += 2) { if (specs[j] == specs[i]) { specs[j] = NULL; break; } } } for (i = 0; i < objc; i += 2) { specPtr = specs[i]; if (specPtr == NULL) continue; if (IS_TAIL(treeColumn) && !(specPtr->typeMask & COLU_CONF_TAIL)) continue; if (specPtr->typeMask & ELEM_HEADER) { elemObjV[0][elemObjC[0]++] = objv[i]; /* name */ elemObjV[0][elemObjC[0]++] = objv[i + 1]; /* value */ } if (specPtr->typeMask & ELEM_IMAGE) { if (params.image) { elemObjV[1][elemObjC[1]++] = objv[i]; /* name */ elemObjV[1][elemObjC[1]++] = objv[i + 1]; /* value */ } } if (specPtr->typeMask & ELEM_TEXT) { if (params.text) { if (!strcmp(specPtr->optionName, "-textcolor")) { if (textFillObj == NULL) { textFillObj = Tcl_NewStringObj("-fill", -1); Tcl_IncrRefCount(textFillObj); } elemObjV[2][elemObjC[2]++] = textFillObj; } else if (!strcmp(specPtr->optionName, "-textlines")) { if (textLinesObj == NULL) { textLinesObj = Tcl_NewStringObj("-lines", -1); Tcl_IncrRefCount(textLinesObj); } elemObjV[2][elemObjC[2]++] = textLinesObj; } else { elemObjV[2][elemObjC[2]++] = objv[i]; /* name */ } /* Text element -font is per-state. */ if (!strcmp(specPtr->optionName, "-font")) { textFontObj = Tcl_NewListObj(1, &objv[i + 1]); Tcl_IncrRefCount(textFontObj); elemObjV[2][elemObjC[2]++] = textFontObj; /* value */ } else { elemObjV[2][elemObjC[2]++] = objv[i + 1]; /* value */ } } } if (specPtr->typeMask & ELEM_BITMAP) { if (params.bitmap) { elemObjV[3][elemObjC[3]++] = objv[i]; /* name */ elemObjV[3][elemObjC[3]++] = objv[i + 1]; /* value */ } } } } if (elemObjC[0] > 0) { result = TreeStyle_ElementConfigure(tree, header->item, column->itemColumn, TreeItemColumn_GetStyle(tree, column->itemColumn), tree->headerStyle.headerElem, elemObjC[0], elemObjV[0], &eMask); if (result != TCL_OK) Tcl_BackgroundError(interp); iMask |= eMask; } if (elemObjC[1] > 0) { result = TreeStyle_ElementConfigure(tree, header->item, column->itemColumn, TreeItemColumn_GetStyle(tree, column->itemColumn), tree->headerStyle.imageElem, elemObjC[1], elemObjV[1], &eMask); if (result != TCL_OK) Tcl_BackgroundError(interp); iMask |= eMask; } if (elemObjC[2] > 0) { result = TreeStyle_ElementConfigure(tree, header->item, column->itemColumn, TreeItemColumn_GetStyle(tree, column->itemColumn), tree->headerStyle.textElem, elemObjC[2], elemObjV[2], &eMask); if (result != TCL_OK) Tcl_BackgroundError(interp); iMask |= eMask; } if (elemObjC[3] > 0) { result = TreeStyle_ElementConfigure(tree, header->item, column->itemColumn, TreeItemColumn_GetStyle(tree, column->itemColumn), tree->headerStyle.bitmapElem, elemObjC[3], elemObjV[3], &eMask); if (result != TCL_OK) Tcl_BackgroundError(interp); iMask |= eMask; } if (iMask & CS_LAYOUT) { TreeItem_InvalidateHeight(tree, header->item); TreeItemColumn_InvalidateSize(tree, column->itemColumn); Tree_FreeItemDInfo(tree, header->item, NULL); TreeColumns_InvalidateWidthOfItems(tree, treeColumn); } else if (iMask & CS_DISPLAY) Tree_InvalidateItemDInfo(tree, treeColumn, header->item, NULL); for (i = 0; i < infoObjC; i++) Tcl_DecrRefCount(infoObjV[i]); if (textFillObj != NULL) Tcl_DecrRefCount(textFillObj); if (textLinesObj != NULL) Tcl_DecrRefCount(textLinesObj); if (textFontObj != NULL) Tcl_DecrRefCount(textFontObj); for (i = 0; i < 4; i++) STATIC_FREE(elemObjV[i], Tcl_Obj *, allocElemObjV[i]); STATIC_FREE(infoObjV, Tcl_Obj *, allocInfoObjV); STATIC_FREE(specs, Tk_OptionSpec *, allocSpecs); return TCL_OK; } /* *---------------------------------------------------------------------- * * Column_Configure -- * * This procedure is called to process an objc/objv list to set * configuration options for a HeaderColumn. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then an error message is left in interp's result. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for column; old resources get freed, if there * were any. Display changes may occur. * *---------------------------------------------------------------------- */ static int Column_Configure( TreeHeader header, /* Header token. */ TreeHeaderColumn column, /* Column token. */ TreeColumn treeColumn, /* Column token. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int createFlag /* TRUE if the Column is being created. */ ) { TreeCtrl *tree = header->tree; HeaderColumn saved; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; int mask, maskFree = 0; int state = column->state, arrow = column->arrow; /* Init these to prevent compiler warnings */ saved.image = NULL; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, STATE_DOMAIN_HEADER, column, tree->headerColumnOptionTable, objc, objv, &savedOptions, &mask) != TCL_OK) { mask = 0; continue; } /* Wouldn't have to do this if Tk_InitOptions() would return * a mask of configured options like Tk_SetOptions() does. */ if (createFlag) { if (column->imageString != NULL) mask |= COLU_CONF_IMAGE; } /* * Step 1: Save old values */ if (mask & COLU_CONF_IMAGE) saved.image = column->image; /* * Step 2: Process new values */ if (mask & COLU_CONF_IMAGE) { if (column->imageString == NULL) { column->image = NULL; } else { column->image = Tree_GetImage(tree, column->imageString); if (column->image == NULL) continue; maskFree |= COLU_CONF_IMAGE; } } /* * Step 3: Free saved values */ if (mask & COLU_CONF_IMAGE) { if (saved.image != NULL) Tree_FreeImage(tree, saved.image); } Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); /* * Free new values. */ if (maskFree & COLU_CONF_IMAGE) Tree_FreeImage(tree, column->image); /* * Restore old values. */ if (mask & COLU_CONF_IMAGE) column->image = saved.image; Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } /* Wouldn't have to do this if Tk_InitOptions() would return * a mask of configured options like Tk_SetOptions() does. */ if (createFlag) { if (column->textObj != NULL) mask |= COLU_CONF_TEXT; if (column->bitmap != None) mask |= COLU_CONF_BITMAP; } if (mask & COLU_CONF_TEXT) { if (column->textObj != NULL) (void) Tcl_GetStringFromObj(column->textObj, &column->textLen); else column->textLen = 0; } /* Keep the STATE_HEADER_XXX flags in sync. */ /* FIXME: don't call TreeItemColumn_ChangeState twice here */ if (treeColumn != tree->columnTail && state != column->state) { int stateOff = 0, stateOn = 0; switch (state) { case COLUMN_STATE_ACTIVE: stateOff = STATE_HEADER_ACTIVE; break; case COLUMN_STATE_NORMAL: stateOff = STATE_HEADER_NORMAL; break; case COLUMN_STATE_PRESSED: stateOff = STATE_HEADER_PRESSED; break; } switch (column->state) { case COLUMN_STATE_ACTIVE: stateOn = STATE_HEADER_ACTIVE; break; case COLUMN_STATE_NORMAL: stateOn = STATE_HEADER_NORMAL; break; case COLUMN_STATE_PRESSED: stateOn = STATE_HEADER_PRESSED; break; } TreeItemColumn_ChangeState(tree, header->item, column->itemColumn, treeColumn, stateOff, stateOn); } if (treeColumn != tree->columnTail && arrow != column->arrow) { int stateOff = 0, stateOn = 0; switch (arrow) { case COLUMN_ARROW_UP: stateOff = STATE_HEADER_SORT_UP; break; case COLUMN_ARROW_DOWN: stateOff = STATE_HEADER_SORT_DOWN; break; } switch (column->arrow) { case COLUMN_ARROW_UP: stateOn = STATE_HEADER_SORT_UP; break; case COLUMN_ARROW_DOWN: stateOn = STATE_HEADER_SORT_DOWN; break; } TreeItemColumn_ChangeState(tree, header->item, column->itemColumn, treeColumn, stateOff, stateOn); } if (!createFlag) { TreeHeaderColumn_EnsureStyleExists(header, column, treeColumn); TreeHeaderColumn_ConfigureHeaderStyle(header, column, treeColumn, objc, objv); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeHeaderColumn_EnsureStyleExists -- * * This procedure maintains the style assigned to a column header. * If the column header uses a custom user-defined style, it is left * alone. Otherwise, a new header style may be created if one * doesn't already exist that satisfies the various configuration * options of the column header. If a new header style is created, * the current instance style (if any) is freed and a new instance * style is assigned and configured. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeHeaderColumn_EnsureStyleExists( TreeHeader header, /* Header token. */ TreeHeaderColumn column, /* Column token. */ TreeColumn treeColumn /* Column token. */ ) { TreeCtrl *tree = header->tree; TreeItemColumn itemColumn = column->itemColumn; TreeStyle styleOld, styleNew; HeaderStyleParams params; int i; styleOld = TreeItemColumn_GetStyle(tree, itemColumn); if (styleOld != NULL) { styleOld = TreeStyle_GetMaster(tree, styleOld); if (!TreeStyle_IsHeaderStyle(tree, styleOld)) return TCL_OK; /* it's a custom style */ } params.justify = column->justify; params.text = column->textLen > 0; params.image = column->image != NULL; params.bitmap = !params.image && (column->bitmap != None); for (i = 0; i < 2; i++) { params.textPadX[i] = column->textPadX[i]; params.textPadY[i] = column->textPadY[i]; params.imagePadX[i] = column->imagePadX[i]; params.imagePadY[i] = column->imagePadY[i]; } if (treeColumn == tree->columnTail) { params.text = params.image = params.bitmap = FALSE; } styleNew = Tree_MakeHeaderStyle(tree, ¶ms); if (styleOld != styleNew) { styleNew = TreeStyle_NewInstance(tree, styleNew); TreeItemColumn_SetStyle(tree, itemColumn, styleNew); TreeHeaderColumn_ConfigureHeaderStyle(header, column, treeColumn, 0, NULL); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeHeader_ConsumeColumnCget -- * * Sets the interpreter result to the value of a single configuration * option for a header-column. This is called when an unknown * option is passed to [column cget]. It operates on the first * row of headers only. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeHeader_ConsumeColumnCget( TreeCtrl *tree, /* Widget info. */ TreeColumn treeColumn, /* Used to determine which header-column to * get the option value from. */ Tcl_Obj *objPtr /* Object holding the name of the option. */ ) { TreeItemColumn itemColumn; TreeHeaderColumn column; Tcl_Obj *resultObjPtr; #ifdef TREECTRL_DEBUG if (tree->headerItems == NULL) panic("the default header was deleted!"); #endif itemColumn = TreeItem_FindColumn(tree, tree->headerItems, TreeColumn_Index(treeColumn)); #ifdef TREECTRL_DEBUG if (itemColumn == NULL) panic("the default header is missing column %s%d!", tree->columnPrefix, TreeColumn_GetID(treeColumn)); #endif column = TreeItemColumn_GetHeaderColumn(tree, itemColumn); resultObjPtr = Tk_GetOptionValue(tree->interp, (char *) column, tree->headerColumnOptionTable, objPtr, tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(tree->interp, resultObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeHeader_ConsumeColumnConfig -- * * Configures a header-column with option/value pairs. This is * called by [column configure] for any unknown options. It * operates on the first row of headers only. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeHeader_ConsumeColumnConfig( TreeCtrl *tree, /* Widget info. */ TreeColumn treeColumn, /* Used to determine which header-column to * configure. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int createFlag /* TRUE if column is being created. */ ) { TreeItemColumn itemColumn; TreeHeaderColumn column; #if 1 if (objc <= 0) #else if ((objc <= 0) || (treeColumn == tree->columnTail)) #endif return TCL_OK; #ifdef TREECTRL_DEBUG if (tree->headerItems == NULL) panic("the default header was deleted!"); #endif itemColumn = TreeItem_FindColumn(tree, tree->headerItems, TreeColumn_Index(treeColumn)); #ifdef TREECTRL_DEBUG if (itemColumn == NULL) panic("the default header is missing column %s%d!", tree->columnPrefix, TreeColumn_GetID(treeColumn)); #endif column = TreeItemColumn_GetHeaderColumn(tree, itemColumn); return Column_Configure(TreeItem_GetHeader(tree, tree->headerItems), column, treeColumn, objc, objv, createFlag); } /* *---------------------------------------------------------------------- * * TreeHeader_ConsumeColumnOptionInfo -- * * Retrieves the info for one or all configuration options of a * header-column. This is called when an unknown option is passed * to [column configure]. It operates on the first row of * headers only. * * Results: * A pointer to a list object containing the configuration info * for the option(s), or NULL if an error occurs. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeHeader_ConsumeColumnOptionInfo( TreeCtrl *tree, /* Widget info. */ TreeColumn treeColumn, /* Used to determine which header-column * to get the option info from. */ Tcl_Obj *objPtr /* Option name or NULL for every option. */ ) { TreeItemColumn itemColumn; TreeHeaderColumn column; #ifdef TREECTRL_DEBUG if (tree->headerItems == NULL) panic("the default header was deleted!"); #endif itemColumn = TreeItem_FindColumn(tree, tree->headerItems, TreeColumn_Index(treeColumn)); #ifdef TREECTRL_DEBUG if (itemColumn == NULL) panic("the default header is missing column %s%d!", tree->columnPrefix, TreeColumn_GetID(treeColumn)); #endif column = TreeItemColumn_GetHeaderColumn(tree, itemColumn); return Tk_GetOptionInfo(tree->interp, (char *) column, tree->headerColumnOptionTable, objPtr, tree->tkwin); } /* *---------------------------------------------------------------------- * * TreeHeaderColumn_GetImageOrText -- * * Retrieves the value of the -image or -text option of a * header-column. * This is called by the [header image] and [header text] command * when a header-column has no style or no style with a text * element. * * Results: * A point to an object containing the value of the -image or * -text option, which may be NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeHeaderColumn_GetImageOrText( TreeHeader header, /* Header token. */ TreeHeaderColumn column, /* Column token. */ int isImage ) { TreeCtrl *tree = header->tree; return Tk_GetOptionValue(tree->interp, (char *) column, tree->headerColumnOptionTable, isImage ? tree->imageOptionNameObj : tree->textOptionNameObj, tree->tkwin); } /* *---------------------------------------------------------------------- * * TreeHeaderColumn_SetImageOrText -- * * Configures the -image or -text option of a header-column. * This is called by the [header image] and [header text] commands * when a header-column has no style or no style with a text * element. * * Results: * A standard Tcl result. * * Side effects: * Header layout may change, a redraw may get scheduled. * *---------------------------------------------------------------------- */ int TreeHeaderColumn_SetImageOrText( TreeHeader header, /* Header token. */ TreeHeaderColumn column, /* Column token. */ TreeColumn treeColumn, /* Column token. */ Tcl_Obj *valueObj, /* New value of -image or -text option */ int isImage /* TRUE to configure the -image option, * FALSE to configure the -text option. */ ) { TreeCtrl *tree = header->tree; int objc = 2; Tcl_Obj *objv[2]; objv[0] = isImage ? tree->imageOptionNameObj : tree->textOptionNameObj; objv[1] = valueObj; return Column_Configure(header, column, treeColumn, objc, objv, FALSE); } static TreeColumn GetFollowingColumn( TreeColumn column, int n, TreeColumn stop ) { while (--n > 0) { TreeColumn next = TreeColumn_Next(column); if (next == NULL) break; if (next == stop) break; if (TreeColumn_Lock(next) != TreeColumn_Lock(column)) break; column = next; } return column; } /* *---------------------------------------------------------------------- * * TreeHeader_ColumnDragOrder -- * * Calculates the display order of a column during drag-and-drop. * If no column headers are being dragged, or there is no indicator * column, or this header isn't displaying drag-and-drop feedback, * then the column order is unchanged. * * Results: * The possibly-updated display order for the column. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeHeader_ColumnDragOrder( TreeHeader header, /* Header token. */ TreeColumn column, /* Column to get updated index for. */ int index /* Zero-based index of this column in * the list of all columns with the same * -lock value. */ ) { TreeCtrl *tree = header->tree; TreeColumn column1min, column1max; TreeColumn column2min, column2max; int index1min, index1max; int index2min, index2max; int index3; if (!header->columnDrag.draw) return index; if (tree->columnDrag.column == NULL) return index; if (tree->columnDrag.indColumn == NULL) return index; column1min = tree->columnDrag.column; column1max = GetFollowingColumn(column1min, tree->columnDrag.span, NULL); index1min = TreeColumn_Index(column1min); index1max = TreeColumn_Index(column1max); column2min = tree->columnDrag.indColumn; column2max = GetFollowingColumn(column2min, tree->columnDrag.indSpan, column1min); index2min = TreeColumn_Index(column2min); index2max = TreeColumn_Index(column2max); /* The library scripts shouldn't pass an indicator column that is * one of the columns being dragged. */ if (index2min >= index1min && index2min <= index1max) return index; index3 = TreeColumn_Index(column); /* D D D D D C C C I I I I I I I I */ if (index1min < index2min) { if (index3 > index1max && index3 <= index2max) return index - (index1max - index1min + 1); if (index3 >= index1min && index3 <= index1max) return index + (index2max - index1max); /* I I I I I I I I C C C D D D D D */ } else { if (index3 >= index2min && index3 < index1min) return index + (index1max - index1min + 1); if (index3 >= index1min && index3 <= index1max) return index - (index1min - index2min); } return index; } /* *---------------------------------------------------------------------- * * TreeHeader_GetDraggedColumns -- * * Returns the first and last columns in the range of columns * whose headers are being dragged. * If the header isn't displaying drag-and-drop feedback, the * result is always zero. * * Results: * The number of columns which may be zero. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeHeader_GetDraggedColumns( TreeHeader header, /* Header token. */ int lock, /* COLUMN_LOCK_XXX. */ TreeColumn *first, /* Out: First dragged column, or NULL. */ TreeColumn *last /* Out: Last dragged column, or NULL */ ) { TreeCtrl *tree = header->tree; TreeColumn column1min, column1max; int index1min, index1max; if (tree->columnDrag.column == NULL) return 0; if (TreeColumn_Lock(tree->columnDrag.column) != lock) return 0; if (!header->columnDrag.draw) return 0; column1min = tree->columnDrag.column; column1max = GetFollowingColumn(column1min, tree->columnDrag.span, NULL); index1min = TreeColumn_Index(column1min); index1max = TreeColumn_Index(column1max); *first = column1min; *last = column1max; return index1max - index1min + 1; } /* *---------------------------------------------------------------------- * * TreeHeader_IsDraggedColumn -- * * Returns TRUE if the header for a column is being dragged. * If the header isn't displaying drag-and-drop feedback, the * result is always FALSE. * * Results: * TRUE or FALSE. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeHeader_IsDraggedColumn( TreeHeader header, /* Header token. */ TreeColumn treeColumn /* Column to test. */ ) { TreeCtrl *tree = header->tree; TreeColumn column1min, column1max; int index1min, index1max, index3; if (tree->columnDrag.column == NULL) return 0; if (!header->columnDrag.draw) return 0; column1min = tree->columnDrag.column; column1max = GetFollowingColumn(column1min, tree->columnDrag.span, NULL); index1min = TreeColumn_Index(column1min); index1max = TreeColumn_Index(column1max); index3 = TreeColumn_Index(treeColumn); return index3 >= index1min && index3 <= index1max; } static void RequiredDummyChangedProc( ClientData clientData, /* Widget info. */ int x, int y, /* Upper left pixel (within image) * that must be redisplayed. */ int width, int height, /* Dimensions of area to redisplay * (may be <= 0). */ int imageWidth, int imageHeight /* New dimensions of image. */ ) { } /* *---------------------------------------------------------------------- * * SetImageForColumn -- * * Sets a photo image to contain a picture of the header of a * column. This image is used when dragging and dropping a column * header. * * Results: * Token for a photo image, or NULL if the image could not be * created. * * Side effects: * A photo image called "::TreeCtrl::ImageColumn" will be created if * it doesn't exist. The image is set to contain a picture of the * column header. * *---------------------------------------------------------------------- */ static Tk_Image SetImageForColumn( TreeHeader header, /* Header token. */ TreeHeaderColumn column, /* Column token. */ TreeColumn treeColumn, /* Column token. */ int indent, /* */ int width, /* Width of the header and image */ int height /* Height of the header and image */ ) { TreeCtrl *tree = header->tree; TreeItem item = header->item; Tk_PhotoHandle photoH; TreeDrawable td; XImage *ximage; char imageName[128]; if ((column->dragImage != NULL) && (column->imageEpoch == tree->columnDrag.imageEpoch)) return column->dragImage; sprintf(imageName, "::TreeCtrl::ImageColumnH%dC%d", TreeItem_GetID(tree, header->item), TreeColumn_GetID(treeColumn)); column->dragImageName = Tk_GetUid(imageName); photoH = Tk_FindPhoto(tree->interp, imageName); if (photoH == NULL) { char buf[256]; sprintf(buf, "image create photo %s", imageName); Tcl_GlobalEval(tree->interp, buf); photoH = Tk_FindPhoto(tree->interp, imageName); if (photoH == NULL) return NULL; } td.width = width; td.height = height; td.drawable = Tk_GetPixmap(tree->display, Tk_WindowId(tree->tkwin), width, height, Tk_Depth(tree->tkwin)); { GC gc = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC); TreeRectangle tr; TreeRect_SetXYWH(tr, 0, 0, width, height); Tree_FillRectangle(tree, td, NULL, gc, tr); } if (TreeItemColumn_GetStyle(tree, column->itemColumn) != NULL) { StyleDrawArgs drawArgs; int area = TREE_AREA_HEADER_NONE; switch (TreeColumn_Lock(treeColumn)) { case COLUMN_LOCK_LEFT: area = TREE_AREA_HEADER_LEFT; break; case COLUMN_LOCK_RIGHT: area = TREE_AREA_HEADER_RIGHT; break; } if (!Tree_AreaBbox(tree, area, &drawArgs.bounds)) { TreeRect_SetXYWH(drawArgs.bounds, 0, 0, 0, 0); } drawArgs.tree = tree; drawArgs.item = item; /* needed for gradients */ drawArgs.td = td; drawArgs.state = TreeItem_GetState(tree, item) | TreeItemColumn_GetState(tree, column->itemColumn); drawArgs.style = TreeItemColumn_GetStyle(tree, column->itemColumn); drawArgs.indent = indent; drawArgs.x = 0; drawArgs.y = 0; drawArgs.width = width, drawArgs.height = height; drawArgs.justify = column->justify; drawArgs.column = treeColumn; TreeStyle_Draw(&drawArgs); } /* Pixmap -> XImage */ ximage = XGetImage(tree->display, td.drawable, 0, 0, (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); if (ximage == NULL) panic("tkTreeColumn.c:SetImageForColumn() ximage is NULL"); /* XImage -> Tk_Image */ Tree_XImage2Photo(tree->interp, photoH, ximage, 0, tree->columnDrag.alpha); XDestroyImage(ximage); Tk_FreePixmap(tree->display, td.drawable); column->dragImage = Tk_GetImage(tree->interp, tree->tkwin, imageName, RequiredDummyChangedProc, (ClientData) NULL); column->imageEpoch = tree->columnDrag.imageEpoch; return column->dragImage; } /* *---------------------------------------------------------------------- * * TreeHeaderColumn_Draw -- * * Draws a single header-column. If the column header is being * drawn at its drag position, a transparent image of the header * is rendered overtop whatever is in the drawable. Otherwise, * the background is erased to the treectrl's -background color, * then the style is drawn if the column header isn't part of * the drag image (or the hidden tail column). * * Results: * None. * * Side effects: * Stuff is drawn in a drawable. * *---------------------------------------------------------------------- */ void TreeHeaderColumn_Draw( TreeHeader header, /* Header token. */ TreeHeaderColumn column, /* Column token. */ int visIndex, /* 0-based index in the list of spans. */ StyleDrawArgs *drawArgs, /* Various args. */ int dragPosition /* TRUE if this header is being drawn at * its drag position (i.e., offset by * -imageoffset). */ ) { TreeCtrl *tree = header->tree; TreeDrawable td = drawArgs->td; TreeColumn column1min, column1max; int index1min, index1max, index3; int x = drawArgs->x, y = drawArgs->y, width = drawArgs->width, height = drawArgs->height; int isDragColumn = 0, isHiddenTail; GC gc; TreeRectangle tr; if (header->columnDrag.draw == TRUE && tree->columnDrag.column != NULL) { column1min = tree->columnDrag.column; column1max = GetFollowingColumn(column1min, tree->columnDrag.span, NULL); index1min = TreeColumn_Index(column1min); index1max = TreeColumn_Index(column1max); index3 = TreeColumn_Index(drawArgs->column); isDragColumn = index3 >= index1min && index3 <= index1max; } /* Don't draw the tail column if it isn't visible. * Currently a span is always created for the tail column. */ isHiddenTail = (drawArgs->column == tree->columnTail) && !TreeColumn_Visible(drawArgs->column); if (!isDragColumn || !dragPosition) { gc = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC); TreeRect_SetXYWH(tr, x, y, width, height); Tree_FillRectangle(tree, td, NULL, gc, tr); } if ((drawArgs->style != NULL) && !isDragColumn && !isHiddenTail) { StyleDrawArgs drawArgsCopy = *drawArgs; TreeStyle_Draw(&drawArgsCopy); } if (isDragColumn && dragPosition) { Tk_Image image; image = SetImageForColumn(header, column, drawArgs->column, 0, width, height); if (image != NULL) { Tree_RedrawImage(image, 0, 0, width, height, td, x, y); } } } /* *---------------------------------------------------------------------- * * TreeHeaderColumn_Justify -- * * Returns the value of the -justify option for a header-column. * * Results: * A Tk_Justify value. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tk_Justify TreeHeaderColumn_Justify( TreeHeader header, /* Header token. */ TreeHeaderColumn column /* Column token. */ ) { return column->justify; } /* *---------------------------------------------------------------------- * * Header_Configure -- * * This procedure is called to process an objc/objv list to set * configuration options for a TreeHeader. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then an error message is left in interp's result. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for 'header'; old resources get freed, if there * were any. Display changes may occur. * *---------------------------------------------------------------------- */ static int Header_Configure( TreeHeader header, /* Header token */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int createFlag /* TRUE if the TreeHeader is being created. */ ) { TreeCtrl *tree = header->tree; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; int mask; int objC = 0, iObjC = 0; Tcl_Obj *staticObjV[STATIC_SIZE], **objV = staticObjV; Tcl_Obj *staticIObjV[STATIC_SIZE], **iObjV = staticIObjV; int i, oldVisible = TreeItem_ReallyVisible(tree, header->item); /* Hack -- Pass all unknown options to the underlying item. */ STATIC_ALLOC(objV, Tcl_Obj *, objc); STATIC_ALLOC(iObjV, Tcl_Obj *, objc); for (i = 0; i < objc; i += 2) { Tk_OptionSpec *specPtr = headerSpecs; int length; CONST char *optionName = Tcl_GetStringFromObj(objv[i], &length); while (specPtr->type != TK_OPTION_END) { if (strncmp(specPtr->optionName, optionName, length) == 0) { objV[objC++] = objv[i]; if (i + 1 < objc) objV[objC++] = objv[i + 1]; break; } specPtr++; } if (specPtr->type == TK_OPTION_END) { iObjV[iObjC++] = objv[i]; if (i + 1 < objc) iObjV[iObjC++] = objv[i + 1]; } } if (TreeItem_ConsumeHeaderConfig(tree, header->item, iObjC, iObjV) != TCL_OK) { STATIC_FREE(objV, Tcl_Obj *, objc); STATIC_FREE(iObjV, Tcl_Obj *, objc); return TCL_ERROR; } for (error = 0; error <= 1; error++) { if (error == 0) { if (Tk_SetOptions(tree->interp, (char *) header, tree->headerOptionTable, objC, objV, tree->tkwin, &savedOptions, &mask) != TCL_OK) { mask = 0; continue; } /* Wouldn't have to do this if Tk_InitOptions() would return * a mask of configured options like Tk_SetOptions() does. */ if (createFlag) { } /* * Step 1: Save old values */ /* * Step 2: Process new values */ /* * Step 3: Free saved values */ Tk_FreeSavedOptions(&savedOptions); STATIC_FREE(objV, Tcl_Obj *, objc); STATIC_FREE(iObjV, Tcl_Obj *, objc); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); /* * Free new values. */ /* * Restore old values. */ Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); STATIC_FREE(objV, Tcl_Obj *, objc); STATIC_FREE(iObjV, Tcl_Obj *, objc); return TCL_ERROR; } } if (oldVisible != TreeItem_ReallyVisible(tree, header->item)) { tree->headerHeight = -1; Tree_FreeItemDInfo(tree, header->item, NULL); TreeColumns_InvalidateWidth(tree); Tree_DInfoChanged(tree, DINFO_DRAW_HEADER); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeHeaderColumn_CreateWithItemColumn -- * * Allocates and initializes a new header-column. * * Results: * A token for the new header-column. * * Side effects: * Memory allocation, option initialization. * *---------------------------------------------------------------------- */ TreeHeaderColumn TreeHeaderColumn_CreateWithItemColumn( TreeHeader header, /* Header token. */ TreeItemColumn itemColumn /* Newly-created item-column to * assocate the new header-column * with. */ ) { TreeCtrl *tree = header->tree; TreeHeaderColumn column; column = (TreeHeaderColumn) ckalloc(sizeof(HeaderColumn)); memset(column, '\0', sizeof(HeaderColumn)); if (Tree_InitOptions(tree, STATE_DOMAIN_HEADER, column, tree->headerColumnOptionTable) != TCL_OK) { WFREE(column, HeaderColumn); return NULL; } /* FIXME: should call Column_Configure to handle any option-database tomfoolery */ column->itemColumn = itemColumn; tree->headerHeight = -1; return column; } /* *---------------------------------------------------------------------- * * TreeHeader_CreateWithItem -- * * Allocates and initializes a new row of column headers. * * Results: * A token for the new header. * * Side effects: * Memory allocation, option initialization. * *---------------------------------------------------------------------- */ TreeHeader TreeHeader_CreateWithItem( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Newly-created item to associate the * new header with. */ ) { TreeHeader header; header = (TreeHeader) ckalloc(sizeof(TreeHeader_)); memset(header, '\0', sizeof(TreeHeader_)); if (Tk_InitOptions(tree->interp, (char *) header, tree->headerOptionTable, tree->tkwin) != TCL_OK) { WFREE(header, TreeHeader_); return NULL; } if (Tk_InitOptions(tree->interp, (char *) header, tree->headerDragOptionTable, tree->tkwin) != TCL_OK) { Tk_FreeConfigOptions((char *) header, tree->headerOptionTable, tree->tkwin); WFREE(header, TreeHeader_); return NULL; } header->tree = tree; header->item = item; return header; } /* *---------------------------------------------------------------------- * * FreeDragImages -- * * Free the drag-and-drop images for all header-columns that have * one. * * Results: * None. * * Side effects: * Images may be freed. * *---------------------------------------------------------------------- */ static void FreeDragImages( TreeCtrl *tree ) { TreeItem item; TreeItemColumn itemColumn; for (item = tree->headerItems; item != NULL; item = TreeItem_GetNextSibling(tree, item)) { for (itemColumn = TreeItem_GetFirstColumn(tree, item); itemColumn != NULL; itemColumn = TreeItemColumn_GetNext(tree, itemColumn)) { TreeHeaderColumn column = TreeItemColumn_GetHeaderColumn(tree, itemColumn); if (column->dragImage != NULL) { Tk_FreeImage(column->dragImage); Tk_DeleteImage(tree->interp, column->dragImageName); column->dragImage = NULL; } } } } /* *---------------------------------------------------------------------- * * TreeHeader_ColumnDeleted -- * * Called when a tree-column is deleted. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeHeader_ColumnDeleted( TreeCtrl *tree, /* Widget info. */ TreeColumn treeColumn /* Column being deleted. */ ) { if (treeColumn == tree->columnDrag.column) { FreeDragImages(tree); tree->columnDrag.column = NULL; } if (treeColumn == tree->columnDrag.indColumn) tree->columnDrag.indColumn = NULL; } /* *---------------------------------------------------------------------- * * TreeHeaderColumn_FreeResources -- * * Frees any memory and options associated with a header-column. * * Results: * None. * * Side effects: * Memory is freed. * *---------------------------------------------------------------------- */ void TreeHeaderColumn_FreeResources( TreeCtrl *tree, /* Widget info. */ TreeHeaderColumn column /* Column token. */ ) { if (column->image != NULL) Tree_FreeImage(tree, column->image); if (column->dragImage != NULL) { Tk_FreeImage(column->dragImage); Tk_DeleteImage(tree->interp, column->dragImageName); } Tk_FreeConfigOptions((char *) column, tree->headerColumnOptionTable, tree->tkwin); WFREE(column, HeaderColumn); } /* *---------------------------------------------------------------------- * * TreeHeader_FreeResources -- * * Frees any memory and options associated with a header. * * Results: * None. * * Side effects: * Memory is freed. * *---------------------------------------------------------------------- */ void TreeHeader_FreeResources( TreeHeader header /* Header to free. */ ) { TreeCtrl *tree = header->tree; Tk_FreeConfigOptions((char *) header, tree->headerOptionTable, tree->tkwin); Tk_FreeConfigOptions((char *) header, tree->headerDragOptionTable, tree->tkwin); WFREE(header, TreeHeader_); } /* *---------------------------------------------------------------------- * * TreeHeaders_RequestWidthInColumns -- * * Calculates the width needed by styles in a range of columns * for every visible header-row. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeHeaders_RequestWidthInColumns( TreeCtrl *tree, /* Widget info. */ TreeColumn columnMin, TreeColumn columnMax ) { TreeItem item = tree->headerItems; while (item != NULL) { if (TreeItem_ReallyVisible(tree, item)) { TreeItem_RequestWidthInColumns(tree, item, columnMin, columnMax); } item = TreeItem_GetNextSibling(tree, item); } } /* *---------------------------------------------------------------------- * * Tree_HeaderHeight -- * * Return the total height of the column header area. The height * is only recalculated if it is marked out-of-date. * * Results: * Pixel height. Will be zero if there are no visible headers. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tree_HeaderHeight( TreeCtrl *tree /* Widget info. */ ) { TreeItem item = tree->headerItems; int totalHeight = 0; if (!tree->showHeader) return 0; if (tree->headerHeight >= 0) return tree->headerHeight; while (item != NULL) { totalHeight += TreeItem_Height(tree, item); item = TreeItem_GetNextSibling(tree, item); } return tree->headerHeight = totalHeight; } /* *---------------------------------------------------------------------- * * Tree_HeaderUnderPoint -- * * Returns the header containing the given coordinates. * * Results: * TreeItem or NULL if the point is outside any header. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem Tree_HeaderUnderPoint( TreeCtrl *tree, /* Widget info. */ int *x_, int *y_, /* In: window coordinates. * Out: coordinates relative to top-left * corner of the returned column. */ int *lock /* Returned COLUMN_LOCK_XXX. */ ) { int y; TreeItem item; if (Tree_HitTest(tree, *x_, *y_) != TREE_AREA_HEADER) return NULL; y = Tree_BorderTop(tree); item = tree->headerItems; if (!TreeItem_ReallyVisible(tree, item)) item = TreeItem_NextSiblingVisible(tree, item); while (item != NULL) { if (*y_ < y + TreeItem_Height(tree, item)) { /* Right-locked columns are drawn over left-locked ones. */ /* Left-locked columns are drawn over unlocked ones. */ if (*x_ >= Tree_ContentRight(tree)) { (*x_) -= Tree_ContentRight(tree); (*lock) = COLUMN_LOCK_RIGHT; } else if (*x_ < Tree_ContentLeft(tree)) { (*x_) -= Tree_BorderLeft(tree); (*lock) = COLUMN_LOCK_LEFT; } else { (*x_) += tree->xOrigin /*- tree->canvasPadX[PAD_TOP_LEFT]*/; (*lock) = COLUMN_LOCK_NONE; } (*y_) = (*y_) - y; return item; } y += TreeItem_Height(tree, item); item = TreeItem_NextSiblingVisible(tree, item); } return NULL; } /* *---------------------------------------------------------------------- * * TreeHeaderColumn_FromObj -- * * Parses a column description into a header-column token. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeHeaderColumn_FromObj( TreeHeader header, /* Header token. */ Tcl_Obj *objPtr, /* Object to parse to a column. */ TreeHeaderColumn *columnPtr /* Returned column. */ ) { TreeCtrl *tree = header->tree; TreeColumn treeColumn; TreeItemColumn itemColumn; if (TreeColumn_FromObj(tree, objPtr, &treeColumn, CFO_NOT_NULL) != TCL_OK) return TCL_ERROR; itemColumn = TreeItem_FindColumn(tree, header->item, TreeColumn_Index(treeColumn)); (*columnPtr) = TreeItemColumn_GetHeaderColumn(tree, itemColumn); return TCL_OK; } typedef struct Qualifiers { TreeCtrl *tree; int visible; /* 1 for -visible TRUE, 0 for -visible FALSE, -1 for unspecified. */ TagExpr expr; /* Tag expression. */ int exprOK; /* TRUE if expr is valid. */ Tk_Uid tag; /* Tag (without operators) or NULL. */ } Qualifiers; /* *---------------------------------------------------------------------- * * Qualifiers_Init -- * * Helper routine for TreeItem_FromObj. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Qualifiers_Init( TreeCtrl *tree, /* Widget info. */ Qualifiers *q /* Out: Initialized qualifiers. */ ) { q->tree = tree; q->visible = -1; q->exprOK = FALSE; q->tag = NULL; } /* *---------------------------------------------------------------------- * * Qualifiers_Scan -- * * Helper routine for TreeHeaderList_FromObj. * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Qualifiers_Scan( Qualifiers *q, /* Must call Qualifiers_Init first, * and Qualifiers_Free if result is TCL_OK. */ int objc, /* Number of arguments. */ Tcl_Obj **objv, /* Argument values. */ int startIndex, /* First objv[] index to look at. */ int *argsUsed /* Out: number of objv[] used. */ ) { TreeCtrl *tree = q->tree; Tcl_Interp *interp = tree->interp; int qual, j = startIndex; static CONST char *qualifiers[] = { "tag", "visible", "!visible", NULL }; enum qualEnum { QUAL_TAG, QUAL_VISIBLE, QUAL_NOT_VISIBLE }; /* Number of arguments used by qualifiers[]. */ static int qualArgs[] = { 2, 1, 1 }; *argsUsed = 0; for (; j < objc; ) { if (Tcl_GetIndexFromObj(NULL, objv[j], qualifiers, NULL, 0, &qual) != TCL_OK) break; if (objc - j < qualArgs[qual]) { Tcl_AppendResult(interp, "missing arguments to \"", Tcl_GetString(objv[j]), "\" qualifier", NULL); goto errorExit; } switch ((enum qualEnum) qual) { case QUAL_TAG: { if (tree->columnTagExpr) { if (q->exprOK) TagExpr_Free(&q->expr); if (TagExpr_Init(tree, objv[j + 1], &q->expr) != TCL_OK) return TCL_ERROR; q->exprOK = TRUE; } else { q->tag = Tk_GetUid(Tcl_GetString(objv[j + 1])); } break; } case QUAL_VISIBLE: { q->visible = 1; break; } case QUAL_NOT_VISIBLE: { q->visible = 0; break; } } *argsUsed += qualArgs[qual]; j += qualArgs[qual]; } return TCL_OK; errorExit: if (q->exprOK) TagExpr_Free(&q->expr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Qualifies -- * * Helper routine for TreeHeaderList_FromObj. * * Results: * Returns TRUE if the header meets the given criteria. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Qualifies( Qualifiers *q, /* Qualifiers to check. */ TreeItem header /* The header to test. May be NULL. */ ) { TreeCtrl *tree = q->tree; /* Note: if the header is NULL it is a "match" because we have run * out of headers to check. */ if (header == NULL) return 1; if ((q->visible == 1) && !TreeItem_ReallyVisible(tree, header)) return 0; else if ((q->visible == 0) && TreeItem_ReallyVisible(tree, header)) return 0; if (q->exprOK && !TagExpr_Eval(&q->expr, TreeItem_GetTagInfo(tree, header))) return 0; if ((q->tag != NULL) && !TreeItem_HasTag(header, q->tag)) return 0; return 1; } /* *---------------------------------------------------------------------- * * Qualifiers_Free -- * * Helper routine for TreeHeaderList_FromObj. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Qualifiers_Free( Qualifiers *q /* Out: Initialized qualifiers. */ ) { if (q->exprOK) TagExpr_Free(&q->expr); } /* *---------------------------------------------------------------------- * * TreeHeaderList_FromObj -- * * Parses a header description into a list of zero or more header * tokens. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeHeaderList_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *objPtr, /* Object to parse to a header. */ TreeItemList *items, /* Uninitialized item list. Caller must free * it with TreeItemList_Free unless the * result of this function is TCL_ERROR. */ int flags /* IFO_xxx flags */ ) { Tcl_Interp *interp = tree->interp; static CONST char *indexName[] = { "all", "end", "first", "last", (char *) NULL }; enum indexEnum { INDEX_ALL, INDEX_END, INDEX_FIRST, INDEX_LAST }; /* Number of arguments used by indexName[]. */ static int indexArgs[] = { 1, 1, 1, 1 }; /* Boolean: can indexName[] be followed by 1 or more qualifiers. */ static int indexQual[] = { 1, 1, 1, 1 }; int id, index, listIndex, objc; Tcl_Obj **objv, *elemPtr; TreeItem item = NULL; Qualifiers q; int qualArgsTotal; TreeItemList_Init(tree, items, 0); Qualifiers_Init(tree, &q); if (Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK) goto baditem; if (objc == 0) goto baditem; listIndex = 0; elemPtr = objv[listIndex]; if (Tcl_GetIndexFromObj(NULL, elemPtr, indexName, NULL, 0, &index) == TCL_OK) { if (objc - listIndex < indexArgs[index]) { Tcl_AppendResult(interp, "missing arguments to \"", Tcl_GetString(elemPtr), "\" keyword", NULL); goto errorExit; } qualArgsTotal = 0; if (indexQual[index]) { if (Qualifiers_Scan(&q, objc, objv, listIndex + indexArgs[index], &qualArgsTotal) != TCL_OK) { goto errorExit; } } switch ((enum indexEnum) index) { case INDEX_ALL: { item = tree->headerItems; while (item != NULL) { if (!qualArgsTotal || Qualifies(&q, item)) { TreeItemList_Append(items, item); } item = TreeItem_GetNextSibling(tree, item); } item = NULL; break; } case INDEX_FIRST: { item = tree->headerItems; while (!Qualifies(&q, item)) item = TreeItem_GetNextSibling(tree, item); break; } case INDEX_END: case INDEX_LAST: { TreeItem walk = tree->headerItems; while (walk != NULL) { if (Qualifies(&q, walk)) item = walk; walk = TreeItem_GetNextSibling(tree, walk); } break; } } listIndex += indexArgs[index] + qualArgsTotal; /* No indexName[] was found. */ } else { int gotId = FALSE; /* Try an item ID. */ if (Tcl_GetIntFromObj(NULL, elemPtr, &id) == TCL_OK) gotId = TRUE; if (gotId) { item = tree->headerItems; while (item != NULL) { if (TreeItem_GetID(tree, item) == id) break; item = TreeItem_GetNextSibling(tree, item); } goto gotFirstPart; } /* Try a list of qualifiers. This has the same effect as * "all QUALIFIERS". */ if (Qualifiers_Scan(&q, objc, objv, listIndex, &qualArgsTotal) != TCL_OK) { goto errorExit; } if (qualArgsTotal) { item = tree->headerItems; while (item != NULL) { if (Qualifies(&q, item)) { TreeItemList_Append(items, item); } item = TreeItem_GetNextSibling(tree, item); } item = NULL; listIndex += qualArgsTotal; goto gotFirstPart; } /* Try a tag or tag expression followed by qualifiers. */ if (objc > 1) { if (Qualifiers_Scan(&q, objc, objv, listIndex + 1, &qualArgsTotal) != TCL_OK) { goto errorExit; } } if (tree->itemTagExpr) { /* FIXME: headerTagExpr */ TagExpr expr; if (TagExpr_Init(tree, elemPtr, &expr) != TCL_OK) goto errorExit; item = tree->headerItems; while (item != NULL) { if (TagExpr_Eval(&expr, TreeItem_GetTagInfo(tree, item)) && Qualifies(&q, item)) { TreeItemList_Append(items, item); } item = TreeItem_GetNextSibling(tree, item); } TagExpr_Free(&expr); } else { Tk_Uid tag = Tk_GetUid(Tcl_GetString(elemPtr)); item = tree->headerItems; while (item != NULL) { if (TreeItem_HasTag(item, tag) && Qualifies(&q, item)) { TreeItemList_Append(items, item); } item = TreeItem_GetNextSibling(tree, item); } } item = NULL; listIndex += 1 + qualArgsTotal; } gotFirstPart: /* This means a valid specification was given, but there is no such item */ if ((TreeItemList_Count(items) == 0) && (item == NULL)) { if (flags & IFO_NOT_NULL) goto noitem; /* Empty list returned */ goto goodExit; } if ((flags & IFO_NOT_MANY) && (TreeItemList_Count(items) > 1)) { FormatResult(interp, "can't specify > 1 header for this command"); goto errorExit; } if (item != NULL) TreeItemList_Append(items, item); goodExit: Qualifiers_Free(&q); return TCL_OK; baditem: Tcl_AppendResult(interp, "bad header description \"", Tcl_GetString(objPtr), "\"", NULL); goto errorExit; noitem: Tcl_AppendResult(interp, "header \"", Tcl_GetString(objPtr), "\" doesn't exist", NULL); errorExit: Qualifiers_Free(&q); TreeItemList_Free(items); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeHeader_FromObj -- * * Parses a header description into a single header token. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeHeader_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *objPtr, /* Object to parse to a header. */ TreeHeader *headerPtr /* Out: returned header, always non-NULL * unless an error occurs. */ ) { TreeItemList items; TreeItem item; if (TreeHeaderList_FromObj(tree, objPtr, &items, IFO_NOT_MANY | IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; item = TreeItemList_Nth(&items, 0); (*headerPtr) = TreeItem_GetHeader(tree, item); TreeItemList_Free(&items); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeHeader_GetItem -- * * Get the underlying item for a header. * * Results: * The TreeItem that is the back-end of a header. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeHeader_GetItem( TreeHeader header /* Header token. */ ) { return header->item; } /* *---------------------------------------------------------------------- * * TreeHeader_ToObj -- * * Convert a TreeHeader to a Tcl_Obj. * * Results: * A new Tcl_Obj representing the TreeHeader. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeHeader_ToObj( TreeHeader header /* Header token. */ ) { TreeCtrl *tree = header->tree; #if 0 if (tree->itemPrefixLen) { char buf[100 + TCL_INTEGER_SPACE]; (void) sprintf(buf, "%s%d", tree->itemPrefix, item->id); return Tcl_NewStringObj(buf, -1); } #endif return Tcl_NewIntObj(TreeItem_GetID(tree, header->item)); } /* *---------------------------------------------------------------------- * * TreeHeaderCmd_Create -- * * This procedure is invoked to process the [header create] widget * command. See the user documentation for details on what it * does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int TreeHeaderCmd_Create( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; TreeItem item; TreeHeader header; item = TreeItem_CreateHeader(tree); header = TreeItem_GetHeader(tree, item); if (Header_Configure(header, objc - 3, objv + 3, TRUE) != TCL_OK) { TreeItem_Delete(tree, item); return TCL_ERROR; } tree->headerHeight = -1; Tree_DInfoChanged(tree, DINFO_DRAW_HEADER); Tcl_SetObjResult(interp, TreeItem_ToObj(tree, item)); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeHeaderCmd_Cget -- * * This procedure is invoked to process the [header cget] widget * command. See the user documentation for details on what it * does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int TreeHeaderCmd_Cget( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; TreeHeader header; TreeHeaderColumn column; Tcl_Obj *resultObjPtr; if (objc < 5 || objc > 6) { Tcl_WrongNumArgs(interp, 3, objv, "header ?column? option"); return TCL_ERROR; } if (TreeHeader_FromObj(tree, objv[3], &header) != TCL_OK) return TCL_ERROR; /* T header cget H option */ if (objc == 5) { { Tk_OptionSpec *specPtr = headerSpecs; int length; CONST char *optionName = Tcl_GetStringFromObj(objv[4], &length); while (specPtr->type != TK_OPTION_END) { if (strncmp(specPtr->optionName, optionName, length) == 0) { break; } specPtr++; } if (specPtr->type == TK_OPTION_END) { return TreeItem_ConsumeHeaderCget(tree, header->item, objv[4]); } } resultObjPtr = Tk_GetOptionValue(interp, (char *) header, tree->headerOptionTable, objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); } else { /* T header cget H C option */ if (TreeHeaderColumn_FromObj(header, objv[4], &column) != TCL_OK) return TCL_ERROR; resultObjPtr = Tk_GetOptionValue(interp, (char *) column, tree->headerColumnOptionTable, objv[5], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeHeaderCmd_Configure -- * * This procedure is invoked to process the [header configure] * widget command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int TreeHeaderCmd_Configure( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; TreeHeader header; TreeHeaderColumn column; Tcl_Obj *resultObjPtr; CONST char *s; TreeItem item; TreeItemList items; ItemForEach iter; TreeColumnList columns; TreeColumn treeColumn; ColumnForEach citer; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "header ?column? ?option? ?value? ?option value ...?"); return TCL_ERROR; } /* T header configure H */ if (objc == 4) { if (TreeHeader_FromObj(tree, objv[3], &header) != TCL_OK) return TCL_ERROR; /* Return the combined [header configure] and [item configure] */ resultObjPtr = Tk_GetOptionInfo(interp, (char *) header, tree->headerOptionTable,(Tcl_Obj *) NULL, tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; if (TreeItem_GetHeaderOptionInfo(tree, header, NULL, resultObjPtr) != TCL_OK) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); return TCL_OK; } s = Tcl_GetString(objv[4]); if (s[0] == '-') { /* T header configure H -option */ if (objc == 5) { if (TreeHeader_FromObj(tree, objv[3], &header) != TCL_OK) return TCL_ERROR; if (TreeItem_GetHeaderOptionInfo(tree, header, objv[4], NULL) == TCL_OK) return TCL_OK; Tcl_ResetResult(interp); resultObjPtr = Tk_GetOptionInfo(interp, (char *) header, tree->headerOptionTable, objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); /* T header configure H -option value ... */ } else { if (TreeHeaderList_FromObj(tree, objv[3], &items, 0) != TCL_OK) return TCL_ERROR; ITEM_FOR_EACH(item, &items, NULL, &iter) { header = TreeItem_GetHeader(tree, item); if (Header_Configure(header, objc - 4, objv + 4, FALSE) != TCL_OK) { TreeItemList_Free(&items); return TCL_ERROR; } } TreeItemList_Free(&items); } return TCL_OK; } /* T header configure H C ?-option? */ if (objc <= 6) { if (TreeHeader_FromObj(tree, objv[3], &header) != TCL_OK) return TCL_ERROR; if (TreeHeaderColumn_FromObj(header, objv[4], &column) != TCL_OK) return TCL_ERROR; resultObjPtr = Tk_GetOptionInfo(interp, (char *) column, tree->headerColumnOptionTable, (objc == 5) ? (Tcl_Obj *) NULL : objv[5], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); /* T header configure H C -option value ... */ } else { if (TreeHeaderList_FromObj(tree, objv[3], &items, 0) != TCL_OK) return TCL_ERROR; if (TreeColumnList_FromObj(tree, objv[4], &columns, 0) != TCL_OK) { TreeItemList_Free(&items); return TCL_ERROR; } ITEM_FOR_EACH(item, &items, NULL, &iter) { header = TreeItem_GetHeader(tree, item); COLUMN_FOR_EACH(treeColumn, &columns, NULL, &citer) { TreeItemColumn itemColumn = TreeItem_FindColumn(tree, item, TreeColumn_Index(treeColumn)); column = TreeItemColumn_GetHeaderColumn(tree, itemColumn); if (Column_Configure(header, column, treeColumn, objc - 5, objv + 5, FALSE) != TCL_OK) { TreeItemList_Free(&items); TreeColumnList_Free(&columns); return TCL_ERROR; } } } TreeItemList_Free(&items); TreeColumnList_Free(&columns); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeHeaderCmd -- * * This procedure is invoked to process the [header] widget * command. See the user documentation for details on what it * does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeHeaderCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; static CONST char *commandNames[] = { "bbox", "cget", "compare", "configure", "count", "create", "delete", "dragcget", "dragconfigure", "element", "id", "image", "span", "state", "style", "tag", "text", (char *) NULL }; enum { COMMAND_BBOX, COMMAND_CGET, COMMAND_COMPARE, COMMAND_CONFIGURE, COMMAND_COUNT, COMMAND_CREATE, COMMAND_DELETE, COMMAND_DRAGCGET, COMMAND_DRAGCONF, COMMAND_ELEMENT, COMMAND_ID, COMMAND_IMAGE, COMMAND_SPAN, COMMAND_STATE, COMMAND_STYLE, COMMAND_TAG, COMMAND_TEXT }; int index; TreeHeader header; TreeItemList items; TreeItem item; ItemForEach iter; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } /* FIXME: Tree_PreserveItems? */ switch (index) { /* T header bbox I ?C? ?E? */ case COMMAND_BBOX: return TreeItemCmd_Bbox(tree, objc, objv, TRUE); case COMMAND_CREATE: return TreeHeaderCmd_Create(clientData, interp, objc, objv); /* T header cget H ?C? option */ case COMMAND_CGET: return TreeHeaderCmd_Cget(clientData, interp, objc, objv); /* T header compare H op H */ case COMMAND_COMPARE: { static CONST char *opName[] = { "<", "<=", "==", ">=", ">", "!=", NULL }; enum { COP_LT, COP_LE, COP_EQ, COP_GE, COP_GT, COP_NE }; int op, compare = 0, index1 = 0, index2 = 0; TreeHeader header1, header2; if (objc != 6) { Tcl_WrongNumArgs(interp, 3, objv, "header1 op header2"); return TCL_ERROR; } if (TreeHeader_FromObj(tree, objv[3], &header1) != TCL_OK) return TCL_ERROR; if (Tcl_GetIndexFromObj(interp, objv[4], opName, "comparison operator", 0, &op) != TCL_OK) { return TCL_ERROR; } if (TreeHeader_FromObj(tree, objv[5], &header2) != TCL_OK) return TCL_ERROR; if (op != COP_EQ && op != COP_NE) { for (item = tree->headerItems; item != header1->item; item = TreeItem_GetNextSibling(tree, item)) { index1++; } for (item = tree->headerItems; item != header2->item; item = TreeItem_GetNextSibling(tree, item)) { index2++; } } switch (op) { case COP_LT: compare = index1 < index2; break; case COP_LE: compare = index1 <= index2; break; case COP_EQ: compare = header1 == header2; break; case COP_GE: compare = index1 >= index2; break; case COP_GT: compare = index1 > index2; break; case COP_NE: compare = header1 != header2; break; } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(compare)); break; } /* T header configure H ?C? ?option? ?value? ?option value ...? */ case COMMAND_CONFIGURE: return TreeHeaderCmd_Configure(clientData, interp, objc, objv); /* T header count ?H? */ case COMMAND_COUNT: { int count = tree->headerCount; if (objc > 4) { Tcl_WrongNumArgs(interp, 3, objv, "?headerDesc?"); return TCL_ERROR; } if (objc == 4) { if (TreeHeaderList_FromObj(tree, objv[3], &items, 0) != TCL_OK) return TCL_ERROR; count = 0; ITEM_FOR_EACH(item, &items, NULL, &iter) { count++; } TreeItemList_Free(&items); } Tcl_SetObjResult(interp, Tcl_NewIntObj(count)); break; } case COMMAND_DELETE: { if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "header"); return TCL_ERROR; } if (TreeHeaderList_FromObj(tree, objv[3], &items, 0) != TCL_OK) return TCL_ERROR; ITEM_FOR_EACH(item, &items, NULL, &iter) { /* The default header can't be deleted */ if (item == tree->headerItems) continue; if (TreeItem_ReallyVisible(tree, item)) { TreeColumns_InvalidateWidth(tree); TreeColumns_InvalidateSpans(tree); /* TreeItem_Delete will call TreeItem_FreeResources which * will call Tree_FreeItemDInfo will will set tree->headerHeight=-1 * and set DINFO_DRAW_HEADER. */ } /* FIXME: ITEM_FLAG_DELETED */ TreeItem_Delete(tree, item); } TreeItemList_Free(&items); break; } /* T header dragcget ?header? option */ case COMMAND_DRAGCGET: { Tcl_Obj *resultObjPtr; if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 3, objv, "?header? option"); return TCL_ERROR; } if (objc == 5) { if (TreeHeader_FromObj(tree, objv[3], &header) != TCL_OK) return TCL_ERROR; resultObjPtr = Tk_GetOptionValue(interp, (char *) header, tree->headerDragOptionTable, objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } resultObjPtr = Tk_GetOptionValue(interp, (char *) tree, tree->columnDrag.optionTable, objv[3], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } /* T header dragconfigure ?header? ?option? ?value? ?option value ...? */ case COMMAND_DRAGCONF: { Tcl_Obj *resultObjPtr; Tk_SavedOptions savedOptions; int mask, result, flags = 0; CONST char *s; if (objc == 3) { resultObjPtr = Tk_GetOptionInfo(interp, (char *) tree, tree->columnDrag.optionTable, (Tcl_Obj *) NULL, tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } s = Tcl_GetString(objv[3]); if (s[0] == '-') { int alpha = tree->columnDrag.alpha; TreeColumn dragColumn = tree->columnDrag.column; if (objc <= 4) { resultObjPtr = Tk_GetOptionInfo(interp, (char *) tree, tree->columnDrag.optionTable, (objc == 3) ? (Tcl_Obj *) NULL : objv[3], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } result = Tk_SetOptions(interp, (char *) tree, tree->columnDrag.optionTable, objc - 3, objv + 3, tree->tkwin, &savedOptions, &mask); if (result != TCL_OK) { Tk_RestoreSavedOptions(&savedOptions); return TCL_ERROR; } Tk_FreeSavedOptions(&savedOptions); if (tree->columnDrag.alpha < 0) tree->columnDrag.alpha = 0; if (tree->columnDrag.alpha > 255) tree->columnDrag.alpha = 255; if (alpha != tree->columnDrag.alpha) tree->columnDrag.imageEpoch++; /* Free header drag images if -imagecolumn changes to "" */ if ((dragColumn != NULL) && (tree->columnDrag.column == NULL)) { FreeDragImages(tree); } for (item = tree->headerItems; item != NULL; item = TreeItem_GetNextSibling(tree, item)) { header = TreeItem_GetHeader(tree, item); if (header->columnDrag.draw) Tree_InvalidateItemDInfo(tree, NULL, item, NULL); } break; } if (objc < 6) flags |= IFO_NOT_MANY | IFO_NOT_NULL; if (TreeHeaderList_FromObj(tree, objv[3], &items, flags) != TCL_OK) return TCL_ERROR; if (objc <= 5) { item = TreeItemList_Nth(&items, 0); header = TreeItem_GetHeader(tree, item); resultObjPtr = Tk_GetOptionInfo(interp, (char *) header, tree->headerDragOptionTable, (objc == 4) ? (Tcl_Obj *) NULL : objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } ITEM_FOR_EACH(item, &items, NULL, &iter) { header = TreeItem_GetHeader(tree, item); result = Tk_SetOptions(interp, (char *) header, tree->headerDragOptionTable, objc - 4, objv + 4, tree->tkwin, &savedOptions, &mask); if (result != TCL_OK) { Tk_RestoreSavedOptions(&savedOptions); TreeItemList_Free(&items); return TCL_ERROR; } Tk_FreeSavedOptions(&savedOptions); Tree_InvalidateItemDInfo(tree, NULL, item, NULL); } /* Tree_DInfoChanged(tree, DINFO_DRAW_HEADER);*/ TreeItemList_Free(&items); break; } case COMMAND_ELEMENT: return TreeItemCmd_Element(tree, objc, objv, TRUE); /* T header id H */ case COMMAND_ID: { Tcl_Obj *listObj; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "header"); return TCL_ERROR; } if (TreeHeaderList_FromObj(tree, objv[3], &items, 0) != TCL_OK) return TCL_ERROR; listObj = Tcl_NewListObj(0, NULL); ITEM_FOR_EACH(item, &items, NULL, &iter) { Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, item)); } TreeItemList_Free(&items); Tcl_SetObjResult(interp, listObj); break; } case COMMAND_IMAGE: return TreeItemCmd_ImageOrText(tree, objc, objv, TRUE, TRUE); case COMMAND_SPAN: return TreeItemCmd_Span(tree, objc, objv, TRUE); case COMMAND_STATE: return TreeItemCmd_State(tree, objc, objv, TRUE); case COMMAND_STYLE: return TreeItemCmd_Style(tree, objc, objv, TRUE); case COMMAND_TAG: return TreeItemCmd_Tag(tree, objc, objv, TRUE); case COMMAND_TEXT: return TreeItemCmd_ImageOrText(tree, objc, objv, FALSE, TRUE); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeHeader_TreeChanged -- * * Called when a TreeCtrl is configured. Performs any relayout * necessary on column headers. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeHeader_TreeChanged( TreeCtrl *tree, /* Widget info. */ int flagT /* TREE_CONF_xxx flags. */ ) { if (!(flagT & (TREE_CONF_FONT | TREE_CONF_RELAYOUT))) return; tree->headerHeight = -1; } /* *---------------------------------------------------------------------- * * TreeHeader_InitWidget -- * * Perform header-related initialization when a new TreeCtrl is * created. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeHeader_InitWidget( TreeCtrl *tree /* Widget info. */ ) { Tk_OptionSpec *specPtr; Tcl_DString dString; Tcl_InitHashTable(&tree->headerHash, TCL_ONE_WORD_KEYS); specPtr = Tree_FindOptionSpec(columnSpecs, "-background"); if (specPtr->defValue == NULL) { Tcl_DStringInit(&dString); Tcl_DStringAppendElement(&dString, DEF_BUTTON_BG_COLOR); Tcl_DStringAppendElement(&dString, "normal"); Tcl_DStringAppendElement(&dString, DEF_BUTTON_ACTIVE_BG_COLOR); Tcl_DStringAppendElement(&dString, ""); specPtr->defValue = ckalloc(Tcl_DStringLength(&dString) + 1); strcpy((char *)specPtr->defValue, Tcl_DStringValue(&dString)); Tcl_DStringFree(&dString); } PerStateCO_Init(columnSpecs, "-arrowbitmap", &pstBitmap, TreeStateFromObj); PerStateCO_Init(columnSpecs, "-arrowimage", &pstImage, TreeStateFromObj); PerStateCO_Init(columnSpecs, "-background", &pstBorder, TreeStateFromObj); PerStateCO_Init(columnSpecs, "-textcolor", &pstColor, TreeStateFromObj); tree->headerOptionTable = Tk_CreateOptionTable(tree->interp, headerSpecs); tree->headerColumnOptionTable = Tk_CreateOptionTable(tree->interp, columnSpecs); tree->headerDragOptionTable = Tk_CreateOptionTable(tree->interp, dragSpecs); tree->tailExtend = 20; /* Create the default/topmost header item. It can't be deleted. */ tree->headerItems = TreeItem_CreateHeader(tree); /* Create the style for the tail column. */ TreeHeaderColumn_EnsureStyleExists(TreeItem_GetHeader(tree, tree->headerItems), TreeItemColumn_GetHeaderColumn(tree, TreeItem_GetFirstColumn(tree, tree->headerItems)), tree->columnTail); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeHeader_FreeWidget -- * * Free header-related resources for a deleted TreeCtrl. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ void TreeHeader_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { TreeItem item; item = tree->headerItems; while (item != NULL) { TreeItem_FreeResources(tree, item); item = TreeItem_GetNextSibling(tree, item); } Tcl_DeleteHashTable(&tree->headerHash); } tktreectrl-2.4.1/generic/tkTreeItem.c0000644000076400010400000101723111645410215020054 0ustar TimAdministrators/* * tkTreeItem.c -- * * This module implements items for treectrl widgets. * * Copyright (c) 2002-2011 Tim Baker */ #include "tkTreeCtrl.h" typedef struct TreeItem_ TreeItem_; typedef struct TreeItemColumn_ TreeItemColumn_; /* * A data structure of the following type is kept for a single column in a * single item. */ struct TreeItemColumn_ { int cstate; /* STATE_xxx flags manipulated with the * [item state forcolumn] command */ int span; /* Number of tree-columns this column covers */ TreeStyle style; /* Instance style. */ TreeHeaderColumn headerColumn; /* The header-column if the parent item * is actually a header, otherwise NULL. */ TreeItemColumn next;/* Column to the right of this one */ }; /* * A data structure of the following type is kept for each item. */ struct TreeItem_ { int id; /* unique id */ int depth; /* tree depth (-1 for the unique root item) */ int fixedHeight; /* -height: desired height of this item (0 for * no-such-value) */ int numChildren; int index; /* "row" in flattened tree */ int indexVis; /* visible "row" in flattened tree, -1 if hidden */ int state; /* STATE_xxx flags */ TreeItem parent; TreeItem firstChild; TreeItem lastChild; TreeItem prevSibling; TreeItem nextSibling; TreeItemDInfo dInfo; /* display info, or NULL */ TreeItemRInfo rInfo; /* range info, or NULL */ TreeItemColumn columns; int *spans; /* 1 per tree-column. spans[N] is the column index of * the item-column displayed in column N. If this * item's columns all have a span of 1, this field * is NULL (unless it was previously allocated * because some spans were > 1). */ int spanAlloc; /* Size of spans[]. */ #define ITEM_FLAG_DELETED 0x0001 /* Item is being deleted */ #define ITEM_FLAG_SPANS_SIMPLE 0x0002 /* All spans are 1 */ #define ITEM_FLAG_SPANS_VALID 0x0004 /* Some spans are > 1, but we don't * need to redo them. Also indicates * we have an entry in * TreeCtrl.itemSpansHash. */ #define ITEM_FLAG_BUTTON 0x0008 /* -button true */ #define ITEM_FLAG_BUTTON_AUTO 0x0010 /* -button auto */ #define ITEM_FLAG_VISIBLE 0x0020 /* -visible */ #define ITEM_FLAG_WRAP 0x0040 /* -wrap */ #define ITEM_FLAG_BUTTONSTATE_ACTIVE 0x0080 /* buttonstate "active" */ #define ITEM_FLAG_BUTTONSTATE_PRESSED 0x0100 /* buttonstate "pressed" */ int flags; TagInfo *tagInfo; /* Tags. May be NULL. */ TreeHeader header; /* The header or NULL */ }; #define ITEM_FLAGS_BUTTONSTATE (ITEM_FLAG_BUTTONSTATE_ACTIVE | \ ITEM_FLAG_BUTTONSTATE_PRESSED) static CONST char *ItemUid = "Item", *ItemColumnUid = "ItemColumn"; /* * Macro to test whether an item is the unique root item */ #define IS_ROOT(i) ((i)->depth == -1) #define IS_ALL(i) ((i) == ITEM_ALL) #define IS_DELETED(i) (((i)->flags & ITEM_FLAG_DELETED) != 0) #define IS_VISIBLE(i) (((i)->flags & ITEM_FLAG_VISIBLE) != 0) #define IS_WRAP(i) (((i)->flags & ITEM_FLAG_WRAP) != 0) /* * Flags returned by Tk_SetOptions() (see itemOptionSpecs below). */ #define ITEM_CONF_BUTTON 0x0001 #define ITEM_CONF_SIZE 0x0002 #define ITEM_CONF_VISIBLE 0x0004 #define ITEM_CONF_WRAP 0x0008 /* * Information used for Item objv parsing. */ static Tk_OptionSpec itemOptionSpecs[] = { {TK_OPTION_CUSTOM, "-button", (char *) NULL, (char *) NULL, "0", -1, Tk_Offset(TreeItem_, flags), 0, (ClientData) NULL, ITEM_CONF_BUTTON}, {TK_OPTION_PIXELS, "-height", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeItem_, fixedHeight), TK_OPTION_NULL_OK, (ClientData) NULL, ITEM_CONF_SIZE}, {TK_OPTION_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(TreeItem_, tagInfo), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_tagInfo, 0}, {TK_OPTION_CUSTOM, "-visible", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeItem_, flags), 0, (ClientData) NULL, ITEM_CONF_VISIBLE}, {TK_OPTION_CUSTOM, "-wrap", (char *) NULL, (char *) NULL, "0", -1, Tk_Offset(TreeItem_, flags), 0, (ClientData) NULL, ITEM_CONF_WRAP}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, 0, 0} }; /* *---------------------------------------------------------------------- * * Column_Alloc -- * * Allocate and initialize a new Column record. * * Results: * Pointer to allocated Column. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ static TreeItemColumn Column_Alloc( TreeCtrl *tree, /* Widget info. */ TreeItem item ) { #ifdef ALLOC_HAX TreeItemColumn column = (TreeItemColumn) TreeAlloc_Alloc(tree->allocData, ItemColumnUid, sizeof(TreeItemColumn_)); #else TreeItemColumn column = (TreeItemColumn) ckalloc(sizeof(TreeItemColumn_)); #endif memset(column, '\0', sizeof(TreeItemColumn_)); column->span = 1; if (item->header != NULL) { column->headerColumn = TreeHeaderColumn_CreateWithItemColumn( item->header, column); #if TREECTRL_DEBUG if (column->headerColumn == NULL) panic("TreeHeaderColumn_CreateWithItemColumn failed"); #endif column->cstate = STATE_HEADER_NORMAL; } return column; } /* *---------------------------------------------------------------------- * * TreeItemColumn_InvalidateSize -- * * Marks the needed height and width of the column as out-of-date. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItemColumn_InvalidateSize( TreeCtrl *tree, /* Widget info. */ TreeItemColumn column_ /* Column token. */ ) { } /* *---------------------------------------------------------------------- * * TreeItemColumn_NeededWidth -- * * Returns the requested width of a Column. * * Results: * If the Column has a style, the requested width of the style * is returned (a positive pixel value). Otherwise 0 is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItemColumn_NeededWidth( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ TreeItemColumn column /* Column token. */ ) { if (column->style != NULL) return TreeStyle_NeededWidth(tree, column->style, item->state | column->cstate); return 0; } /* *---------------------------------------------------------------------- * * TreeItems_RequestWidthInColumns -- * * Calculates the width needed by styles in a range of columns * for every visible item. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItems_RequestWidthInColumns( TreeCtrl *tree, /* Widget info. */ TreeColumn columnMin, TreeColumn columnMax ) { TreeItem item = tree->root; if (!TreeItem_ReallyVisible(tree, item)) item = TreeItem_NextVisible(tree, item); while (item != NULL) { TreeItem_RequestWidthInColumns(tree, item, columnMin, columnMax); item = TreeItem_NextVisible(tree, item); } } /* *---------------------------------------------------------------------- * * TreeItemColumn_GetStyle -- * * Returns the style assigned to a Column. * * Results: * Returns the style, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeStyle TreeItemColumn_GetStyle( TreeCtrl *tree, /* Widget info. */ TreeItemColumn column /* Column token. */ ) { return column->style; } /* *---------------------------------------------------------------------- * * TreeItemColumn_Index -- * * Return the 0-based index of a Column in an Item's linked list of * Columns. * * Results: * Integer index of the Column. * * Side effects: * Tcl_Panic() if the Column isn't found. * *---------------------------------------------------------------------- */ int TreeItemColumn_Index( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ TreeItemColumn column /* Column token. */ ) { TreeItemColumn walk; int i = 0; walk = item->columns; while ((walk != NULL) && (walk != column)) { i++; walk = walk->next; } if (walk == NULL) panic("TreeItemColumn_Index: couldn't find the column\n"); return i; } /* *---------------------------------------------------------------------- * * TreeItemColumn_ForgetStyle -- * * Free the style assigned to a Column. * * Results: * Column has no style assigned anymore. * * Side effects: * Memory is freed. * *---------------------------------------------------------------------- */ void TreeItemColumn_ForgetStyle( TreeCtrl *tree, /* Widget info. */ TreeItemColumn column /* Column token. */ ) { if (column->style != NULL) { TreeStyle_FreeResources(tree, column->style); column->style = NULL; } } /* *---------------------------------------------------------------------- * * TreeItemColumn_SetStyle -- * * Assign a style to a Column, freeing the old one if it exists. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItemColumn_SetStyle( TreeCtrl *tree, /* Widget info. */ TreeItemColumn column, /* Column token. */ TreeStyle style /* New instance style. */ ) { if (column->style != NULL) { TreeStyle_FreeResources(tree, column->style); } column->style = style; } /* *---------------------------------------------------------------------- * * TreeItemColumn_GetNext -- * * Return the Column to the right of this one. * * Results: * The next Column in the linked list, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItemColumn TreeItemColumn_GetNext( TreeCtrl *tree, /* Widget info. */ TreeItemColumn column /* Column token. */ ) { return column->next; } /* *---------------------------------------------------------------------- * * Column_FreeResources -- * * Free the style and memory associated with the given Column. * * Results: * The next Column in the linked list, or NULL. * * Side effects: * Memory is freed. * *---------------------------------------------------------------------- */ static TreeItemColumn Column_FreeResources( TreeCtrl *tree, /* Widget info. */ TreeItemColumn self /* Column to free. */ ) { TreeItemColumn next = self->next; if (self->style != NULL) TreeStyle_FreeResources(tree, self->style); if (self->headerColumn != NULL) TreeHeaderColumn_FreeResources(tree, self->headerColumn); #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, ItemColumnUid, (char *) self, sizeof(TreeItemColumn_)); #else WFREE(self, TreeItemColumn_); #endif return next; } /* *---------------------------------------------------------------------- * * Item_UpdateIndex -- * * Set the Item.depth, Item.index and Item.indexVis fields of the * given Item and all its descendants. * * Results: * None. * * Side effects: * The TreeCtrl.depth field may be updated to track the maximum * depth of all items. * *---------------------------------------------------------------------- */ static void Item_UpdateIndex(TreeCtrl *tree, TreeItem item, /* Item to update. */ int *index, /* New Item.index value for the item. * Value is incremented. */ int *indexVis /* New Item.indexVis value for the item if * the item is ReallyVisible(). * Value is incremented if the item is * ReallyVisible(). */ ) { TreeItem child, parent = item->parent; int parentVis, parentOpen; /* Also track max depth */ if (parent != NULL) item->depth = parent->depth + 1; else item->depth = 0; if (item->depth > tree->depth) tree->depth = item->depth; item->index = (*index)++; item->indexVis = -1; if (parent != NULL) { parentOpen = (parent->state & STATE_ITEM_OPEN) != 0; parentVis = parent->indexVis != -1; if (IS_ROOT(parent) && !tree->showRoot) { parentOpen = TRUE; parentVis = IS_VISIBLE(parent); } if (parentVis && parentOpen && IS_VISIBLE(item)) { item->indexVis = (*indexVis)++; if (IS_WRAP(item)) tree->itemWrapCount++; } } child = item->firstChild; while (child != NULL) { Item_UpdateIndex(tree, child, index, indexVis); child = child->nextSibling; } } /* *---------------------------------------------------------------------- * * Tree_UpdateItemIndex -- * * Set the Item.depth, Item.index and Item.indexVis fields of the * every Item. Set TreeCtrl.depth to the maximum depth of all * Items. Set TreeCtrl.itemVisCount to the count of all visible * items. * * Because this is slow we try not to do it until necessary. * The tree->updateIndex flags indicates when this is needed. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_UpdateItemIndex( TreeCtrl *tree /* Widget info. */ ) { TreeItem item = tree->root; int index = 1, indexVis = 0; if (!tree->updateIndex) return; if (tree->debug.enable && tree->debug.data) dbwin("Tree_UpdateItemIndex %s\n", Tk_PathName(tree->tkwin)); /* Also track max depth */ tree->depth = -1; /* Count visible items with -wrap=true */ tree->itemWrapCount = 0; item->index = 0; item->indexVis = -1; if (tree->showRoot && IS_VISIBLE(item)) { item->indexVis = indexVis++; if (IS_WRAP(item)) tree->itemWrapCount++; } item = item->firstChild; while (item != NULL) { Item_UpdateIndex(tree, item, &index, &indexVis); item = item->nextSibling; } tree->itemVisCount = indexVis; tree->updateIndex = 0; } /* *---------------------------------------------------------------------- * * Item_Alloc -- * * Allocate an initialize a new Item record. * * Results: * Pointer to the allocated Item record. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ static TreeItem Item_Alloc( TreeCtrl *tree, /* Widget info. */ int isHeader ) { #ifdef ALLOC_HAX TreeItem item = (TreeItem) TreeAlloc_Alloc(tree->allocData, ItemUid, sizeof(TreeItem_)); #else TreeItem item = (TreeItem) ckalloc(sizeof(TreeItem_)); #endif memset(item, '\0', sizeof(TreeItem_)); if (Tk_InitOptions(tree->interp, (char *) item, tree->itemOptionTable, tree->tkwin) != TCL_OK) panic("Tk_InitOptions() failed in Item_Alloc()"); if (isHeader) { if (tree->gotFocus) item->state |= STATE_HEADER_FOCUS; } else { item->state = STATE_ITEM_OPEN | STATE_ITEM_ENABLED; if (tree->gotFocus) item->state |= STATE_ITEM_FOCUS; } item->indexVis = -1; /* In the typical case all spans are 1. */ item->flags |= ITEM_FLAG_SPANS_SIMPLE; if (isHeader) Tree_AddHeader(tree, item); else Tree_AddItem(tree, item); return item; } /* *---------------------------------------------------------------------- * * Item_AllocRoot -- * * Allocate and initialize a new Item record for the root item. * * Results: * Pointer to the allocated Item record. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ static TreeItem Item_AllocRoot( TreeCtrl *tree /* Widget info. */ ) { TreeItem item; item = Item_Alloc(tree, FALSE); item->depth = -1; item->state |= STATE_ITEM_ACTIVE; return item; } /* *---------------------------------------------------------------------- * * TreeItem_GetFirstColumn -- * * Return the first Column record for an Item. * * Results: * Token for the column, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItemColumn TreeItem_GetFirstColumn( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return item->columns; } /* *---------------------------------------------------------------------- * * TreeItem_GetState -- * * Return the state flags for an Item. * * Results: * Bit mask of STATE_xxx flags. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_GetState( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return item->state; } /* *---------------------------------------------------------------------- * * TreeItemColumn_GetState -- * * Return the state flags for an item-column. * * Results: * Bit mask of STATE_xxx flags. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItemColumn_GetState( TreeCtrl *tree, /* Widget info. */ TreeItemColumn column /* Column token. */ ) { return column->cstate; } /* *---------------------------------------------------------------------- * * TreeItemColumn_ChangeState -- * * Toggles zero or more STATE_xxx flags for a Column. If the * Column has a style assigned, its state may be changed. * * Results: * Bit mask of CS_LAYOUT and CS_DISPLAY flags, or zero if no * changes occurred. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ int TreeItemColumn_ChangeState( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the column. */ TreeItemColumn column, /* Column to modify the state of. */ TreeColumn treeColumn, /* Tree column. */ int stateOff, /* STATE_xxx flags to turn off. */ int stateOn /* STATE_xxx flags to turn on. */ ) { int cstate, state; int sMask, iMask = 0; cstate = column->cstate; cstate &= ~stateOff; cstate |= stateOn; if (cstate == column->cstate) return 0; state = item->state | column->cstate; state &= ~stateOff; state |= stateOn; if (column->style != NULL) { sMask = TreeStyle_ChangeState(tree, column->style, item->state | column->cstate, state); if (sMask) { if ((sMask & CS_LAYOUT) /*&& (item->header == NULL)*/) TreeColumns_InvalidateWidthOfItems(tree, treeColumn); iMask |= sMask; } if (iMask & CS_LAYOUT) { TreeItem_InvalidateHeight(tree, item); TreeItemColumn_InvalidateSize(tree, column); Tree_FreeItemDInfo(tree, item, NULL); if (item->header == NULL) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); } else if (iMask & CS_DISPLAY) { Tree_InvalidateItemDInfo(tree, treeColumn, item, NULL); } } if ((iMask & CS_LAYOUT) /*&& (item->header != NULL)*/) TreeColumns_InvalidateWidth(tree); column->cstate = cstate; return iMask; } /* *---------------------------------------------------------------------- * * TreeItem_ChangeState -- * * Toggles zero or more STATE_xxx flags for an Item. If the * Column has a style assigned, its state may be changed. * * Results: * Bit mask of CS_LAYOUT and CS_DISPLAY flags, or zero if no * changes occurred. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ int TreeItem_ChangeState( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int stateOff, /* STATE_xxx flags to turn off. */ int stateOn /* STATE_xxx flags to turn on. */ ) { TreeItemColumn column; TreeColumn treeColumn; int columnIndex = 0, state, cstate; int sMask, iMask = 0; int tailOK = item->header != NULL; state = item->state; state &= ~stateOff; state |= stateOn; if (state == item->state) return 0; treeColumn = Tree_FirstColumn(tree, -1, tailOK); column = item->columns; while (column != NULL) { if (column->style != NULL) { cstate = item->state | column->cstate; cstate &= ~stateOff; cstate |= stateOn; sMask = TreeStyle_ChangeState(tree, column->style, item->state | column->cstate, cstate); if (sMask) { if (sMask & CS_LAYOUT) { TreeColumns_InvalidateWidthOfItems(tree, treeColumn); TreeItemColumn_InvalidateSize(tree, column); } else if (sMask & CS_DISPLAY) { Tree_InvalidateItemDInfo(tree, treeColumn, item, NULL); } iMask |= sMask; } } columnIndex++; column = column->next; treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK); } /* This item has a button */ if (TreeItem_HasButton(tree, item)) { Tk_Image image1, image2; Pixmap bitmap1, bitmap2; /* NOTE: These next 2 lines must have 'static' to work around a * Microsoft compiler optimization bug. */ static int butOpen, butClosed; static int themeOpen, themeClosed; int w1, h1, w2, h2; void *ptr1 = NULL, *ptr2 = NULL; /* * Compare the image/bitmap/theme/xlib button for the old state * to the image/bitmap/theme/xlib button for the new state. Figure * out if the size or appearance has changed. */ /* image > bitmap > theme > draw */ image1 = PerStateImage_ForState(tree, &tree->buttonImage, item->state, NULL); if (image1 != NULL) { Tk_SizeOfImage(image1, &w1, &h1); ptr1 = image1; } if (ptr1 == NULL) { bitmap1 = PerStateBitmap_ForState(tree, &tree->buttonBitmap, item->state, NULL); if (bitmap1 != None) { Tk_SizeOfBitmap(tree->display, bitmap1, &w1, &h1); ptr1 = (void *) bitmap1; } } if (ptr1 == NULL) { if (tree->useTheme && TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin), (item->state & STATE_ITEM_OPEN) != 0, &w1, &h1) == TCL_OK) { ptr1 = (item->state & STATE_ITEM_OPEN) ? &themeOpen : &themeClosed; } } if (ptr1 == NULL) { w1 = h1 = tree->buttonSize; ptr1 = (item->state & STATE_ITEM_OPEN) ? &butOpen : &butClosed; } /* image > bitmap > theme > draw */ image2 = PerStateImage_ForState(tree, &tree->buttonImage, state, NULL); if (image2 != NULL) { Tk_SizeOfImage(image2, &w2, &h2); ptr2 = image2; } if (ptr2 == NULL) { bitmap2 = PerStateBitmap_ForState(tree, &tree->buttonBitmap, state, NULL); if (bitmap2 != None) { Tk_SizeOfBitmap(tree->display, bitmap2, &w2, &h2); ptr2 = (void *) bitmap2; } } if (ptr2 == NULL) { if (tree->useTheme && TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin), (state & STATE_ITEM_OPEN) != 0, &w2, &h2) == TCL_OK) { ptr2 = (state & STATE_ITEM_OPEN) ? &themeOpen : &themeClosed; } } if (ptr2 == NULL) { w2 = h2 = tree->buttonSize; ptr2 = (state & STATE_ITEM_OPEN) ? &butOpen : &butClosed; } if ((w1 != w2) || (h1 != h2)) { iMask |= CS_LAYOUT | CS_DISPLAY; } else if (ptr1 != ptr2) { iMask |= CS_DISPLAY; if (tree->columnTree != NULL) Tree_InvalidateItemDInfo(tree, tree->columnTree, item, NULL); } } if (iMask & CS_LAYOUT) { TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); if (item->header == NULL) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); else TreeColumns_InvalidateWidth(tree); } item->state = state; return iMask; } /* *---------------------------------------------------------------------- * * TreeItem_UndefineState -- * * Clear a STATE_xxx flag in an Item and its Columns. This is * called when a user-defined state is undefined via the * [state undefine] widget command. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_UndefineState( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int state /* STATE_xxx flag that is undefined. */ ) { TreeItemColumn column = item->columns; while (column != NULL) { column->cstate &= ~state; column = column->next; } item->state &= ~state; } /* *---------------------------------------------------------------------- * * TreeItem_HasButton -- * * Determine whether an item should have a button displayed next to * it. This considers the value of the item option -button as well * as the treectrl options -showbuttons, -showrootchildbuttons and * -showrootbutton. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_HasButton( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { if (!tree->showButtons || (IS_ROOT(item) && !tree->showRootButton)) return 0; if (item->parent == tree->root && !tree->showRootChildButtons) return 0; if (item->flags & ITEM_FLAG_BUTTON) return 1; if (item->flags & ITEM_FLAG_BUTTON_AUTO) { TreeItem child = item->firstChild; while (child != NULL) { if (IS_VISIBLE(child)) return 1; child = child->nextSibling; } } return 0; } /* *---------------------------------------------------------------------- * * TreeItem_GetButtonBbox -- * * Determine the bounding box of the expand/collapse button * next to an item. * * Results: * If the -treecolumn is not visible, or the item is not visible, * or the item has no button, or the bounding box for the item * in the -treecolumn has zero size, then 0 is returned. * * Otherwise, the bounding box of the biggest possible button * (considering -buttonbitmap, -buttonimage, -buttonsize and * any themed button) is returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_GetButtonBbox( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ TreeRectangle *tr /* Returned bounds of the button in * item coordinates. */ ) { TreeItemColumn itemColumn; TreeStyle style = NULL; int indent, buttonY = -1; if (!tree->columnTreeVis) return 0; if (!TreeItem_HasButton(tree, item)) return 0; /* Get the bounding box in canvas coords of the tree-column for this * item. */ if (TreeItem_GetRects(tree, item, tree->columnTree, 0, NULL, tr) == 0) return 0; itemColumn = TreeItem_FindColumn(tree, item, TreeColumn_Index(tree->columnTree)); if (itemColumn != NULL) style = TreeItemColumn_GetStyle(tree, itemColumn); indent = TreeItem_Indent(tree, tree->columnTree, item); if (style != NULL) buttonY = TreeStyle_GetButtonY(tree, style); /* FIXME? The button is as wide as the -indent option. */ tr->x = indent - tree->useIndent; tr->width = tree->useIndent; if (buttonY < 0) tr->y = (tr->height - tree->buttonHeightMax) / 2; else tr->y = buttonY; tr->height = tree->buttonHeightMax; return 1; } /* *---------------------------------------------------------------------- * * TreeItem_IsPointInButton -- * * Determine if the given point is over the expand/collapse * button next to an item. * * Results: * 1 if the point is over the button, 0 otherwise. * * For the purposes of hit-testing, the button is considered to * be larger than what is displayed to make it easier to click. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_IsPointInButton( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int x, /* Item coords. */ int y /* Item coords. */ ) { TreeRectangle tr; #define BUTTON_HITTEST_SLOP 11 int centerY, slop = MAX(tree->buttonHeightMax / 2, BUTTON_HITTEST_SLOP); if (!TreeItem_GetButtonBbox(tree, item, &tr)) return 0; centerY = TreeRect_Top(tr) + TreeRect_Height(tr) / 2; if ((y < centerY - slop) || (y >= centerY + slop + (tree->buttonHeightMax % 2))) return 0; return 1; } /* *---------------------------------------------------------------------- * * TreeItem_GetDepth -- * * Return the depth of an Item. * * Results: * Integer >= -1. (-1 for the root) * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_GetDepth( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { #if 0 Tree_UpdateItemIndex(tree); #endif return item->depth; } /* *---------------------------------------------------------------------- * * TreeItem_GetID -- * * Return the unique ID of an Item. * * Results: * Integer >= 0. (0 for the root) * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_GetID( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return item->id; } /* *---------------------------------------------------------------------- * * TreeItem_SetID -- * * Set the unique ID of an Item. This is called when the item * is created. * * Results: * The given ID. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_SetID( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int id /* Unique ID for the item. */ ) { return item->id = id; } /* *---------------------------------------------------------------------- * * TreeItem_GetEnabled -- * * Return whether an Item is enabled or not. * * Results: * TRUE if the item is enabled, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_GetEnabled( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return (item->state & STATE_ITEM_ENABLED) != 0; } /* *---------------------------------------------------------------------- * * TreeItem_GetSelected -- * * Return whether an Item is selected or not. * * Results: * TRUE if the item is part of the selection, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_GetSelected( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return (item->state & STATE_ITEM_SELECTED) != 0; } /* *---------------------------------------------------------------------- * * TreeItem_CanAddToSelection -- * * Return whether an Item is selectable or not. * * Results: * TRUE if the item can be added to the selection, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_CanAddToSelection( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { if (item->header != NULL) return FALSE; if (TreeItem_GetSelected(tree, item)) return FALSE; if (!TreeItem_GetEnabled(tree, item)) return FALSE; #ifdef SELECTION_VISIBLE if (!TreeItem_ReallyVisible(tree, item)) return FALSE; #endif return TRUE; } /* *---------------------------------------------------------------------- * * TreeItem_GetParent -- * * Return the parent of an Item. * * Results: * Token for parent Item, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeItem_GetParent( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return item->parent; } /* *---------------------------------------------------------------------- * * TreeItem_GetWrap -- * * Return whether an Item -wrap is TRUE or FALSE. * * Results: * TRUE if the item should wrap, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_GetWrap( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return (item->flags & ITEM_FLAG_WRAP) != 0; } /* *---------------------------------------------------------------------- * * TreeItem_GetNextSibling -- * * Return the next sibling of an Item. * * Results: * Token for next sibling Item, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeItem_GetNextSibling( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return item->nextSibling; } /* *---------------------------------------------------------------------- * * TreeItem_NextSiblingVisible -- * * Find a following sibling that is ReallyVisible(). * * Results: * Token for a sibling Item, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeItem_NextSiblingVisible( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { item = TreeItem_GetNextSibling(tree, item); while (item != NULL) { if (TreeItem_ReallyVisible(tree, item)) return item; item = TreeItem_GetNextSibling(tree, item); } return NULL; } /* *---------------------------------------------------------------------- * * TreeItem_SetDInfo -- * * Store a display-info token in an Item. Called by the display * code. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_SetDInfo( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ TreeItemDInfo dInfo /* Display-info token. */ ) { item->dInfo = dInfo; } /* *---------------------------------------------------------------------- * * TreeItem_GetDInfo -- * * Return the display-info token of an Item. Called by the display * code. * * Results: * The display-info token or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItemDInfo TreeItem_GetDInfo( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return item->dInfo; } /* *---------------------------------------------------------------------- * * TreeItem_SetRInfo -- * * Store a range-info token in an Item. Called by the display * code. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_SetRInfo( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ TreeItemRInfo rInfo /* Range-info token */ ) { item->rInfo = rInfo; } /* *---------------------------------------------------------------------- * * TreeItem_GetRInfo -- * * Return the range-info token of an Item. Called by the display * code. * * Results: * The range-info token or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItemRInfo TreeItem_GetRInfo( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return item->rInfo; } /* *---------------------------------------------------------------------- * * TreeItem_Next -- * * Return the Item after the given one. * * Results: * Result will be: * a) the first child, or * b) the next sibling, or * c) the next sibling of an ancestor, or * d) NULL if no item follows this one * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeItem_Next( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { if (item->firstChild != NULL) return item->firstChild; if (item->nextSibling != NULL) return item->nextSibling; while (1) { item = item->parent; if (item == NULL) break; if (item->nextSibling != NULL) return item->nextSibling; } return NULL; } /* *---------------------------------------------------------------------- * * TreeItem_NextVisible -- * * Return the ReallyVisible() Item after the given one. * * Results: * Result will be: * a) the first ReallyVisible() child, or * b) the next ReallyVisible() sibling, or * c) the next ReallyVisible() sibling of an ancestor, or * d) NULL if no ReallyVisible() item follows this one * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeItem_NextVisible( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { item = TreeItem_Next(tree, item); while (item != NULL) { if (TreeItem_ReallyVisible(tree, item)) return item; item = TreeItem_Next(tree, item); } return NULL; } /* *---------------------------------------------------------------------- * * TreeItem_Prev -- * * Return the Item before the given one. * * Results: * Result will be: * a) the last descendant of the previous sibling, or * b) the parent, or * c) NULL if the given Item is the root * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeItem_Prev( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { TreeItem walk; if (item->parent == NULL) /* root */ return NULL; walk = item->parent; if (item->prevSibling) { walk = item->prevSibling; while (walk->lastChild != NULL) walk = walk->lastChild; } return walk; } /* *---------------------------------------------------------------------- * * TreeItem_PrevVisible -- * * Return the ReallyVisible() Item before the given one. * * Results: * Result will be: * a) the last descendant of the previous sibling, or * b) the parent, or * c) NULL if the given Item is the root * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeItem_PrevVisible( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { item = TreeItem_Prev(tree, item); while (item != NULL) { if (TreeItem_ReallyVisible(tree, item)) return item; item = TreeItem_Prev(tree, item); } return NULL; } /* *---------------------------------------------------------------------- * * TreeItem_ToIndex -- * * Return Item.index and Item.indexVis. * * Results: * The zero-based indexes of the Item. * * Side effects: * Will recalculate the indexes of every item if needed. * *---------------------------------------------------------------------- */ void TreeItem_ToIndex( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int *index, /* Returned Item.index, may be NULL */ int *indexVis /* Returned Item.indexVis, may be NULL */ ) { Tree_UpdateItemIndex(tree); if (index != NULL) (*index) = item->index; if (indexVis != NULL) (*indexVis) = item->indexVis; } /* *---------------------------------------------------------------------- * * TreeItem_HasTag -- * * Checks whether an item has a certain tag. * * Results: * Returns TRUE if the item has the given tag. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_HasTag( TreeItem item, /* The item to test. */ Tk_Uid tag /* Tag to look for. */ ) { TagInfo *tagInfo = item->tagInfo; Tk_Uid *tagPtr; int count; if (tagInfo == NULL) return 0; for (tagPtr = tagInfo->tagPtr, count = tagInfo->numTags; count > 0; tagPtr++, count--) { if (*tagPtr == tag) { return 1; } } return 0; } typedef struct Qualifiers { TreeCtrl *tree; int visible; /* 1 if the item must be ReallyVisible(), 0 if the item must not be ReallyVisible(), -1 for unspecified. */ int states[3]; /* Item states that must be on or off. */ TagExpr expr; /* Tag expression. */ int exprOK; /* TRUE if expr is valid. */ int depth; /* >= 0 for depth, -1 for unspecified */ Tk_Uid tag; /* Tag (without operators) or NULL. */ } Qualifiers; /* *---------------------------------------------------------------------- * * Qualifiers_Init -- * * Helper routine for TreeItem_FromObj. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Qualifiers_Init( TreeCtrl *tree, /* Widget info. */ Qualifiers *q /* Out: Initialized qualifiers. */ ) { q->tree = tree; q->visible = -1; q->states[0] = q->states[1] = q->states[2] = 0; q->exprOK = FALSE; q->depth = -1; q->tag = NULL; } /* *---------------------------------------------------------------------- * * Qualifiers_Scan -- * * Helper routine for TreeItemList_FromObj. * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Qualifiers_Scan( Qualifiers *q, /* Must call Qualifiers_Init first, * and Qualifiers_Free if result is TCL_OK. */ int objc, /* Number of arguments. */ Tcl_Obj **objv, /* Argument values. */ int startIndex, /* First objv[] index to look at. */ int *argsUsed /* Out: number of objv[] used. */ ) { TreeCtrl *tree = q->tree; Tcl_Interp *interp = tree->interp; int qual, j = startIndex; static CONST char *qualifiers[] = { "depth", "state", "tag", "visible", "!visible", NULL }; enum qualEnum { QUAL_DEPTH, QUAL_STATE, QUAL_TAG, QUAL_VISIBLE, QUAL_NOT_VISIBLE }; /* Number of arguments used by qualifiers[]. */ static int qualArgs[] = { 2, 2, 2, 1, 1 }; *argsUsed = 0; for (; j < objc; ) { if (Tcl_GetIndexFromObj(NULL, objv[j], qualifiers, NULL, 0, &qual) != TCL_OK) break; if (objc - j < qualArgs[qual]) { Tcl_AppendResult(interp, "missing arguments to \"", Tcl_GetString(objv[j]), "\" qualifier", NULL); goto errorExit; } switch ((enum qualEnum) qual) { case QUAL_DEPTH: { if (Tcl_GetIntFromObj(interp, objv[j + 1], &q->depth) != TCL_OK) goto errorExit; break; } case QUAL_STATE: { if (Tree_StateFromListObj(tree, STATE_DOMAIN_ITEM, objv[j + 1], q->states, SFO_NOT_TOGGLE) != TCL_OK) goto errorExit; break; } case QUAL_TAG: { if (tree->itemTagExpr) { if (q->exprOK) TagExpr_Free(&q->expr); if (TagExpr_Init(tree, objv[j + 1], &q->expr) != TCL_OK) return TCL_ERROR; q->exprOK = TRUE; } else { q->tag = Tk_GetUid(Tcl_GetString(objv[j + 1])); } break; } case QUAL_VISIBLE: { q->visible = 1; break; } case QUAL_NOT_VISIBLE: { q->visible = 0; break; } } *argsUsed += qualArgs[qual]; j += qualArgs[qual]; } return TCL_OK; errorExit: if (q->exprOK) TagExpr_Free(&q->expr); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * Qualifies -- * * Helper routine for TreeItem_FromObj. * * Results: * Returns TRUE if the item meets the given criteria. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Qualifies( Qualifiers *q, /* Qualifiers to check. */ TreeItem item /* The item to test. May be NULL. */ ) { TreeCtrl *tree = q->tree; /* Note: if the item is NULL it is a "match" because we have run * out of items to check. */ if (item == NULL) return 1; if ((q->visible == 1) && !TreeItem_ReallyVisible(tree, item)) return 0; else if ((q->visible == 0) && TreeItem_ReallyVisible(tree, (TreeItem) item)) return 0; if (q->states[STATE_OP_OFF] & item->state) return 0; if ((q->states[STATE_OP_ON] & item->state) != q->states[STATE_OP_ON]) return 0; if (q->exprOK && !TagExpr_Eval(&q->expr, item->tagInfo)) return 0; if ((q->depth >= 0) && (item->depth + 1 != q->depth)) return 0; if ((q->tag != NULL) && !TreeItem_HasTag(item, q->tag)) return 0; return 1; } /* *---------------------------------------------------------------------- * * Qualifiers_Free -- * * Helper routine for TreeItem_FromObj. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Qualifiers_Free( Qualifiers *q /* Out: Initialized qualifiers. */ ) { if (q->exprOK) TagExpr_Free(&q->expr); } /* *---------------------------------------------------------------------- * * NotManyMsg -- * * Set the interpreter result with an error message. * * Results: * None. * * Side effects: * Changes the interpreter result. * *---------------------------------------------------------------------- */ static void NotManyMsg( TreeCtrl *tree, int doHeaders ) { FormatResult(tree->interp, "can't specify > 1 %s for this command", doHeaders ? "header" : "item"); } /* *---------------------------------------------------------------------- * * TreeItemList_FromObj -- * * Parse a Tcl_Obj item description to get a list of items. * * -- returning a single item -- * "active MODIFIERS" * "anchor MODIFIERS" * "nearest x y MODIFIERS" * "root MODIFIERS" * "first QUALIFIERS MODIFIERS" * "last QUALIFIERS MODIFIERS" * "end QUALIFIERS MODIFIERS" * "rnc row col MODIFIERS" * "ID MODIFIERS" * -- returning multiple items -- * all QUALIFIERS * QUALIFIERS (like "all QUALIFIERS") * list listOfItemDescs * range QUALIFIERS * tag tagExpr QUALIFIERS * "TAG-EXPR QUALFIERS" * * MODIFIERS: * -- returning a single item -- * above * below * left * right * top * bottom * leftmost * rightmost * next QUALIFIERS * prev QUALIFIERS * parent * firstchild QUALIFIERS * lastchild QUALIFIERS * child N|end?-offset? QUALIFIERS * nextsibling QUALIFIERS * prevsibling QUALIFIERS * sibling N|end?-offset? QUALIFIERS * -- returning multiple items -- * ancestors QUALIFIERS * children QUALIFIERS * descendants QUALIFIERS * * QUALIFIERS: * depth integer * state stateList * tag tagExpr * visible * !visible * * Examples: * $T item id "first visible firstchild" * $T item id "first visible firstchild visible" * $T item id "nearest x y nextsibling visible" * $T item id "last visible state enabled" * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItemList_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *objPtr, /* Object to parse to a list of items. */ TreeItemList *items, /* Uninitialized item list. Caller must free * it with TreeItemList_Free unless the * result of this function is TCL_ERROR. */ int flags /* IFO_xxx flags */ ) { Tcl_Interp *interp = tree->interp; int i, objc, index, listIndex, id; Tcl_HashEntry *hPtr; Tcl_HashSearch search; Tcl_Obj **objv, *elemPtr; TreeItem item = NULL; Qualifiers q; int qualArgsTotal; static CONST char *indexName[] = { "active", "all", "anchor", "end", "first", "last", "list", "nearest", "range", "rnc", "root", (char *) NULL }; enum indexEnum { INDEX_ACTIVE, INDEX_ALL, INDEX_ANCHOR, INDEX_END, INDEX_FIRST, INDEX_LAST, INDEX_LIST, INDEX_NEAREST, INDEX_RANGE, INDEX_RNC, INDEX_ROOT }; /* Number of arguments used by indexName[]. */ static int indexArgs[] = { 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 1 }; /* Boolean: can indexName[] be followed by 1 or more qualifiers. */ static int indexQual[] = { 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1 }; static CONST char *modifiers[] = { "above", "ancestors", "below", "bottom", "child", "children", "descendants", "firstchild", "lastchild", "left", "leftmost", "next", "nextsibling", "parent", "prev", "prevsibling", "right", "rightmost", "sibling", "top", (char *) NULL }; enum modEnum { TMOD_ABOVE, TMOD_ANCESTORS, TMOD_BELOW, TMOD_BOTTOM, TMOD_CHILD, TMOD_CHILDREN, TMOD_DESCENDANTS, TMOD_FIRSTCHILD, TMOD_LASTCHILD, TMOD_LEFT, TMOD_LEFTMOST, TMOD_NEXT, TMOD_NEXTSIBLING, TMOD_PARENT, TMOD_PREV, TMOD_PREVSIBLING, TMOD_RIGHT, TMOD_RIGHTMOST, TMOD_SIBLING, TMOD_TOP }; /* Number of arguments used by modifiers[]. */ static int modArgs[] = { 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1 }; /* Boolean: can modifiers[] be followed by 1 or more qualifiers. */ static int modQual[] = { 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0 }; TreeItemList_Init(tree, items, 0); Qualifiers_Init(tree, &q); if (Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK) goto baditem; if (objc == 0) goto baditem; listIndex = 0; elemPtr = objv[listIndex]; if (Tcl_GetIndexFromObj(NULL, elemPtr, indexName, NULL, 0, &index) == TCL_OK) { if (objc - listIndex < indexArgs[index]) { Tcl_AppendResult(interp, "missing arguments to \"", Tcl_GetString(elemPtr), "\" keyword", NULL); goto errorExit; } qualArgsTotal = 0; if (indexQual[index]) { if (Qualifiers_Scan(&q, objc, objv, listIndex + indexArgs[index], &qualArgsTotal) != TCL_OK) { goto errorExit; } } switch ((enum indexEnum) index) { case INDEX_ACTIVE: { item = tree->activeItem; break; } case INDEX_ALL: { if (qualArgsTotal) { hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); if (Qualifies(&q, item)) { TreeItemList_Append(items, (TreeItem) item); } hPtr = Tcl_NextHashEntry(&search); } item = NULL; } else if (flags & IFO_LIST_ALL) { hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); TreeItemList_Append(items, item); hPtr = Tcl_NextHashEntry(&search); } item = NULL; } else { item = ITEM_ALL; } break; } case INDEX_ANCHOR: { item = tree->anchorItem; break; } case INDEX_FIRST: { item = tree->root; while (!Qualifies(&q, item)) item = TreeItem_Next(tree, item); break; } case INDEX_END: case INDEX_LAST: { item = tree->root; while (item->lastChild) { item = item->lastChild; } while (!Qualifies(&q, item)) item = TreeItem_Prev(tree, item); break; } case INDEX_LIST: { int listObjc; Tcl_Obj **listObjv; int count; if (Tcl_ListObjGetElements(interp, objv[listIndex + 1], &listObjc, &listObjv) != TCL_OK) { goto errorExit; } for (i = 0; i < listObjc; i++) { TreeItemList item2s; if (TreeItemList_FromObj(tree, listObjv[i], &item2s, flags) != TCL_OK) goto errorExit; TreeItemList_Concat(items, &item2s); TreeItemList_Free(&item2s); } /* If any of the item descriptions in the list is "all", then * clear the list of items and use "all". */ count = TreeItemList_Count(items); for (i = 0; i < count; i++) { TreeItem item2 = TreeItemList_Nth(items, i); if (IS_ALL(item2)) break; } if (i < count) { TreeItemList_Free(items); item = ITEM_ALL; } else item = NULL; break; } case INDEX_NEAREST: { int x, y; if (Tk_GetPixelsFromObj(interp, tree->tkwin, objv[listIndex + 1], &x) != TCL_OK) { goto errorExit; } if (Tk_GetPixelsFromObj(interp, tree->tkwin, objv[listIndex + 2], &y) != TCL_OK) { goto errorExit; } item = Tree_ItemUnderPoint(tree, &x, &y, NULL, TRUE); break; } case INDEX_RANGE: { TreeItem itemFirst, itemLast; if (TreeItem_FromObj(tree, objv[listIndex + 1], &itemFirst, IFO_NOT_NULL) != TCL_OK) goto errorExit; if (TreeItem_FromObj(tree, objv[listIndex + 2], &itemLast, IFO_NOT_NULL) != TCL_OK) goto errorExit; if (TreeItem_FirstAndLast(tree, &itemFirst, &itemLast) == 0) goto errorExit; while (1) { if (Qualifies(&q, itemFirst)) { TreeItemList_Append(items, itemFirst); } if (itemFirst == itemLast) break; itemFirst = TreeItem_Next(tree, itemFirst); } item = NULL; break; } case INDEX_RNC: { int row, col; if (Tcl_GetIntFromObj(interp, objv[listIndex + 1], &row) != TCL_OK) goto errorExit; if (Tcl_GetIntFromObj(interp, objv[listIndex + 2], &col) != TCL_OK) goto errorExit; item = Tree_RNCToItem(tree, row, col); break; } case INDEX_ROOT: { item = tree->root; break; } } listIndex += indexArgs[index] + qualArgsTotal; /* No indexName[] was found. */ } else { int gotId = FALSE; TagExpr expr; /* Try an itemPrefix + item ID. */ if (tree->itemPrefixLen) { char *end, *t = Tcl_GetString(elemPtr); if (strncmp(t, tree->itemPrefix, tree->itemPrefixLen) == 0) { t += tree->itemPrefixLen; id = strtoul(t, &end, 10); if ((end != t) && (*end == '\0')) gotId = TRUE; } /* Try an item ID. */ } else if (Tcl_GetIntFromObj(NULL, elemPtr, &id) == TCL_OK) { gotId = TRUE; } if (gotId) { hPtr = Tcl_FindHashEntry(&tree->itemHash, (char *) INT2PTR(id)); if (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); } else { item = NULL; } listIndex++; goto gotFirstPart; } /* Try a list of qualifiers. This has the same effect as * "all QUALIFIERS". */ if (Qualifiers_Scan(&q, objc, objv, listIndex, &qualArgsTotal) != TCL_OK) { goto errorExit; } if (qualArgsTotal) { hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); if (Qualifies(&q, item)) { TreeItemList_Append(items, item); } hPtr = Tcl_NextHashEntry(&search); } item = NULL; listIndex += qualArgsTotal; goto gotFirstPart; } /* Try a tag or tag expression followed by qualifiers. */ if (objc > 1) { if (Qualifiers_Scan(&q, objc, objv, listIndex + 1, &qualArgsTotal) != TCL_OK) { goto errorExit; } } if (tree->itemTagExpr) { if (TagExpr_Init(tree, elemPtr, &expr) != TCL_OK) goto errorExit; hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); if (TagExpr_Eval(&expr, item->tagInfo) && Qualifies(&q, item)) { TreeItemList_Append(items, item); } hPtr = Tcl_NextHashEntry(&search); } TagExpr_Free(&expr); } else { Tk_Uid tag = Tk_GetUid(Tcl_GetString(elemPtr)); hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); if (TreeItem_HasTag(item, tag) && Qualifies(&q, item)) { TreeItemList_Append(items, item); } hPtr = Tcl_NextHashEntry(&search); } } item = NULL; listIndex += 1 + qualArgsTotal; } gotFirstPart: /* If 1 item, use it and clear the list. */ if (TreeItemList_Count(items) == 1) { item = TreeItemList_Nth(items, 0); items->count = 0; } /* If "all" but only root exists, use it. */ if (IS_ALL(item) && (tree->itemCount == 1) && !(flags & IFO_NOT_ROOT)) { item = tree->root; } /* If > 1 item, no modifiers may follow. */ if ((TreeItemList_Count(items) > 1) || IS_ALL(item)) { if (listIndex < objc) { Tcl_AppendResult(interp, "unexpected arguments after \"", (char *) NULL); for (i = 0; i < listIndex; i++) { Tcl_AppendResult(interp, Tcl_GetString(objv[i]), (char *) NULL); if (i != listIndex - 1) Tcl_AppendResult(interp, " ", (char *) NULL); } Tcl_AppendResult(interp, "\"", (char *) NULL); goto errorExit; } } /* This means a valid specification was given, but there is no such item */ if ((TreeItemList_Count(items) == 0) && (item == NULL)) { if (flags & IFO_NOT_NULL) goto noitem; /* Empty list returned */ goto goodExit; } /* Process any modifiers following the item we matched above. */ for (; listIndex < objc; /* nothing */) { elemPtr = objv[listIndex]; if (Tcl_GetIndexFromObj(interp, elemPtr, modifiers, "modifier", 0, &index) != TCL_OK) { goto errorExit; } if (objc - listIndex < modArgs[index]) { Tcl_AppendResult(interp, "missing arguments to \"", Tcl_GetString(elemPtr), "\" modifier", NULL); goto errorExit; } qualArgsTotal = 0; if (modQual[index]) { Qualifiers_Free(&q); Qualifiers_Init(tree, &q); if (Qualifiers_Scan(&q, objc, objv, listIndex + modArgs[index], &qualArgsTotal) != TCL_OK) { goto errorExit; } } switch ((enum modEnum) index) { case TMOD_ABOVE: { item = Tree_ItemAbove(tree, item); break; } case TMOD_ANCESTORS: { item = item->parent; while (item != NULL) { if (Qualifies(&q, item)) { TreeItemList_Append(items, item); } item = item->parent; } item = NULL; break; } case TMOD_BELOW: { item = Tree_ItemBelow(tree, item); break; } case TMOD_BOTTOM: { item = Tree_ItemBottom(tree, item); break; } case TMOD_CHILD: { int n, endRelative; if (Tree_GetIntForIndex(tree, objv[listIndex + 1], &n, &endRelative) != TCL_OK) { goto errorExit; } if (endRelative) { item = item->lastChild; while (item != NULL) { if (Qualifies(&q, item)) if (n-- <= 0) break; item = item->prevSibling; } } else { item = item->firstChild; while (item != NULL) { if (Qualifies(&q, item)) if (n-- <= 0) break; item = item->nextSibling; } } break; } case TMOD_CHILDREN: { item = item->firstChild; while (item != NULL) { if (Qualifies(&q, item)) { TreeItemList_Append(items, item); } item = item->nextSibling; } item = NULL; break; } case TMOD_DESCENDANTS: { TreeItem last = item; while (last->lastChild != NULL) last = last->lastChild; item = item->firstChild; while (item != NULL) { if (Qualifies(&q, item)) { TreeItemList_Append(items, item); } if (item == last) break; item = TreeItem_Next(tree, item); } item = NULL; break; } case TMOD_FIRSTCHILD: { item = item->firstChild; while (!Qualifies(&q, item)) item = item->nextSibling; break; } case TMOD_LASTCHILD: { item = item->lastChild; while (!Qualifies(&q, item)) item = item->prevSibling; break; } case TMOD_LEFT: { item = Tree_ItemLeft(tree, item); break; } case TMOD_LEFTMOST: { item = Tree_ItemLeftMost(tree, item); break; } case TMOD_NEXT: { item = TreeItem_Next(tree, item); while (!Qualifies(&q, item)) item = TreeItem_Next(tree, item); break; } case TMOD_NEXTSIBLING: { item = item->nextSibling; while (!Qualifies(&q, item)) item = item->nextSibling; break; } case TMOD_PARENT: { item = item->parent; break; } case TMOD_PREV: { item = TreeItem_Prev(tree, item); while (!Qualifies(&q, item)) item = TreeItem_Prev(tree, item); break; } case TMOD_PREVSIBLING: { item = item->prevSibling; while (!Qualifies(&q, item)) item = item->prevSibling; break; } case TMOD_RIGHT: { item = Tree_ItemRight(tree, item); break; } case TMOD_RIGHTMOST: { item = Tree_ItemRightMost(tree, item); break; } case TMOD_SIBLING: { int n, endRelative; if (Tree_GetIntForIndex(tree, objv[listIndex + 1], &n, &endRelative) != TCL_OK) { goto errorExit; } item = item->parent; if (item == NULL) break; if (endRelative) { item = item->lastChild; while (item != NULL) { if (Qualifies(&q, item)) if (n-- <= 0) break; item = item->prevSibling; } } else { item = item->firstChild; while (item != NULL) { if (Qualifies(&q, item)) if (n-- <= 0) break; item = item->nextSibling; } } break; } case TMOD_TOP: { item = Tree_ItemTop(tree, item); break; } } if ((TreeItemList_Count(items) > 1) || IS_ALL(item)) { int end = listIndex + modArgs[index] + qualArgsTotal; if (end < objc) { Tcl_AppendResult(interp, "unexpected arguments after \"", (char *) NULL); for (i = 0; i < end; i++) { Tcl_AppendResult(interp, Tcl_GetString(objv[i]), (char *) NULL); if (i != end - 1) Tcl_AppendResult(interp, " ", (char *) NULL); } Tcl_AppendResult(interp, "\"", (char *) NULL); goto errorExit; } } if ((TreeItemList_Count(items) == 0) && (item == NULL)) { if (flags & IFO_NOT_NULL) goto noitem; /* Empty list returned. */ goto goodExit; } listIndex += modArgs[index] + qualArgsTotal; } if ((flags & IFO_NOT_MANY) && (IS_ALL(item) || (TreeItemList_Count(items) > 1))) { NotManyMsg(tree, FALSE); goto errorExit; } if (TreeItemList_Count(items)) { if (flags & (IFO_NOT_ROOT | IFO_NOT_ORPHAN)) { int i; for (i = 0; i < TreeItemList_Count(items); i++) { item = TreeItemList_Nth(items, i); if (IS_ROOT(item) && (flags & IFO_NOT_ROOT)) goto notRoot; if ((item->parent == NULL) && (flags & IFO_NOT_ORPHAN)) goto notOrphan; } } } else if (IS_ALL(item)) { TreeItemList_Append(items, ITEM_ALL); } else { if (IS_ROOT(item) && (flags & IFO_NOT_ROOT)) { notRoot: FormatResult(interp, "can't specify \"root\" for this command"); goto errorExit; } if ((item->parent == NULL) && (flags & IFO_NOT_ORPHAN)) { notOrphan: FormatResult(interp, "item \"%s\" has no parent", Tcl_GetString(objPtr)); goto errorExit; } TreeItemList_Append(items, item); } goodExit: Qualifiers_Free(&q); return TCL_OK; baditem: Tcl_AppendResult(interp, "bad item description \"", Tcl_GetString(objPtr), "\"", NULL); goto errorExit; noitem: Tcl_AppendResult(interp, "item \"", Tcl_GetString(objPtr), "\" doesn't exist", NULL); errorExit: Qualifiers_Free(&q); TreeItemList_Free(items); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeItem_FromObj -- * * Parse a Tcl_Obj item description to get a single item. * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *objPtr, /* Object to parse to an item. */ TreeItem *itemPtr, /* Returned item. */ int flags /* IFO_xxx flags */ ) { TreeItemList items; if (TreeItemList_FromObj(tree, objPtr, &items, flags | IFO_NOT_MANY) != TCL_OK) return TCL_ERROR; /* May be NULL. */ (*itemPtr) = TreeItemList_Nth(&items, 0); TreeItemList_Free(&items); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeItemForEach_Start -- * * Begin iterating over items. A command might accept two item * descriptions for a range of items, or a single item description * which may itself refer to multiple items. Either item * description could be ITEM_ALL. * * Results: * Returns the first item to iterate over. If an error occurs * then ItemForEach.error is set to 1. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeItemForEach_Start( TreeItemList *items, /* List of items. */ TreeItemList *item2s, /* List of items or NULL. */ ItemForEach *iter /* Returned info, pass to TreeItemForEach_Next. */ ) { TreeCtrl *tree = items->tree; TreeItem item, item2 = NULL; item = TreeItemList_Nth(items, 0); if (item2s) item2 = TreeItemList_Nth(item2s, 0); iter->tree = tree; iter->all = FALSE; iter->error = 0; iter->items = NULL; if (IS_ALL(item) || IS_ALL(item2)) { Tcl_HashEntry *hPtr = Tcl_FirstHashEntry(&tree->itemHash, &iter->search); iter->all = TRUE; return iter->item = (TreeItem) Tcl_GetHashValue(hPtr); } if (item2 != NULL) { if (TreeItem_FirstAndLast(tree, &item, &item2) == 0) { iter->error = 1; return NULL; } iter->last = item2; return iter->item = item; } iter->items = items; iter->index = 0; return iter->item = item; } /* *---------------------------------------------------------------------- * * TreeItemForEach_Next -- * * Returns the next item to iterate over. Keep calling this until * the result is NULL. * * Results: * Returns the next item to iterate over or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeItemForEach_Next( ItemForEach *iter /* Initialized by TreeItemForEach_Start. */ ) { TreeCtrl *tree = iter->tree; if (iter->all) { Tcl_HashEntry *hPtr = Tcl_NextHashEntry(&iter->search); if (hPtr == NULL) return iter->item = NULL; return iter->item = (TreeItem) Tcl_GetHashValue(hPtr); } if (iter->items != NULL) { if (iter->index >= TreeItemList_Count(iter->items)) return iter->item = NULL; return iter->item = TreeItemList_Nth(iter->items, ++iter->index); } if (iter->item == iter->last) return iter->item = NULL; return iter->item = TreeItem_Next(tree, iter->item); } /* *---------------------------------------------------------------------- * * Item_ToggleOpen -- * * Inverts the STATE_ITEM_OPEN flag of an Item. * * Results: * Items may be displayed/undisplayed. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ static void Item_ToggleOpen( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item record. */ int stateOff, /* STATE_ITEM_OPEN or 0 */ int stateOn /* STATE_ITEM_OPEN or 0 */ ) { int mask; mask = TreeItem_ChangeState(tree, item, stateOff, stateOn); if (IS_ROOT(item) && !tree->showRoot) return; #if 0 /* Don't affect display if we weren't visible */ if (!TreeItem_ReallyVisible(tree, item)) return; /* Invalidate display info for this item, so it is redrawn later. */ Tree_InvalidateItemDInfo(tree, item, NULL); #endif if (item->numChildren > 0) { /* indexVis needs updating for all items after this one, if we * have any visible children */ tree->updateIndex = 1; Tree_DInfoChanged(tree, DINFO_REDO_RANGES); /* Hiding/showing children may change the width of any column */ TreeColumns_InvalidateWidthOfItems(tree, NULL); TreeColumns_InvalidateSpans(tree); } /* If this item was previously onscreen, this call is repetitive. */ Tree_EventuallyRedraw(tree); } /* *---------------------------------------------------------------------- * * TreeItem_OpenClose -- * * Inverts the STATE_ITEM_OPEN flag of an Item. * * Results: * Items may be displayed/undisplayed. * * Side effects: * Display changes. and events may be * generated. * *---------------------------------------------------------------------- */ void TreeItem_OpenClose( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int mode /* -1: toggle * 0: close * 1: open */ ) { int stateOff = 0, stateOn = 0; /* When processing a list of items, any or event * may result in items being deleted. */ if (IS_DELETED(item)) return; if (mode == -1) { if (item->state & STATE_ITEM_OPEN) stateOff = STATE_ITEM_OPEN; else stateOn = STATE_ITEM_OPEN; } else if (!mode && (item->state & STATE_ITEM_OPEN)) stateOff = STATE_ITEM_OPEN; else if (mode && !(item->state & STATE_ITEM_OPEN)) stateOn = STATE_ITEM_OPEN; if (stateOff != stateOn) { TreeNotify_OpenClose(tree, item, stateOn, TRUE); if (IS_DELETED(item)) return; Item_ToggleOpen(tree, item, stateOff, stateOn); TreeNotify_OpenClose(tree, item, stateOn, FALSE); } } /* *---------------------------------------------------------------------- * * TreeItem_Delete -- * * Recursively frees resources associated with an Item and its * descendants. * * Results: * Items are removed from their parent and freed. * * Side effects: * Memory is freed. If the active item or selection-anchor item * is deleted, the root becomes the active/anchor item. * Display changes may occur. * *---------------------------------------------------------------------- */ void TreeItem_Delete( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { while (item->numChildren > 0) TreeItem_Delete(tree, item->firstChild); /* Remove from tree->headerItems. */ if (item->header != NULL) { if (item != tree->headerItems) { item->prevSibling->nextSibling = item->nextSibling; if (item->nextSibling != NULL) item->nextSibling->prevSibling = item->prevSibling; } else { tree->headerItems = item->nextSibling; if (item->nextSibling != NULL) item->nextSibling->prevSibling = NULL; } item->prevSibling = item->nextSibling = NULL; } TreeItem_RemoveFromParent(tree, item); TreeDisplay_ItemDeleted(tree, item); TreeGradient_ItemDeleted(tree, item); TreeTheme_ItemDeleted(tree, item); if (item->header != NULL) Tree_RemoveHeader(tree, item); else Tree_RemoveItem(tree, item); TreeItem_FreeResources(tree, item); if (tree->activeItem == item) { tree->activeItem = tree->root; TreeItem_ChangeState(tree, tree->activeItem, 0, STATE_ITEM_ACTIVE); } if (tree->anchorItem == item) tree->anchorItem = tree->root; if (tree->debug.enable && tree->debug.data) Tree_Debug(tree); } /* *---------------------------------------------------------------------- * * TreeItem_Deleted -- * * Return 1 if the given item is deleted. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_Deleted( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return IS_DELETED(item); } /* *---------------------------------------------------------------------- * * TreeItem_FirstAndLast -- * * Determine the order of two items and swap them if needed. * * Results: * If the items do not share a common ancestor, 0 is returned and * an error message is left in the interpreter result. * Otherwise the return value is the number of items in the * range between first and last. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_FirstAndLast( TreeCtrl *tree, /* Widget info. */ TreeItem *first, /* Item token. */ TreeItem *last /* Item token. */ ) { int indexFirst, indexLast, index; if (TreeItem_RootAncestor(tree, *first) != TreeItem_RootAncestor(tree, *last)) { FormatResult(tree->interp, "item %s%d and item %s%d don't share a common ancestor", tree->itemPrefix, TreeItem_GetID(tree, *first), tree->itemPrefix, TreeItem_GetID(tree, *last)); return 0; } TreeItem_ToIndex(tree, *first, &indexFirst, NULL); TreeItem_ToIndex(tree, *last, &indexLast, NULL); if (indexFirst > indexLast) { TreeItem item = *first; *first = *last; *last = item; index = indexFirst; indexFirst = indexLast; indexLast = index; } return indexLast - indexFirst + 1; } /* *---------------------------------------------------------------------- * * TreeItem_ListDescendants -- * * Appends descendants of an item to a list of items. * * Results: * List of items may grow. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_ListDescendants( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ TreeItemList *items /* List of items to append descendants to. */ ) { TreeItem last; if (item->firstChild == NULL) return; last = item; while (last->lastChild != NULL) last = last->lastChild; item = item->firstChild; while (1) { TreeItemList_Append(items, item); if (item == last) break; item = TreeItem_Next(tree, item); } } /* *---------------------------------------------------------------------- * * TreeItem_UpdateDepth -- * * Recursively updates Item.depth of an Item and its * descendants. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_UpdateDepth( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { TreeItem child; if (IS_ROOT(item)) return; if (item->parent != NULL) item->depth = item->parent->depth + 1; else item->depth = 0; child = item->firstChild; while (child != NULL) { TreeItem_UpdateDepth(tree, child); child = child->nextSibling; } } /* *---------------------------------------------------------------------- * * TreeItem_AddToParent -- * * Called *after* an Item is added as a child to another Item. * * Results: * None. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ void TreeItem_AddToParent( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { TreeItem last, parent = item->parent; /* If this is the new last child, redraw the lines of the previous * sibling and all of its descendants so the line from the previous * sibling reaches this item */ if ((item->prevSibling != NULL) && (item->nextSibling == NULL) && tree->showLines && (tree->columnTree != NULL)) { last = item->prevSibling; while (last->lastChild != NULL) last = last->lastChild; Tree_InvalidateItemDInfo(tree, tree->columnTree, item->prevSibling, last); } /* Redraw the parent if the parent has "-button auto". */ if (IS_VISIBLE(item) && (parent->flags & ITEM_FLAG_BUTTON_AUTO) && tree->showButtons && (tree->columnTree != NULL)) { Tree_InvalidateItemDInfo(tree, tree->columnTree, parent, NULL); } tree->updateIndex = 1; Tree_DInfoChanged(tree, DINFO_REDO_RANGES); /* Tree_UpdateItemIndex() also recalcs depth, but in one of my demos * I retrieve item depth during list creation. Since Tree_UpdateItemIndex() * is slow I will keep depth up-to-date here. */ TreeItem_UpdateDepth(tree, item); TreeColumns_InvalidateWidthOfItems(tree, NULL); TreeColumns_InvalidateSpans(tree); if (tree->debug.enable && tree->debug.data) Tree_Debug(tree); } /* *---------------------------------------------------------------------- * * RemoveFromParentAux -- * * Recursively update Item.depth, Item.index and Item.indexVis. * * Results: * None. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ static void RemoveFromParentAux( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item being removed. */ int *index /* New value of Item.index. Is incremented. */ ) { TreeItem child; /* Invalidate display info. Don't free it because we may just be * moving the item to a new parent. FIXME: if it is being moved, * it might not actually need to be redrawn (just copied) */ if (item->dInfo != NULL) Tree_InvalidateItemDInfo(tree, NULL, item, NULL); if (item->parent != NULL) item->depth = item->parent->depth + 1; else item->depth = 0; item->index = (*index)++; item->indexVis = -1; child = item->firstChild; while (child != NULL) { RemoveFromParentAux(tree, child, index); child = child->nextSibling; } } /* *---------------------------------------------------------------------- * * TreeItem_RemoveFromParent -- * * Remove an Item from its parent (if any). * * Results: * None. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ void TreeItem_RemoveFromParent( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { TreeItem parent = item->parent; TreeItem last; int index = 0; if (parent == NULL) return; /* If this is the last child, redraw the lines of the previous * sibling and all of its descendants because the line from * the previous sibling to us is now gone */ if ((item->prevSibling != NULL) && (item->nextSibling == NULL) && tree->showLines && (tree->columnTree != NULL)) { last = item->prevSibling; while (last->lastChild != NULL) last = last->lastChild; Tree_InvalidateItemDInfo(tree, tree->columnTree, item->prevSibling, last); } /* Redraw the parent if the parent has "-button auto". */ if (IS_VISIBLE(item) && (parent->flags & ITEM_FLAG_BUTTON_AUTO) && tree->showButtons && (tree->columnTree != NULL)) { Tree_InvalidateItemDInfo(tree, tree->columnTree, parent, NULL); } /* * Set a flag indicating that item indexes are out-of-date. This doesn't * cover the current item being removed. */ tree->updateIndex = 1; Tree_DInfoChanged(tree, DINFO_REDO_RANGES); if (item->prevSibling) item->prevSibling->nextSibling = item->nextSibling; if (item->nextSibling) item->nextSibling->prevSibling = item->prevSibling; if (parent->firstChild == item) { parent->firstChild = item->nextSibling; if (!parent->firstChild) parent->lastChild = NULL; } if (parent->lastChild == item) parent->lastChild = item->prevSibling; item->prevSibling = item->nextSibling = NULL; item->parent = NULL; parent->numChildren--; /* * Update Item.depth, Item.index and Item.indexVis for the item and its * descendants. An up-to-date Item.index is needed for some operations that * use a range of items, such as [item delete]. */ RemoveFromParentAux(tree, item, &index); } /* *---------------------------------------------------------------------- * * TreeItem_RemoveColumns -- * * Free a range of Columns in an Item. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ void TreeItem_RemoveColumns( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int first, /* 0-based column index at start of * the range. Must be <= last */ int last /* 0-based column index at end of * the range. Must be >= first */ ) { TreeItemColumn column = item->columns; TreeItemColumn prev = NULL, next = NULL; int i = 0; while (column != NULL) { next = column->next; if (i == first - 1) prev = column; else if (i >= first) Column_FreeResources(tree, column); if (i == last) break; ++i; column = next; } if (prev != NULL) prev->next = next; else if (first == 0) item->columns = next; } /* *---------------------------------------------------------------------- * * TreeItem_RemoveAllColumns -- * * Free all the Columns in an Item. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ void TreeItem_RemoveAllColumns( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { TreeItemColumn column = item->columns; while (column != NULL) { TreeItemColumn next = column->next; /* Don't delete the tail item-column in header items. */ if (item->header != NULL && next == NULL) { item->columns = column; return; } Column_FreeResources(tree, column); column = next; } item->columns = NULL; } /* *---------------------------------------------------------------------- * * Item_CreateColumn -- * * Allocate a Column record for an Item if it doesn't already * exist. * * Results: * Pointer to new or existing Column record. * * Side effects: * Any column records preceding the desired one are allocated * if they weren't already. Memory is allocated. * *---------------------------------------------------------------------- */ static TreeItemColumn Item_CreateColumn( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item to contain the column. */ int columnIndex, /* 0-based index of new column. */ int *isNew /* May be NULL. Set to TRUE if the * column record was created. */ ) { TreeItemColumn column; int i; #ifdef TREECTRL_DEBUG if (columnIndex < 0 || columnIndex >= tree->columnCount + (item->header ? 1 : 0)) { panic("Item_CreateColumn with index %d, must be from 0-%d", columnIndex, tree->columnCount + (item->header ? 1 : 0) - 1); } #endif if (isNew != NULL) (*isNew) = FALSE; column = item->columns; if (column == NULL) { column = Column_Alloc(tree, item); item->columns = column; if (isNew != NULL) (*isNew) = TRUE; } for (i = 0; i < columnIndex; i++) { if (column->next == NULL) { column->next = Column_Alloc(tree, item); if (isNew != NULL) (*isNew) = TRUE; } column = column->next; } /* If creating a new -lock=none column then Column_Move does nothing */ if (item->header != NULL && columnIndex == TreeColumn_Index(tree->columnTail) + 1) { TreeItem_MoveColumn(tree, item, columnIndex, columnIndex - 1); } return column; } /* *---------------------------------------------------------------------- * * TreeItem_MoveColumn -- * * Rearranges an Item's list of Column records by moving one * in front of another. * * Results: * If the Column to be moved does not exist and the Column to place it * in front of does not exist, then nothing happens. If the Column is * to be moved past all currently allocated Columns, then new * Column records are allocated. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ void TreeItem_MoveColumn( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int columnIndex, /* 0-based index of the column to move. */ int beforeIndex /* 0-based index of the second column to move * the first column to the left of. */ ) { TreeItemColumn before = NULL, move = NULL; TreeItemColumn prevM = NULL, prevB = NULL; TreeItemColumn last = NULL, prev, walk; int index = 0; prev = NULL; walk = item->columns; while (walk != NULL) { if (index == columnIndex) { prevM = prev; move = walk; } if (index == beforeIndex) { prevB = prev; before = walk; } prev = walk; if (walk->next == NULL) last = walk; index++; walk = walk->next; } if (move == NULL && before == NULL) return; if (move == NULL) move = Column_Alloc(tree, item); else { if (before == NULL) { prevB = Item_CreateColumn(tree, item, beforeIndex - 1, NULL); last = prevB; } if (prevM == NULL) item->columns = move->next; else prevM->next = move->next; } if (before == NULL) { last->next = move; move->next = NULL; } else { if (prevB == NULL) item->columns = move; else prevB->next = move; move->next = before; } } /* *---------------------------------------------------------------------- * * TreeItem_FreeResources -- * * Free memory etc assocated with an Item. * * Results: * None. * * Side effects: * Memory is deallocated. Display changes. * *---------------------------------------------------------------------- */ void TreeItem_FreeResources( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { TreeItemColumn column; column = item->columns; while (column != NULL) column = Column_FreeResources(tree, column); if (item->dInfo != NULL) Tree_FreeItemDInfo(tree, item, NULL); if (item->rInfo != NULL) Tree_FreeItemRInfo(tree, item); if (item->spans != NULL) ckfree((char *) item->spans); if (item->header != NULL) TreeHeader_FreeResources(item->header); Tk_FreeConfigOptions((char *) item, tree->itemOptionTable, tree->tkwin); /* Add the item record to the "preserved" list. It will be freed later. */ TreeItemList_Append(&tree->preserveItemList, item); } /* *---------------------------------------------------------------------- * * TreeItem_Release -- * * Finally free an item record when it is no longer needed. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ void TreeItem_Release( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, ItemUid, (char *) item, sizeof(TreeItem_)); #else WFREE(item, TreeItem_); #endif } /* *---------------------------------------------------------------------- * * Item_HeightOfStyles -- * * Return the height used by styles in an Item. * * Results: * Maximum height in pixels of the style in each visible Column. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Item_HeightOfStyles( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item record. */ ) { TreeItemColumn column = item->columns; int *spans = TreeItem_GetSpans(tree, item); int tailOK = item->header != NULL; TreeColumn treeColumn = Tree_FirstColumn(tree, -1, tailOK); StyleDrawArgs drawArgs; int height = 0, hasHeaderElem = FALSE; drawArgs.tree = tree; if (spans == NULL) { while (column != NULL) { if (TreeColumn_Visible(treeColumn) && (column->style != NULL)) { drawArgs.state = item->state | column->cstate; drawArgs.style = column->style; drawArgs.indent = TreeItem_Indent(tree, treeColumn, item); if (treeColumn == tree->columnTail) { drawArgs.width = -1; /* as much width as the style needs */ } else { drawArgs.width = TreeColumn_UseWidth(treeColumn); if (item->header != NULL) drawArgs.width += drawArgs.indent; } height = MAX(height, TreeStyle_UseHeight(&drawArgs)); if (!hasHeaderElem && (item->header != NULL) && TreeStyle_HasHeaderElement(tree, column->style)) hasHeaderElem = TRUE; } treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK); column = column->next; } } else { while (column != NULL) { if (TreeColumn_Visible(treeColumn)) { int columnIndex = TreeColumn_Index(treeColumn); int columnIndex2 = columnIndex; TreeColumn treeColumn2 = treeColumn; drawArgs.width = 0; #if defined(TREECTRL_DEBUG) if (TreeColumn_Index(treeColumn) != columnIndex) BreakIntoDebugger(); if (TreeItemColumn_Index(tree, item, column) != columnIndex) BreakIntoDebugger(); if (spans[columnIndex] != columnIndex) BreakIntoDebugger(); #endif while (spans[columnIndex2] == columnIndex) { if (!TreeColumn_Visible(treeColumn2)) { /* nothing */ } else if (treeColumn2 == tree->columnTail) { drawArgs.width = -1; /* as much width as the style needs */ } else { drawArgs.width += TreeColumn_UseWidth(treeColumn2); } treeColumn2 = Tree_ColumnToTheRight(treeColumn2, FALSE, tailOK); if (treeColumn2 == NULL) break; columnIndex2++; } if (column->style != NULL) { drawArgs.indent = TreeItem_Indent(tree, treeColumn, item); if (item->header != NULL) drawArgs.width += drawArgs.indent; drawArgs.state = item->state | column->cstate; drawArgs.style = column->style; height = MAX(height, TreeStyle_UseHeight(&drawArgs)); if (!hasHeaderElem && (item->header != NULL) && TreeStyle_HasHeaderElement(tree, column->style)) hasHeaderElem = TRUE; } treeColumn = treeColumn2; if (treeColumn == NULL) break; while ((column != NULL) && (columnIndex < columnIndex2)) { column = column->next; columnIndex++; } continue; } treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK); column = column->next; } } /* List headers are a fixed height on Aqua. */ /* FIXME: all that work above just to ignore the result here! */ if (hasHeaderElem && tree->useTheme) { if (tree->themeHeaderHeight > 0) return tree->themeHeaderHeight; } return height; } /* *---------------------------------------------------------------------- * * TreeItem_Height -- * * Return the height of an Item. * * Results: * If the Item -height option is > 0, the result is the maximum * of the button height (if a button is displayed) and the -height * option. * If the TreeCtrl -itemheight option is > 0, the result is the maximum * of the button height (if a button is displayed) and the -itemheight * option. * Otherwise the result is the maximum of the button height (if a button * is displayed) AND the TreeCtrl -minitemheight AND the height of * the style in each visible Column. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_Height( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { int buttonHeight = 0; int useHeight; if (!TreeItem_ReallyVisible(tree, item)) return 0; if (item->header != NULL) { if (item->fixedHeight > 0) return item->fixedHeight; return Item_HeightOfStyles(tree, item); } /* Get requested height of the style in each column */ useHeight = Item_HeightOfStyles(tree, item); /* Can't have less height than our button */ if (TreeItem_HasButton(tree, item)) { buttonHeight = Tree_ButtonHeight(tree, item->state); } /* User specified a fixed height for this item */ if (item->fixedHeight > 0) return MAX(item->fixedHeight, buttonHeight); /* Fixed height of all items */ if (tree->itemHeight > 0) return MAX(tree->itemHeight, buttonHeight); /* Minimum height of all items */ if (tree->minItemHeight > 0) useHeight = MAX(useHeight, tree->minItemHeight); /* No fixed height specified */ return MAX(useHeight, buttonHeight); } /* *---------------------------------------------------------------------- * * TreeItem_InvalidateHeight -- * * Marks Item.neededHeight out-of-date. * NOTE: Item.neededHeight is unused. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_InvalidateHeight( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { } /* *---------------------------------------------------------------------- * * TreeItem_FindColumn -- * * Return an item-column token given a zero-based index. * * Results: * The item-column token or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItemColumn TreeItem_FindColumn( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int columnIndex /* 0-based index of column to find. */ ) { TreeItemColumn column; int i = 0; column = item->columns; if (!column) return NULL; while (column != NULL && i < columnIndex) { column = column->next; i++; } return column; } /* *---------------------------------------------------------------------- * * TreeItem_ColumnFromObj -- * * Return an item-column token given a Tcl_Obj column description. * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_ColumnFromObj( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ Tcl_Obj *obj, /* Column description. */ TreeItemColumn *columnPtr, /* Returned column, or NULL. */ TreeColumn *treeColumnPtr, /* May be NULL. Returned tree column, * or NULL. */ int *indexPtr, /* May be NULL. Returned 0-based index of * the column. */ int flags /* CFO_XXX flags. */ ) { TreeColumn treeColumn; int columnIndex; if (TreeColumn_FromObj(tree, obj, &treeColumn, flags) != TCL_OK) return TCL_ERROR; columnIndex = TreeColumn_Index(treeColumn); (*columnPtr) = TreeItem_FindColumn(tree, item, columnIndex); if (treeColumnPtr != NULL) (*treeColumnPtr) = treeColumn; if (indexPtr != NULL) (*indexPtr) = columnIndex; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeItem_Indent -- * * Return the amount of indentation for the given item. This is * the width of the buttons/lines. * * Results: * Pixel value >= 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_Indent( TreeCtrl *tree, /* Widget info. */ TreeColumn treeColumn, /* Which column. */ TreeItem item /* Item token. */ ) { int depth; if (item->header != NULL) { if ((TreeColumn_Lock(treeColumn) == COLUMN_LOCK_NONE) && (TreeColumn_VisIndex(treeColumn) == 0)) { return tree->canvasPadX[PAD_TOP_LEFT]; } return 0; } if (treeColumn != tree->columnTree) return 0; if (IS_ROOT(item)) return (tree->showRoot && tree->showButtons && tree->showRootButton) ? tree->useIndent : 0; Tree_UpdateItemIndex(tree); depth = item->depth; if (tree->showRoot) { depth += 1; if (tree->showButtons && tree->showRootButton) depth += 1; } else if (tree->showButtons && tree->showRootChildButtons) depth += 1; else if (tree->showLines && tree->showRootLines) depth += 1; return tree->useIndent * depth; } /* *---------------------------------------------------------------------- * * ItemDrawBackground -- * * Draws part of the background area of an Item. The area is * erased to the -itembackground color of the tree column or the * TreeCtrl -background color. If the TreeCtrl -backgroundimage * option is specified then that image is tiled over the given area. * * Results: * None. * * Side effects: * Stuff is drawn in a drawable. * *---------------------------------------------------------------------- */ static void ItemDrawBackground( TreeCtrl *tree, /* Widget info. */ TreeColumn treeColumn, /* Tree-column token. */ TreeItem item, /* Item record. */ TreeItemColumn column, /* First column. */ TreeDrawable td, /* Where to draw. */ int x, int y, /* Area of the item to draw. */ int width, int height, /* ^ */ int index /* Used to select a color from the * tree-column's -itembackground option. */ ) { TreeColor *tc; TreeClip clip, *clipPtr = &clip; TreeRectangle tr; #if USE_ITEM_PIXMAP == 0 clip.type = TREE_CLIP_AREA; switch (TreeColumn_Lock(treeColumn)) { case COLUMN_LOCK_LEFT: clip.area = TREE_AREA_LEFT; break; case COLUMN_LOCK_NONE: clip.area = TREE_AREA_CONTENT; break; case COLUMN_LOCK_RIGHT: clip.area = TREE_AREA_RIGHT; break; } #else clipPtr = NULL; #endif TreeRect_SetXYWH(tr, x, y, width, height); /* * If the -backgroundimage is being drawn and is opaque, * there is no need to erase first (unless it doesn't tile!). */ if (!Tree_IsBgImageOpaque(tree)) { tc = TreeColumn_BackgroundColor(treeColumn, index); if (tc != NULL) { TreeRectangle trBrush; TreeColor_GetBrushBounds(tree, tc, tr, tree->drawableXOrigin, tree->drawableYOrigin, treeColumn, item, &trBrush); if (!TreeColor_IsOpaque(tree, tc) || (trBrush.width <= 0) || (trBrush.height <= 0)) { GC gc = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC); Tree_FillRectangle(tree, td, clipPtr, gc, tr); } TreeColor_FillRect(tree, td, clipPtr, tc, trBrush, tr); } else { GC gc = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC); Tree_FillRectangle(tree, td, clipPtr, gc, tr); } } if (tree->backgroundImage != NULL) { Tree_DrawBgImage(tree, td, tr, tree->drawableXOrigin, tree->drawableYOrigin); } } /* *---------------------------------------------------------------------- * * TreeItem_SpansInvalidate -- * * Invalidates the Item.spans field of one or all items. * * Results: * The item(s) are removed from the TreeCtrl.itemSpansHash to * indicate that the list of spans must be recalculated. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_SpansInvalidate( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. NULL for all items. */ ) { Tcl_HashEntry *hPtr; Tcl_HashSearch search; int count = 0; if (item == NULL) { hPtr = Tcl_FirstHashEntry(&tree->itemSpansHash, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashKey(&tree->itemSpansHash, hPtr); item->flags &= ~ITEM_FLAG_SPANS_VALID; count++; hPtr = Tcl_NextHashEntry(&search); } if (count) { Tcl_DeleteHashTable(&tree->itemSpansHash); Tcl_InitHashTable(&tree->itemSpansHash, TCL_ONE_WORD_KEYS); } } else if (item->flags & ITEM_FLAG_SPANS_VALID) { hPtr = Tcl_FindHashEntry(&tree->itemSpansHash, (char *) item); Tcl_DeleteHashEntry(hPtr); item->flags &= ~ITEM_FLAG_SPANS_VALID; count++; } if (count && tree->debug.enable && tree->debug.span) dbwin("TreeItem_SpansInvalidate forgot %d items\n", count); TreeColumns_InvalidateSpans(tree); /* FIXME: only if item visible? */ } /* *---------------------------------------------------------------------- * * TreeItem_SpansRedo -- * * Updates the Item.spans field of an item. * * Results: * Item.spans is resized if needed to (at least) the current number * of tree columns. For tree column N, the index of the item * column displayed there is written to spans[N]. * * The return value is 1 if every span is 1, otherwise 0. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ int TreeItem_SpansRedo( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { TreeColumn treeColumn = tree->columns; TreeItemColumn itemColumn = item->columns; int columnCount = tree->columnCount + (item->header ? 1 : 0); int columnIndex = 0, spanner = 0, span = 1, simple = TRUE; int lock = TreeColumn_Lock(treeColumn); if (tree->debug.enable && tree->debug.span) dbwin("TreeItem_SpansRedo %s %d\n", item->header ? "header" : "item", item->id); if (item->spans == NULL) { item->spans = (int *) ckalloc(sizeof(int) * columnCount); item->spanAlloc = columnCount; } else if (item->spanAlloc < columnCount) { item->spans = (int *) ckrealloc((char *) item->spans, sizeof(int) * columnCount); item->spanAlloc = columnCount; } while (treeColumn != NULL) { /* End current span if column lock changes. */ if (TreeColumn_Lock(treeColumn) != lock) { lock = TreeColumn_Lock(treeColumn); span = 1; } if (--span == 0) { if (TreeColumn_Visible(treeColumn)) span = itemColumn ? itemColumn->span : 1; else span = 1; spanner = columnIndex; } if ((itemColumn != NULL) && (itemColumn->span > 1)) simple = FALSE; item->spans[columnIndex] = spanner; columnIndex++; treeColumn = TreeColumn_Next(treeColumn); if (itemColumn != NULL) itemColumn = itemColumn->next; } /* Add a span of 1 for the tail column if this is a header. */ if (item->header != NULL) { item->spans[columnCount - 1] = columnCount - 1; /* tail column */ } return simple; } /* *---------------------------------------------------------------------- * * TreeItem_SpansRedoIfNeeded -- * * Updates the Item.spans field of an item if needed. * * Results: * If all spans are known to be 1, nothing is done. If the list of * spans is marked valid, nothing is done. Otherwise the list of * spans is recalculated; if any span is > 1 the item is added * to TreeCtrl.itemSpansHash. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ void TreeItem_SpansRedoIfNeeded( TreeCtrl *tree, TreeItem item ) { /* All the spans are 1. */ if (item->flags & ITEM_FLAG_SPANS_SIMPLE) return; /* Some spans > 1, but we calculated them already. */ if (item->flags & ITEM_FLAG_SPANS_VALID) return; if (TreeItem_SpansRedo(tree, item)) { /* Reverted to all spans=1. */ item->flags |= ITEM_FLAG_SPANS_SIMPLE; } else { int isNew; Tcl_HashEntry *hPtr; hPtr = Tcl_CreateHashEntry(&tree->itemSpansHash, (char *) item, &isNew); Tcl_SetHashValue(hPtr, (ClientData) item); item->flags |= ITEM_FLAG_SPANS_VALID; } } /* *---------------------------------------------------------------------- * * TreeItem_GetSpans -- * * Returns the spans[] array for an item. * * Results: * If all spans are known to be 1, the result is NULL. Otherwise the * list of spans is returned. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ int * TreeItem_GetSpans( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { TreeItem_SpansRedoIfNeeded(tree, item); if (item->flags & ITEM_FLAG_SPANS_SIMPLE) return NULL; return item->spans; } /* * The following structure holds information about which item column * is displayed at a given tree column. */ typedef struct SpanInfo { TreeColumn treeColumn; /* Always non-null. */ TreeItemColumn itemColumn; /* May be null. */ int span; /* Number of tree-columns spanned. */ int width; /* Width of the span. */ int visIndex; /* 0-based index into list of * spans. Used by header items. */ int isDragColumn; /* TRUE if this span is for a column header * that is being dragged. */ } SpanInfo; typedef struct ColumnColumn { TreeColumn treeColumn; TreeItemColumn itemColumn; int isDragColumn; } ColumnColumn; typedef struct SpanInfoStack SpanInfoStack; struct SpanInfoStack { int spanCount; SpanInfo *spans; int columnCount; ColumnColumn *columns; int inUse; SpanInfoStack *next; }; /* *---------------------------------------------------------------------- * * Item_GetSpans -- * * Fills an array of SpanInfo records, one per visible span. * * Results: * The return value is the number of SpanInfo records written. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Item_GetSpans( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ TreeColumn firstColumn, /* Which columns. */ TreeColumn lastColumn, /* Which columns. */ int columnCount, SpanInfo spans[], /* Returned span records. */ #define WALKSPAN_IGNORE_DND 0 /* Ignore header drag-and-drop positions. */ #define WALKSPAN_ONLY_DRAGGED 0x01 /* Calculate the bounds of dragged headers * only considering -imageoffset. */ #define WALKSPAN_DRAG_ORDER 0x02 /* Calculate the bounds of all headers in * their current drag positions. */ #define WALKSPAN_IGNORE_DRAGGED 0x04 /* Don't call the callback routine for * dragged headers. */ int dragPosition ) { /* Note: getting head of the stack, that's ok since this routine isn't * in danger of being called recursively. */ SpanInfoStack *siStack = tree->itemSpanPriv; ColumnColumn *columns = siStack->columns; TreeColumn treeColumn = firstColumn; int columnIndex = TreeColumn_Index(firstColumn); TreeItemColumn column = TreeItem_FindColumn(tree, item, columnIndex); int spanCount = 0, span = 1; SpanInfo *spanPtr = NULL; int i, isDragColumn; if ((item->header == NULL) && (dragPosition & WALKSPAN_ONLY_DRAGGED)) return 0; if ((columns == NULL) || (siStack->columnCount < tree->columnCount + 1)) { columns = (ColumnColumn *) ckrealloc((char *) columns, sizeof(ColumnColumn) * (tree->columnCount + 1)); siStack->columnCount = tree->columnCount + 1; siStack->columns = columns; } #ifdef TREECTRL_DEBUG for (i = 0; i < tree->columnCount + 1; i++) { columns[i].treeColumn = NULL; columns[i].itemColumn = NULL; } #endif columnCount = 0; while (treeColumn != NULL) { if (TreeColumn_Lock(treeColumn) != TreeColumn_Lock(firstColumn)) break; columnIndex = columnCount; isDragColumn = 0; if ((item->header != NULL) && (dragPosition != WALKSPAN_IGNORE_DND)) { if (dragPosition & WALKSPAN_DRAG_ORDER) { isDragColumn = TreeHeader_IsDraggedColumn(item->header, treeColumn); columnIndex = TreeHeader_ColumnDragOrder(item->header, treeColumn, columnIndex); } if (dragPosition & WALKSPAN_ONLY_DRAGGED) isDragColumn = 1; } #ifdef TREECTRL_DEBUG if (columnIndex < 0 || columnIndex >= siStack->columnCount) panic("Item_GetSpans columnIndex %d columnCount %d", columnIndex, siStack->columnCount); #endif columns[columnIndex].treeColumn = treeColumn; columns[columnIndex].itemColumn = column; columns[columnIndex].isDragColumn = isDragColumn; columnCount++; if (treeColumn == lastColumn) /* FIXME: lastColumn is usually NULL */ break; treeColumn = Tree_ColumnToTheRight(treeColumn, TRUE, item->header != NULL); if (column != NULL) column = column->next; if (treeColumn == tree->columnTail) { while (column != NULL && column->next != NULL) column = column->next; } } isDragColumn = columns[0].isDragColumn; for (i = 0; i < columnCount; i++) { treeColumn = columns[i].treeColumn; column = columns[i].itemColumn; if (isDragColumn != columns[i].isDragColumn) span = 1; isDragColumn = columns[i].isDragColumn; if (treeColumn == tree->columnTail) { span = 1; /* End the current span if it hits the tail. */ } if (--span == 0) { /* Always create a span for the tail column in headers */ if ((treeColumn == tree->columnTail) || TreeColumn_Visible(treeColumn)) { span = column ? column->span : 1; if (spanPtr == NULL) spanPtr = spans; else spanPtr++; spanPtr->treeColumn = treeColumn; spanPtr->itemColumn = column; spanPtr->span = 0; spanPtr->width = 0; if (!(dragPosition & WALKSPAN_ONLY_DRAGGED) && (item->header != NULL) && (spanCount == 0) && (TreeColumn_Lock(treeColumn) == COLUMN_LOCK_NONE)) { spanPtr->width += tree->canvasPadX[PAD_TOP_LEFT]; } spanPtr->visIndex = spanCount; spanPtr->isDragColumn = isDragColumn; spanCount++; } else { span = 1; continue; } } spanPtr->span++; if (treeColumn == tree->columnTail) { spanPtr->width = 100; /* TreeItem_WalkSpans will calculate the correct value */ } else { spanPtr->width += TreeColumn_UseWidth(treeColumn); } } return spanCount; } typedef int (*TreeItemWalkSpansProc)( TreeCtrl *tree, TreeItem item, SpanInfo *spanPtr, StyleDrawArgs *drawArgs, ClientData clientData ); /* *---------------------------------------------------------------------- * * TreeItem_WalkSpans -- * * Iterates over the spans of an item and calls a callback routine * for each span of non-zero width. This is used for drawing, * hit-testing and other purposes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void TreeItem_WalkSpans( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int lock, /* Which columns. */ int x, int y, /* Drawable coordinates of the item. */ int width, int height, /* Total size of the item. */ int dragPosition, TreeItemWalkSpansProc proc, /* Callback routine. */ ClientData clientData /* Data passed to callback routine. */ ) { SpanInfoStack *siStack = tree->itemSpanPriv; int columnWidth, totalWidth; TreeItemColumn itemColumn; StyleDrawArgs drawArgs; TreeColumn treeColumn = tree->columnLockNone, treeColumnLast = NULL; int spanCount, spanIndex, columnCount = tree->columnCountVis; SpanInfo *spans; int area = TREE_AREA_CONTENT; switch (lock) { case COLUMN_LOCK_LEFT: treeColumn = tree->columnLockLeft; columnCount = tree->columnCountVisLeft; area = TREE_AREA_LEFT; break; case COLUMN_LOCK_NONE: break; case COLUMN_LOCK_RIGHT: treeColumn = tree->columnLockRight; columnCount = tree->columnCountVisRight; area = TREE_AREA_RIGHT; break; } if (item->header != NULL) { switch (lock) { case COLUMN_LOCK_LEFT: area = TREE_AREA_HEADER_LEFT; break; case COLUMN_LOCK_NONE: area = TREE_AREA_HEADER_NONE; if (treeColumn == NULL) treeColumn = tree->columnTail; columnCount += 1; /* +1 for columnTail */ break; case COLUMN_LOCK_RIGHT: area = TREE_AREA_HEADER_RIGHT; break; } if (dragPosition & WALKSPAN_ONLY_DRAGGED) { columnCount = TreeHeader_GetDraggedColumns(item->header, lock, &treeColumn, &treeColumnLast); if (columnCount == 0) return; } } if (columnCount <= 0) return; if (!Tree_AreaBbox(tree, area, &drawArgs.bounds)) { TreeRect_SetXYWH(drawArgs.bounds, 0, 0, 0, 0); } /* Originally, the array of SpanInfo records used by this function was * allocated using STATIC_ALLOC. Not wanting to allocate memory every * time this function is called (which is often) I decided to keep a * pointer to the array. One problem is that TreeItem_UpdateWindowPositions * may result in recursive calls to this function via code in * event scripts. So I have to keep a stack on the heap. That's also why * the array can't be shared by different treectrl widgets. */ if (siStack == NULL) { siStack = (SpanInfoStack *) ckalloc(sizeof(SpanInfoStack)); memset(siStack, '\0', sizeof(SpanInfoStack)); tree->itemSpanPriv = siStack; } while (siStack->inUse) { if (siStack->next == NULL) { siStack->next = (SpanInfoStack *) ckalloc(sizeof(SpanInfoStack)); memset(siStack->next, '\0', sizeof(SpanInfoStack)); siStack = siStack->next; break; } siStack = siStack->next; } if (siStack->spanCount < columnCount) { siStack->spans = (SpanInfo *) ckrealloc((char *) siStack->spans, sizeof(SpanInfo) * columnCount); siStack->spanCount = columnCount; } spans = siStack->spans; spanCount = Item_GetSpans(tree, item, treeColumn, treeColumnLast, columnCount, spans, dragPosition); if (spanCount <= 0) return; #ifdef TREECTRL_DEBUG if (siStack->inUse) panic("TreeItem_WalkSpans stack is in use"); #endif siStack->inUse = 1; drawArgs.tree = tree; drawArgs.item = item; /* needed for gradients */ drawArgs.td.drawable = None; totalWidth = 0; if (dragPosition & WALKSPAN_ONLY_DRAGGED) { #ifdef TREECTRL_DEBUG if (item->header == NULL) panic("TreeItem_WalkSpans header == NULL"); #endif treeColumn = spans[0].treeColumn; /* tree->columnDrag.column */ totalWidth = TreeColumn_Offset(treeColumn); } for (spanIndex = 0; spanIndex < spanCount; spanIndex++) { treeColumn = spans[spanIndex].treeColumn; itemColumn = spans[spanIndex].itemColumn; /* This is where the actual width of the tail column is determined. */ if (treeColumn == tree->columnTail) { spans[spanIndex].width = MAX(0, MAX(Tree_ContentWidth(tree), Tree_FakeCanvasWidth(tree)) - totalWidth) + tree->tailExtend; } if (item->header != NULL) { columnWidth = spans[spanIndex].width; /* If this is the single visible column, use the provided width which * may be different than the column's width. */ } else if ((tree->columnCountVis == 1) && (treeColumn == tree->columnVis)) { columnWidth = width; /* More than one column is visible, or this is not the visible * column. */ } else { columnWidth = spans[spanIndex].width; } if (columnWidth <= 0) continue; if ((dragPosition & WALKSPAN_IGNORE_DRAGGED) && spans[spanIndex].isDragColumn) goto next; if (itemColumn != NULL) { drawArgs.state = item->state | itemColumn->cstate; drawArgs.style = itemColumn->style; /* may be NULL */ } else { drawArgs.state = item->state; drawArgs.style = NULL; } if ((dragPosition & WALKSPAN_DRAG_ORDER) && (item->header != NULL)) { if ((spanIndex == 0) && (TreeColumn_Lock(treeColumn) == COLUMN_LOCK_NONE)) drawArgs.indent = tree->canvasPadX[PAD_TOP_LEFT]; else drawArgs.indent = 0; } else drawArgs.indent = TreeItem_Indent(tree, treeColumn, item); drawArgs.x = x + totalWidth; if (dragPosition & WALKSPAN_ONLY_DRAGGED) { #ifdef TREECTRL_DEBUG if (item->header == NULL) panic("TreeItem_WalkSpans header == NULL"); #endif drawArgs.x += tree->columnDrag.offset; drawArgs.indent = 0; } drawArgs.y = y; drawArgs.width = columnWidth; drawArgs.height = height; drawArgs.spanIndex = spanIndex; if (item->header != NULL) drawArgs.justify = TreeHeaderColumn_Justify(item->header, itemColumn->headerColumn); else drawArgs.justify = TreeColumn_ItemJustify(treeColumn); drawArgs.column = treeColumn; /* needed for gradients */ if ((*proc)(tree, item, &spans[spanIndex], &drawArgs, clientData)) break; next: totalWidth += columnWidth; } siStack->inUse = 0; } /* *---------------------------------------------------------------------- * * SpanWalkProc_Draw -- * * Callback routine to TreeItem_WalkSpans for TreeItem_Draw. * * Results: * None. * * Side effects: * Stuff is drawn in a drawable. * *---------------------------------------------------------------------- */ static int SpanWalkProc_Draw( TreeCtrl *tree, TreeItem item, SpanInfo *spanPtr, StyleDrawArgs *drawArgs, ClientData clientData ) { TreeColumn treeColumn = spanPtr->treeColumn; TreeItemColumn itemColumn = spanPtr->itemColumn; #if COLUMNGRID == 1 TreeColor *leftColor, *rightColor; int leftWidth, rightWidth; #endif int i, x; struct { TreeDrawable td; int minX; int maxX; int index; int dragPosition; } *data = clientData; /* Draw nothing if the entire span is out-of-bounds. */ if ((drawArgs->x >= data->maxX) || (drawArgs->x + drawArgs->width <= data->minX)) return 0; drawArgs->td = data->td; if (item->header != NULL) { TreeHeaderColumn_Draw(item->header, itemColumn ? itemColumn->headerColumn : NULL, spanPtr->visIndex, drawArgs, data->dragPosition); return drawArgs->x + drawArgs->width >= data->maxX; } /* Draw background colors. */ if (spanPtr->span == 1) { /* Important point: use drawArgs->width since an item's width may * be totally different than tree->columnVis' width. */ ItemDrawBackground(tree, treeColumn, item, itemColumn, drawArgs->td, drawArgs->x, drawArgs->y, drawArgs->width, drawArgs->height, data->index); } else { x = drawArgs->x; for (i = 0; i < spanPtr->span; i++) { int columnWidth = TreeColumn_UseWidth(treeColumn); if ((columnWidth > 0) && (x < data->maxX) && (x + columnWidth > data->minX)) { ItemDrawBackground(tree, treeColumn, item, itemColumn, drawArgs->td, x, drawArgs->y, columnWidth, drawArgs->height, data->index); } x += columnWidth; treeColumn = TreeColumn_Next(treeColumn); } } if (drawArgs->style != NULL) { StyleDrawArgs drawArgsCopy = *drawArgs; TreeStyle_Draw(&drawArgsCopy); } #if COLUMNGRID == 1 if (TreeColumn_GridColors(spanPtr->treeColumn, &leftColor, &rightColor, &leftWidth, &rightWidth) != 0) { TreeRectangle tr, trBrush; if (leftColor != NULL && leftWidth > 0) { TreeRect_SetXYWH(tr, drawArgs->x, drawArgs->y, leftWidth, drawArgs->height); TreeColor_GetBrushBounds(tree, leftColor, tr, tree->drawableXOrigin, tree->drawableYOrigin, spanPtr->treeColumn, item, &trBrush); TreeColor_FillRect(tree, data->td, NULL, leftColor, trBrush, tr); } if (rightColor != NULL && rightWidth > 0) { TreeRect_SetXYWH(tr, drawArgs->x + drawArgs->width - rightWidth, drawArgs->y, rightWidth, drawArgs->height); TreeColor_GetBrushBounds(tree, rightColor, tr, tree->drawableXOrigin, tree->drawableYOrigin, spanPtr->treeColumn, item, &trBrush); TreeColor_FillRect(tree, data->td, NULL, rightColor, trBrush, tr); } } #endif if (spanPtr->treeColumn == tree->columnTree) { if (tree->showLines) TreeItem_DrawLines(tree, item, drawArgs->x, drawArgs->y, drawArgs->width, drawArgs->height, data->td, drawArgs->style); if (tree->showButtons) TreeItem_DrawButton(tree, item, drawArgs->x, drawArgs->y, drawArgs->width, drawArgs->height, data->td, drawArgs->style); } /* Stop walking if we went past the right edge of the dirty area. */ return drawArgs->x + drawArgs->width >= data->maxX; } /* *---------------------------------------------------------------------- * * TreeItem_Draw -- * * Draws part of an Item. * * Results: * None. * * Side effects: * Stuff is drawn in a drawable. * *---------------------------------------------------------------------- */ void TreeItem_Draw( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int lock, /* Which columns. */ int x, int y, /* Drawable coordinates of the item. */ int width, int height, /* Total size of the item. */ TreeDrawable td, /* Where to draw. */ int minX, int maxX, /* Left/right edge that needs to be drawn. */ int index /* Used to select a color from a * tree-column's -itembackground option. */ ) { struct { TreeDrawable td; int minX; int maxX; int index; int dragPosition; } clientData; clientData.td = td; clientData.minX = minX; clientData.maxX = maxX; clientData.index = index; clientData.dragPosition = FALSE; TreeItem_WalkSpans(tree, item, lock, x, y, width, height, WALKSPAN_DRAG_ORDER, SpanWalkProc_Draw, (ClientData) &clientData); if (item->header != NULL) { clientData.dragPosition = TRUE; TreeItem_WalkSpans(tree, item, lock, x, y, width, height, WALKSPAN_ONLY_DRAGGED, SpanWalkProc_Draw, (ClientData) &clientData); } } /* *---------------------------------------------------------------------- * * TreeItem_DrawLines -- * * Draws horizontal and vertical lines indicating parent-child * relationship in an item. * * Results: * None. * * Side effects: * Stuff is drawn in a drawable. * *---------------------------------------------------------------------- */ void TreeItem_DrawLines( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int x, int y, /* Drawable coordinates of columnTree. */ int width, int height, /* Total size of columnTree. */ TreeDrawable td, /* Where to draw. */ TreeStyle style /* Instance style or NULL. Used to get * optional vertical offset of the button. */ ) { TreeItem parent, walk; int buttonY = -1; int indent, left, lineLeft, lineTop; int hasPrev, hasNext; int i, vert = 0; indent = TreeItem_Indent(tree, tree->columnTree, item); if (style != NULL) buttonY = TreeStyle_GetButtonY(tree, style); /* Left edge of button/line area */ left = x /* + tree->columnTreeLeft */ + indent - tree->useIndent; /* Left edge of vertical line */ lineLeft = left + (tree->useIndent - tree->lineThickness) / 2; /* Top edge of horizontal line */ if (buttonY < 0) lineTop = y + (height - tree->lineThickness) / 2; else lineTop = y + buttonY + (tree->buttonHeightMax - tree->lineThickness) / 2; /* NOTE: The next three checks do not call TreeItem_ReallyVisible() * since 'item' is ReallyVisible */ /* Check for ReallyVisible previous sibling */ walk = item->prevSibling; while ((walk != NULL) && !IS_VISIBLE(walk)) walk = walk->prevSibling; hasPrev = (walk != NULL); /* Check for ReallyVisible parent */ if ((item->parent != NULL) && (!IS_ROOT(item->parent) || tree->showRoot)) hasPrev = TRUE; /* Check for ReallyVisible next sibling */ walk = item->nextSibling; while ((walk != NULL) && !IS_VISIBLE(walk)) walk = walk->nextSibling; hasNext = (walk != NULL); /* Option: Don't connect children of root item */ if ((item->parent != NULL) && IS_ROOT(item->parent) && !tree->showRootLines) hasPrev = hasNext = FALSE; /* Vertical line to parent and/or previous/next sibling */ if (hasPrev || hasNext) { int top = y, bottom = y + height; if (!hasPrev) top = lineTop; if (!hasNext) bottom = lineTop + tree->lineThickness; if (tree->lineStyle == LINE_STYLE_DOT) { for (i = 0; i < tree->lineThickness; i++) { Tree_VDotLine(tree, td.drawable, lineLeft + i, top, bottom); } } else { XFillRectangle(tree->display, td.drawable, tree->lineGC[0], lineLeft, top, tree->lineThickness, bottom - top); } /* Don't overlap horizontal line */ vert = tree->lineThickness; } /* Horizontal line to self */ if (hasPrev || hasNext) { if (tree->lineStyle == LINE_STYLE_DOT) { for (i = 0; i < tree->lineThickness; i++) { Tree_HDotLine(tree, td.drawable, lineLeft + vert, lineTop + i, x /* + tree->columnTreeLeft */ + indent); } } else { XFillRectangle(tree->display, td.drawable, tree->lineGC[0], lineLeft + vert, lineTop, left + tree->useIndent - (lineLeft + vert), tree->lineThickness); } } /* Vertical lines from ancestors to their next siblings */ for (parent = item->parent; parent != NULL; parent = parent->parent) { lineLeft -= tree->useIndent; /* Option: Don't connect children of root item */ if ((parent->parent != NULL) && IS_ROOT(parent->parent) && !tree->showRootLines) continue; /* Check for ReallyVisible next sibling */ item = parent->nextSibling; while ((item != NULL) && !IS_VISIBLE(item)) item = item->nextSibling; if (item != NULL) { if (tree->lineStyle == LINE_STYLE_DOT) { for (i = 0; i < tree->lineThickness; i++) { Tree_VDotLine(tree, td.drawable, lineLeft + i, y, y + height); } } else { XFillRectangle(tree->display, td.drawable, tree->lineGC[0], lineLeft, y, tree->lineThickness, height); } } } } /* *---------------------------------------------------------------------- * * TreeItem_DrawButton -- * * Draws the button (if any) in an item. * * Results: * None. * * Side effects: * Stuff is drawn in a drawable. * *---------------------------------------------------------------------- */ void TreeItem_DrawButton( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int x, int y, /* Drawable coordinates of columnTree. */ int width, int height, /* Total size of columnTree. */ TreeDrawable td, /* Where to draw. */ TreeStyle style /* Instance style or NULL. Used to get * optional vertical offset of the button. */ ) { int indent, left, lineLeft, lineTop; int buttonLeft, buttonTop, buttonY = -1, w1; Tk_Image image; Pixmap bitmap; if (!TreeItem_HasButton(tree, item)) return; indent = TreeItem_Indent(tree, tree->columnTree, item); if (style != NULL) buttonY = TreeStyle_GetButtonY(tree, style); /* Left edge of button/line area */ left = x /* + tree->columnTreeLeft */ + indent - tree->useIndent; image = PerStateImage_ForState(tree, &tree->buttonImage, item->state, NULL); if (image != NULL) { int imgW, imgH; Tk_SizeOfImage(image, &imgW, &imgH); if (buttonY < 0) buttonY = (height - imgH) / 2; Tree_RedrawImage(image, 0, 0, imgW, imgH, td, left + (tree->useIndent - imgW) / 2, y + buttonY); return; } bitmap = PerStateBitmap_ForState(tree, &tree->buttonBitmap, item->state, NULL); if (bitmap != None) { int bmpW, bmpH; int bx, by; Tk_SizeOfBitmap(tree->display, bitmap, &bmpW, &bmpH); if (buttonY < 0) buttonY = (height - bmpH) / 2; bx = left + (tree->useIndent - bmpW) / 2; by = y + buttonY; Tree_DrawBitmap(tree, bitmap, td.drawable, NULL, NULL, 0, 0, (unsigned int) bmpW, (unsigned int) bmpH, bx, by); return; } if (tree->useTheme) { int bw, bh; int buttonState = item->state; /* FIXME: These may overwrite [state define] states */ buttonState &= ~ITEM_FLAGS_BUTTONSTATE; if (item->flags & ITEM_FLAG_BUTTONSTATE_ACTIVE) buttonState |= BUTTON_STATE_ACTIVE; if (item->flags & ITEM_FLAG_BUTTONSTATE_PRESSED) buttonState |= BUTTON_STATE_PRESSED; if (TreeTheme_GetButtonSize(tree, td.drawable, (buttonState & STATE_ITEM_OPEN) != 0, &bw, &bh) == TCL_OK) { if (buttonY < 0) buttonY = (height - bh) / 2; if (TreeTheme_DrawButton(tree, td, item, buttonState, left + (tree->useIndent - bw) / 2, y + buttonY, bw, bh) == TCL_OK) { return; } } } w1 = tree->buttonThickness / 2; /* Left edge of vertical line */ /* Make sure this matches TreeItem_DrawLines() */ lineLeft = left + (tree->useIndent - tree->buttonThickness) / 2; /* Top edge of horizontal line */ /* Make sure this matches TreeItem_DrawLines() */ if (buttonY < 0) lineTop = y + (height - tree->lineThickness) / 2; else lineTop = y + buttonY + (tree->buttonHeightMax - tree->lineThickness) / 2; buttonLeft = left + (tree->useIndent - tree->buttonSize) / 2; if (buttonY < 0) buttonTop = y + (height - tree->buttonSize) / 2; else buttonTop = y + buttonY + (tree->buttonHeightMax - tree->buttonSize) / 2; /* Erase button background */ XFillRectangle(tree->display, td.drawable, Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC), buttonLeft + tree->buttonThickness, buttonTop + tree->buttonThickness, tree->buttonSize - tree->buttonThickness, tree->buttonSize - tree->buttonThickness); /* Draw button outline */ XDrawRectangle(tree->display, td.drawable, tree->buttonGC, buttonLeft + w1, buttonTop + w1, tree->buttonSize - tree->buttonThickness, tree->buttonSize - tree->buttonThickness); /* Horizontal '-' */ XFillRectangle(tree->display, td.drawable, tree->buttonGC, buttonLeft + tree->buttonThickness * 2, lineTop, tree->buttonSize - tree->buttonThickness * 4, tree->buttonThickness); if (!(item->state & STATE_ITEM_OPEN)) { /* Finish '+' */ XFillRectangle(tree->display, td.drawable, tree->buttonGC, lineLeft, buttonTop + tree->buttonThickness * 2, tree->buttonThickness, tree->buttonSize - tree->buttonThickness * 4); } } /* *---------------------------------------------------------------------- * * SpanWalkProc_UpdateWindowPositions -- * * Callback routine to TreeItem_WalkSpans for * TreeItem_UpdateWindowPositions. * * Results: * None. * * Side effects: * Windows in window elements may be resized/repositioned. * *---------------------------------------------------------------------- */ static int SpanWalkProc_UpdateWindowPositions( TreeCtrl *tree, TreeItem item, SpanInfo *spanPtr, StyleDrawArgs *drawArgs, ClientData clientData ) { StyleDrawArgs drawArgsCopy; int requests; if ((drawArgs->x >= TreeRect_Right(drawArgs->bounds)) || (drawArgs->x + drawArgs->width <= TreeRect_Left(drawArgs->bounds)) || (drawArgs->style == NULL)) return 0; TreeDisplay_GetReadyForTrouble(tree, &requests); drawArgsCopy = *drawArgs; TreeStyle_UpdateWindowPositions(&drawArgsCopy); if (TreeDisplay_WasThereTrouble(tree, requests)) return 1; /* Stop walking if we went past the right edge of the display area. */ return drawArgs->x + drawArgs->width >= TreeRect_Right(drawArgs->bounds); } /* *---------------------------------------------------------------------- * * TreeItem_UpdateWindowPositions -- * * Updates the geometry of any on-screen window elements. Called * by the display code when an item was possibly scrolled. * * Results: * None. * * Side effects: * Windows in window elements may be resized/repositioned. * *---------------------------------------------------------------------- */ void TreeItem_UpdateWindowPositions( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int lock, /* Columns we care about. */ int x, int y, /* Window coordinates of the item. */ int width, int height /* Total size of the item. */ ) { TreeItem_WalkSpans(tree, item, lock, x, y, width, height, WALKSPAN_DRAG_ORDER | WALKSPAN_IGNORE_DRAGGED, SpanWalkProc_UpdateWindowPositions, (ClientData) NULL); if (item->header != NULL) { TreeItem_WalkSpans(tree, item, lock, x, y, width, height, WALKSPAN_ONLY_DRAGGED, SpanWalkProc_UpdateWindowPositions, (ClientData) NULL); } } /* *---------------------------------------------------------------------- * * SpanWalkProc_GetOnScreenColumns -- * * Callback routine to TreeItem_WalkSpans for * TreeItem_GetOnScreenColumns. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SpanWalkProc_GetOnScreenColumns( TreeCtrl *tree, TreeItem item, SpanInfo *spanPtr, StyleDrawArgs *drawArgs, ClientData clientData ) { TreeColumnList *columns = clientData; if ((drawArgs->x >= TreeRect_Right(drawArgs->bounds)) || (drawArgs->x + drawArgs->width <= TreeRect_Left(drawArgs->bounds))) return 0; TreeColumnList_Append(columns, drawArgs->column); /* Stop walking if we went past the right edge of the display area. */ return drawArgs->x + drawArgs->width >= TreeRect_Right(drawArgs->bounds); } /* *---------------------------------------------------------------------- * * TreeItem_GetOnScreenColumns -- * * Get a list of onscreen columns for an item. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_GetOnScreenColumns( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int lock, /* Which columns. */ int x, int y, /* Drawable coordinates of the item. */ int width, int height, /* Total size of the item. */ TreeColumnList *columns /* Out: list of onscreen columns. */ ) { TreeItem_WalkSpans(tree, item, lock, x, y, width, height, WALKSPAN_DRAG_ORDER | WALKSPAN_IGNORE_DRAGGED, SpanWalkProc_GetOnScreenColumns, (ClientData) columns); if (item->header != NULL) { TreeItem_WalkSpans(tree, item, lock, x, y, width, height, WALKSPAN_ONLY_DRAGGED, SpanWalkProc_GetOnScreenColumns, (ClientData) columns); } } /* *---------------------------------------------------------------------- * * TreeItem_OnScreen -- * * Called by the display code when the item becomes visible * (i.e., actually displayed) or hidden. * * Results: * None. * * Side effects: * Windows in window elements may be mapped/unmapped. * *---------------------------------------------------------------------- */ void TreeItem_OnScreen( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int onScreen /* TRUE if item is displayed. */ ) { #if 0 TreeItemColumn column = item->columns; while (column != NULL) { if (column->style != NULL) { TreeStyle_OnScreen(tree, column->style, onScreen); } column = column->next; } #endif } /* *---------------------------------------------------------------------- * * TreeItem_ReallyVisible -- * * Return whether the given Item could be displayed. * * Results: * TRUE if the item's -visible is TRUE, all of its ancestors' * -visible options are TRUE, and all of its ancestors are open. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_ReallyVisible( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { TreeItem parent = item->parent; if (item->header != NULL) { if (!tree->showHeader || !IS_VISIBLE(item)) return 0; /* For compatibility, if there are no visible columns then don't * display the lone tail column. */ (void) TreeColumns_UpdateCounts(tree); if (tree->columnCountVis + tree->columnCountVisLeft + tree->columnCountVisRight == 0) return 0; return 1; } if (!tree->updateIndex) return item->indexVis != -1; if (!IS_VISIBLE(item)) return 0; if (parent == NULL) return IS_ROOT(item) ? tree->showRoot : 0; if (IS_ROOT(parent)) { if (!IS_VISIBLE(parent)) return 0; if (!tree->showRoot) return 1; if (!(parent->state & STATE_ITEM_OPEN)) return 0; } if (!IS_VISIBLE(parent) || !(parent->state & STATE_ITEM_OPEN)) return 0; return TreeItem_ReallyVisible(tree, parent); } /* *---------------------------------------------------------------------- * * TreeItem_RootAncestor -- * * Return the toplevel ancestor of an Item. * * Results: * Returns the root, or an orphan ancestor, or the given Item. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeItem TreeItem_RootAncestor( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { while (item->parent != NULL) item = item->parent; return item; } /* *---------------------------------------------------------------------- * * TreeItem_IsAncestor -- * * Determine if one Item is the ancestor of another. * * Results: * TRUE if item1 is an ancestor of item2. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_IsAncestor( TreeCtrl *tree, /* Widget info. */ TreeItem item1, /* Possible ancestor. */ TreeItem item2 /* Item to check ancestry of. */ ) { if (item1 == item2) return 0; while (item2 && item2 != item1) item2 = item2->parent; return item2 != NULL; } /* *---------------------------------------------------------------------- * * TreeItem_ToObj -- * * Convert an Item to a Tcl_Obj. * * Results: * A new Tcl_Obj representing the Item. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeItem_ToObj( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { if (tree->itemPrefixLen) { char buf[100 + TCL_INTEGER_SPACE]; (void) sprintf(buf, "%s%d", tree->itemPrefix, item->id); return Tcl_NewStringObj(buf, -1); } return Tcl_NewIntObj(item->id); } /* *---------------------------------------------------------------------- * * Item_Configure -- * * This procedure is called to process an objc/objv list, plus * the Tk option database, in order to configure (or reconfigure) * an Item. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then the interp's result contains an error message. * * Side effects: * Configuration information gets set for item; old resources get * freed, if there were any. * *---------------------------------------------------------------------- */ static int Item_Configure( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item to configure. */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Array of arguments */ ) { Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; int mask; int lastVisible = IS_VISIBLE(item); int lastWrap = IS_WRAP(item); for (error = 0; error <= 1; error++) { if (error == 0) { if (Tree_SetOptions(tree, STATE_DOMAIN_ITEM, item, tree->itemOptionTable, objc, objv, &savedOptions, &mask) != TCL_OK) { mask = 0; continue; } /* xxx */ Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); /* xxx */ Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } if (mask & ITEM_CONF_SIZE) { Tree_FreeItemDInfo(tree, item, NULL); Tree_DInfoChanged(tree, DINFO_REDO_RANGES); } if (mask & ITEM_CONF_BUTTON) { if (tree->columnTree != NULL) Tree_InvalidateItemDInfo(tree, tree->columnTree, item, NULL); } if ((mask & ITEM_CONF_VISIBLE) && (IS_VISIBLE(item) != lastVisible)) { /* Changing the visibility of an item can change the width of * any column. This is due to column expansion (a style may * be the widest in a column) or when any span > 1. */ TreeColumns_InvalidateWidthOfItems(tree, NULL); TreeColumns_InvalidateSpans(tree); /* If this is the last child, redraw the lines of the previous * sibling and all of its descendants because the line from * the previous sibling to us is appearing/disappearing. */ if ((item->prevSibling != NULL) && (item->nextSibling == NULL) && tree->showLines && (tree->columnTree != NULL)) { TreeItem last = item->prevSibling; while (last->lastChild != NULL) last = last->lastChild; Tree_InvalidateItemDInfo(tree, tree->columnTree, item->prevSibling, last); } /* Redraw the parent if the parent has "-button auto". */ if ((item->parent != NULL) && (item->parent->flags & ITEM_FLAG_BUTTON_AUTO) && tree->showButtons && (tree->columnTree != NULL)) { Tree_InvalidateItemDInfo(tree, tree->columnTree, item->parent, NULL); } tree->updateIndex = 1; Tree_DInfoChanged(tree, DINFO_REDO_RANGES | DINFO_REDO_SELECTION); } if ((mask & ITEM_CONF_WRAP) && (IS_WRAP(item) != lastWrap)) { tree->updateIndex = 1; TreeColumns_InvalidateWidthOfItems(tree, NULL); Tree_DInfoChanged(tree, DINFO_REDO_RANGES); } return TCL_OK; } /* *---------------------------------------------------------------------- * * NoStyleMsg -- * * Utility to set the interpreter result with a message indicating * a Column has no assigned style. * * Results: * None. * * Side effects: * Interpreter result is changed. * *---------------------------------------------------------------------- */ static void NoStyleMsg( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item record. */ int columnIndex /* 0-based index of the column that * has no style. */ ) { FormatResult(tree->interp, "%s %s%d column %s%d has no style", item->header ? "header" : "item", item->header ? "" : tree->itemPrefix, item->id, tree->columnPrefix, TreeColumn_GetID(Tree_FindColumn(tree, columnIndex))); } /* *---------------------------------------------------------------------- * * StateDomainErrMsg -- * * Utility to set the interpreter result with a message indicating * a style's state-domain isn't compatible. * * Results: * Interpreter result is changed. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void StateDomainErrMsg( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item record. */ TreeStyle style /* Style token. */ ) { FormatResult(tree->interp, "state domain conflict between %s \"%s%d\" and style \"%s\"", item->header ? "header" : "item", item->header ? "" : tree->itemPrefix, item->id, TreeStyle_GetName(tree, style)); } /* *---------------------------------------------------------------------- * * TreeItemCmd_Bbox -- * * This procedure is invoked to process the [item bbox] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeItemCmd_Bbox( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int doHeaders /* TRUE to operate on headers, FALSE * to operate on items. */ ) { Tcl_Interp *interp = tree->interp; TreeItem item; int count; TreeColumn treeColumn; TreeRectangle rect; if (objc < 4 || objc > 6) { Tcl_WrongNumArgs(interp, 3, objv, doHeaders ? "header ?column? ?element?" : "item ?column? ?element?"); return TCL_ERROR; } if (doHeaders) { TreeHeader header; if (TreeHeader_FromObj(tree, objv[3], &header) != TCL_OK) return TCL_ERROR; item = TreeHeader_GetItem(header); } else { if (TreeItem_FromObj(tree, objv[3], &item, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; } (void) Tree_GetOriginX(tree); (void) Tree_GetOriginY(tree); if (objc == 4) { /* If an item is visible but has zero height a valid bbox * is returned. */ if (Tree_ItemBbox(tree, item, COLUMN_LOCK_NONE, &rect) < 0) return TCL_OK; if (doHeaders) rect.width -= tree->tailExtend; } else { if (TreeColumn_FromObj(tree, objv[4], &treeColumn, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) return TCL_ERROR; /* Bounds of a column. */ if (objc == 5) { objc = 0; objv = NULL; /* Single element in a column. */ } else { TreeItemColumn column; TreeElement elem; objc -= 5; objv += 5; /* Validate the style + element here. If a span has zero size * it won't be done. */ column = TreeItem_FindColumn(tree, item, TreeColumn_Index(treeColumn)); if (column == NULL || column->style == NULL || TreeStyle_IsHeaderStyle(tree, column->style)) { NoStyleMsg(tree, item, TreeColumn_Index(treeColumn)); return TCL_ERROR; } if (TreeElement_FromObj(tree, objv[0], &elem) != TCL_OK) return TCL_ERROR; if (TreeStyle_FindElement(tree, column->style, elem, NULL) != TCL_OK) return TCL_ERROR; } count = TreeItem_GetRects(tree, item, treeColumn, objc, objv, &rect); if (count == 0) return TCL_OK; if (count == -1) return TCL_ERROR; } /* Canvas -> window coordinates */ FormatResult(interp, "%d %d %d %d", TreeRect_Left(rect) - tree->xOrigin, TreeRect_Top(rect) - tree->yOrigin, TreeRect_Left(rect) - tree->xOrigin + TreeRect_Width(rect), TreeRect_Top(rect) - tree->yOrigin + TreeRect_Height(rect)); return TCL_OK; } static int ItemBboxCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; return TreeItemCmd_Bbox(tree, objc, objv, FALSE); } /* *---------------------------------------------------------------------- * * ItemCreateCmd -- * * This procedure is invoked to process the [item create] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int ItemCreateCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; static CONST char *optionNames[] = { "-button", "-count", "-enabled", "-height", "-nextsibling", "-open", "-parent", "-prevsibling", "-returnid", "-tags", "-visible", "-wrap", (char *) NULL }; enum { OPT_BUTTON, OPT_COUNT, OPT_ENABLED, OPT_HEIGHT, OPT_NEXTSIBLING, OPT_OPEN, OPT_PARENT, OPT_PREVSIBLING, OPT_RETURNID, OPT_TAGS, OPT_VISIBLE, OPT_WRAP }; int index, i, count = 1, button = 0, returnId = 1, open = 1, visible = 1; int enabled = 1, wrap = 0, height = 0; TreeItem item, parent = NULL, prevSibling = NULL, nextSibling = NULL; TreeItem head = NULL, tail = NULL; Tcl_Obj *listObj = NULL, *tagsObj = NULL; TagInfo *tagInfo = NULL; TreeColumn treeColumn; for (i = 3; i < objc; i += 2) { if (Tcl_GetIndexFromObj(interp, objv[i], optionNames, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } if (i + 1 == objc) { FormatResult(interp, "missing value for \"%s\" option", optionNames[index]); return TCL_ERROR; } switch (index) { case OPT_BUTTON: { int length; char *s = Tcl_GetStringFromObj(objv[i + 1], &length); if (s[0] == 'a' && strncmp(s, "auto", length) == 0) { button = ITEM_FLAG_BUTTON_AUTO; } else { if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &button) != TCL_OK) { FormatResult(interp, "expected boolean or auto but got \"%s\"", s); return TCL_ERROR; } if (button) { button = ITEM_FLAG_BUTTON; } } break; } case OPT_COUNT: if (Tcl_GetIntFromObj(interp, objv[i + 1], &count) != TCL_OK) return TCL_ERROR; if (count <= 0) { FormatResult(interp, "bad count \"%d\": must be > 0", count); return TCL_ERROR; } break; case OPT_ENABLED: if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &enabled) != TCL_OK) { return TCL_ERROR; } break; case OPT_HEIGHT: if (Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], &height) != TCL_OK) return TCL_ERROR; if (height < 0) { FormatResult(interp, "bad screen distance \"%s\": must be > 0", Tcl_GetString(objv[i + 1])); return TCL_ERROR; } break; case OPT_NEXTSIBLING: if (TreeItem_FromObj(tree, objv[i + 1], &nextSibling, IFO_NOT_NULL | IFO_NOT_ROOT | IFO_NOT_ORPHAN) != TCL_OK) { return TCL_ERROR; } parent = prevSibling = NULL; break; case OPT_OPEN: if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &open) != TCL_OK) { return TCL_ERROR; } break; case OPT_PARENT: if (TreeItem_FromObj(tree, objv[i + 1], &parent, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } prevSibling = nextSibling = NULL; break; case OPT_PREVSIBLING: if (TreeItem_FromObj(tree, objv[i + 1], &prevSibling, IFO_NOT_NULL | IFO_NOT_ROOT | IFO_NOT_ORPHAN) != TCL_OK) { return TCL_ERROR; } parent = nextSibling = NULL; break; case OPT_RETURNID: if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &returnId) != TCL_OK) { return TCL_ERROR; } break; case OPT_TAGS: tagsObj = objv[i + 1]; break; case OPT_VISIBLE: if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &visible) != TCL_OK) { return TCL_ERROR; } break; case OPT_WRAP: if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &wrap) != TCL_OK) { return TCL_ERROR; } break; } } /* Do it here so I don't have to free it above if an error occurs. */ if (tagsObj != NULL) { if (TagInfo_FromObj(tree, tagsObj, &tagInfo) != TCL_OK) return TCL_ERROR; } if (returnId) listObj = Tcl_NewListObj(0, NULL); /* Don't allow non-deleted items to become children of a * deleted item. */ if ((parent && IS_DELETED(parent)) || (prevSibling && IS_DELETED(prevSibling->parent)) || (nextSibling && IS_DELETED(nextSibling->parent))) parent = prevSibling = nextSibling = NULL; for (i = 0; i < count; i++) { item = Item_Alloc(tree, FALSE); item->flags &= ~(ITEM_FLAG_BUTTON | ITEM_FLAG_BUTTON_AUTO); item->flags |= button; if (enabled) item->state |= STATE_ITEM_ENABLED; else item->state &= ~STATE_ITEM_ENABLED; if (open) item->state |= STATE_ITEM_OPEN; else item->state &= ~STATE_ITEM_OPEN; if (visible) item->flags |= ITEM_FLAG_VISIBLE; else item->flags &= ~ITEM_FLAG_VISIBLE; if (wrap) item->flags |= ITEM_FLAG_WRAP; else item->flags &= ~ITEM_FLAG_WRAP; item->fixedHeight = height; /* Apply each column's -itemstyle option. */ for (treeColumn = tree->columns; treeColumn != NULL; treeColumn = TreeColumn_Next(treeColumn)) { TreeStyle style = TreeColumn_ItemStyle(treeColumn); if (style != NULL) { TreeItemColumn column = Item_CreateColumn(tree, item, TreeColumn_Index(treeColumn), NULL); column->style = TreeStyle_NewInstance(tree, style); } } #ifdef DEPRECATED /* Apply default styles */ if (tree->defaultStyle.numStyles) { int i, n = MIN(tree->columnCount, tree->defaultStyle.numStyles); for (i = 0; i < n; i++) { TreeItemColumn column = Item_CreateColumn(tree, item, i, NULL); if (column->style != NULL) continue; if (tree->defaultStyle.styles[i] != NULL) { column->style = TreeStyle_NewInstance(tree, tree->defaultStyle.styles[i]); } } } #endif /* DEPRECATED */ if (tagInfo != NULL) { if (count == 1) { item->tagInfo = tagInfo; tagInfo = NULL; } else { item->tagInfo = TagInfo_Copy(tree, tagInfo); } } /* Link the new items together as siblings */ if (parent || prevSibling || nextSibling) { if (head == NULL) head = item; if (tail != NULL) { tail->nextSibling = item; item->prevSibling = tail; } tail = item; } if (returnId) Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, item)); } if (parent != NULL) { head->prevSibling = parent->lastChild; if (parent->lastChild != NULL) parent->lastChild->nextSibling = head; else parent->firstChild = head; parent->lastChild = tail; } else if (prevSibling != NULL) { parent = prevSibling->parent; if (prevSibling->nextSibling != NULL) prevSibling->nextSibling->prevSibling = tail; else parent->lastChild = tail; head->prevSibling = prevSibling; tail->nextSibling = prevSibling->nextSibling; prevSibling->nextSibling = head; } else if (nextSibling != NULL) { parent = nextSibling->parent; if (nextSibling->prevSibling != NULL) nextSibling->prevSibling->nextSibling = head; else parent->firstChild = head; head->prevSibling = nextSibling->prevSibling; tail->nextSibling = nextSibling; nextSibling->prevSibling = tail; } if (parent != NULL) { for (item = head; item != NULL; item = item->nextSibling) { item->parent = parent; item->depth = parent->depth + 1; } parent->numChildren += count; TreeItem_AddToParent(tree, head); } TagInfo_Free(tree, tagInfo); if (returnId) Tcl_SetObjResult(interp, listObj); return TCL_OK; } /* *---------------------------------------------------------------------- * * ItemElementCmd -- * * This procedure is invoked to process the [item element] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeItemCmd_Element( TreeCtrl *tree, int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int doHeaders /* TRUE to operate on headers, FALSE * to operate on items. */ ) { Tcl_Interp *interp = tree->interp; static CONST char *commandNames[] = { #ifdef DEPRECATED "actual", #endif "cget", "configure", "perstate", (char *) NULL }; enum { #ifdef DEPRECATED COMMAND_ACTUAL, #endif COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_PERSTATE }; int index; int columnIndex; TreeItemColumn column; TreeItemList itemList; TreeItem item; int flags = IFO_NOT_NULL; int result = TCL_OK; int tailFlag = doHeaders ? 0 : CFO_NOT_TAIL; /* styles allowed in tail? */ int domain = doHeaders ? STATE_DOMAIN_HEADER : STATE_DOMAIN_ITEM; if (objc < 7) { Tcl_WrongNumArgs(interp, 3, objv, doHeaders ? "command header column element ?arg ...?" : "command item column element ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[3], commandNames, "command", 0, &index) != TCL_OK) return TCL_ERROR; /* * [configure] without an option-value pair can operate on a single item * only. [cget] and [perstate] only operate on a single item. */ if ((index != COMMAND_CONFIGURE) || (objc < 9)) flags |= IFO_NOT_MANY; if (doHeaders) { if (TreeHeaderList_FromObj(tree, objv[4], &itemList, flags) != TCL_OK) { return TCL_ERROR; } } else { if (TreeItemList_FromObj(tree, objv[4], &itemList, flags) != TCL_OK) return TCL_ERROR; } item = TreeItemList_Nth(&itemList, 0); switch (index) { /* T item element perstate I C E option ?stateList? */ #ifdef DEPRECATED case COMMAND_ACTUAL: #endif case COMMAND_PERSTATE: { int state; if (objc < 8 || objc > 9) { Tcl_WrongNumArgs(tree->interp, 4, objv, doHeaders ? "header column element option ?stateList?" : "item column element option ?stateList?"); result = TCL_ERROR; break; } if (TreeItem_ColumnFromObj(tree, item, objv[5], &column, NULL, &columnIndex, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) { result = TCL_ERROR; break; } if ((column == NULL) || (column->style == NULL) || TreeStyle_IsHeaderStyle(tree, column->style)) { NoStyleMsg(tree, item, columnIndex); result = TCL_ERROR; break; } state = item->state | column->cstate; if (objc == 9) { int states[3]; if (Tree_StateFromListObj(tree, domain, objv[8], states, SFO_NOT_OFF | SFO_NOT_TOGGLE) != TCL_OK) { result = TCL_ERROR; break; } state = states[STATE_OP_ON]; } result = TreeStyle_ElementActual(tree, column->style, state, objv[6], objv[7]); break; } /* T item element cget I C E option */ case COMMAND_CGET: { if (objc != 8) { Tcl_WrongNumArgs(tree->interp, 4, objv, doHeaders ? "header column element option" : "item column element option"); result = TCL_ERROR; break; } if (TreeItem_ColumnFromObj(tree, item, objv[5], &column, NULL, &columnIndex, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) { result = TCL_ERROR; break; } if ((column == NULL) || (column->style == NULL) || TreeStyle_IsHeaderStyle(tree, column->style)) { NoStyleMsg(tree, item, columnIndex); result = TCL_ERROR; break; } result = TreeStyle_ElementCget(tree, item, column, column->style, objv[6], objv[7]); break; } /* T item element configure I C E ... */ case COMMAND_CONFIGURE: { struct columnObj { TreeColumnList columns; int isColumn; int numArgs; } staticCO[STATIC_SIZE], *co = staticCO; int i, index, indexElem, prevColumn; ItemForEach iter; /* If no option-value pair is given, we can't specify more than * one column. */ flags = CFO_NOT_NULL | tailFlag; if (objc < 9) flags |= CFO_NOT_MANY; STATIC_ALLOC(co, struct columnObj, objc); for (i = 5; i < objc; i++) { co[i].isColumn = FALSE; co[i].numArgs = -1; } indexElem = 6; /* Get the first column(s) */ i = indexElem - 1; if (TreeColumnList_FromObj(tree, objv[i], &co[i].columns, flags) != TCL_OK) { result = TCL_ERROR; break; } co[i].isColumn = TRUE; prevColumn = i; while (1) { int numArgs = 0; char breakChar = '\0'; /* Look for a + or , */ for (index = indexElem + 1; index < objc; index++) { if (numArgs % 2 == 0) { int length; char *s = Tcl_GetStringFromObj(objv[index], &length); if ((length == 1) && ((s[0] == '+') || (s[0] == ','))) { breakChar = s[0]; break; } } numArgs++; } /* Require at least one option-value pair if more than one * element is specified. */ if ((breakChar || indexElem != 6) && (numArgs < 2)) { FormatResult(interp, "missing option-value pair after element \"%s\"", Tcl_GetString(objv[indexElem])); result = TCL_ERROR; goto doneCONF; } co[indexElem].numArgs = numArgs; if (!breakChar) break; if (index == objc - 1) { FormatResult(interp, "missing %s after \"%c\"", (breakChar == '+') ? "element name" : "column", breakChar); result = TCL_ERROR; goto doneCONF; } /* + indicates start of another element */ if (breakChar == '+') { indexElem = index + 1; } /* , indicates start of another column */ else if (breakChar == ',') { co[prevColumn].numArgs = index - prevColumn; if (TreeColumnList_FromObj(tree, objv[index + 1], &co[index + 1].columns, CFO_NOT_NULL | tailFlag) != TCL_OK) { result = TCL_ERROR; goto doneCONF; } co[index + 1].isColumn = TRUE; prevColumn = index + 1; indexElem = index + 2; if (indexElem == objc) { FormatResult(interp, "missing element name after column \"%s\"", Tcl_GetString(objv[index + 1])); result = TCL_ERROR; goto doneCONF; } } } co[prevColumn].numArgs = index - prevColumn; ITEM_FOR_EACH(item, &itemList, NULL, &iter) { /* T item element configure I C E option value \ * + E option value , C E option value */ int iMask = 0; /* co[index].numArgs is the number of arguments from the C * to the next separator (but not including that separator). */ for (index = 5; index < objc; index += co[index].numArgs + 1) { ColumnForEach citer; TreeColumn treeColumn; #ifdef TREECTRL_DEBUG if (!co[index].isColumn) panic("isColumn == FALSE"); #endif COLUMN_FOR_EACH(treeColumn, &co[index].columns, NULL, &citer) { int columnIndex, cMask = 0; columnIndex = TreeColumn_Index(treeColumn); column = TreeItem_FindColumn(tree, item, columnIndex); if ((column == NULL) || (column->style == NULL) || TreeStyle_IsHeaderStyle(tree, column->style)) { NoStyleMsg(tree, item, columnIndex); result = TCL_ERROR; break; } indexElem = index + 1; /* Do each element in this column */ while (1) { int eMask, index2; #ifdef TREECTRL_DEBUG if (co[indexElem].numArgs == -1) panic("indexElem=%d (%s) objc=%d numArgs == -1", indexElem, Tcl_GetString(objv[indexElem]), objc); #endif result = TreeStyle_ElementConfigureFromObj(tree, item, column, column->style, objv[indexElem], co[indexElem].numArgs, (Tcl_Obj **) objv + indexElem + 1, &eMask); if (result != TCL_OK) break; cMask |= eMask; /* co[indexElem].numArgs is the number of * option-value arguments after the element. */ index2 = indexElem + co[indexElem].numArgs; if (index2 == objc - 1) break; /* Skip the '+' or ',' */ index2 += 2; if (co[index2].isColumn) break; indexElem = index2; } if (cMask & CS_LAYOUT) { TreeItemColumn_InvalidateSize(tree, column); TreeColumns_InvalidateWidthOfItems(tree, treeColumn); } else if (cMask & CS_DISPLAY) { Tree_InvalidateItemDInfo(tree, treeColumn, item, NULL); } iMask |= cMask; if (result != TCL_OK) break; } if (result != TCL_OK) break; } if (iMask & CS_LAYOUT) { TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); if (item->header == NULL) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); } else if (iMask & CS_DISPLAY) { } if (result != TCL_OK) break; } doneCONF: for (i = 5; i < objc; i++) { if (co[i].isColumn) TreeColumnList_Free(&co[i].columns); } STATIC_FREE(co, struct columnObj, objc); break; } } TreeItemList_Free(&itemList); return result; } static int ItemElementCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; return TreeItemCmd_Element(tree, objc, objv, FALSE); } /* *---------------------------------------------------------------------- * * ItemStyleCmd -- * * This procedure is invoked to process the [item style] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeItemCmd_Style( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int doHeaders /* TRUE to operate on headers, FALSE * to operate on items. */ ) { Tcl_Interp *interp = tree->interp; int domain = doHeaders ? STATE_DOMAIN_HEADER : STATE_DOMAIN_ITEM; int index; TreeItemList itemList; TreeItem item; int flags = IFO_NOT_NULL; int result = TCL_OK; int tailFlag = doHeaders ? 0 : CFO_NOT_TAIL; static CONST char *commandNames[] = { "elements", "map", "set", (char *) NULL }; enum { COMMAND_ELEMENTS, COMMAND_MAP, COMMAND_SET }; if (objc < 5) { Tcl_WrongNumArgs(interp, 3, objv, doHeaders ? "command header ?arg ...?" : "command item ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[3], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } /* [style elements] only works on a single item. * [style set] only works on a single item without a column-style pair. */ if ((index == COMMAND_ELEMENTS) || (index == COMMAND_SET && objc < 7)) flags |= IFO_NOT_MANY; if (doHeaders) { if (TreeHeaderList_FromObj(tree, objv[4], &itemList, flags) != TCL_OK) { return TCL_ERROR; } } else { if (TreeItemList_FromObj(tree, objv[4], &itemList, flags) != TCL_OK) { return TCL_ERROR; } } item = TreeItemList_Nth(&itemList, 0); switch (index) { /* T item style elements I C */ case COMMAND_ELEMENTS: { TreeItemColumn column; int columnIndex; if (objc != 6) { Tcl_WrongNumArgs(interp, 4, objv, doHeaders ? "header column" : "item column"); result = TCL_ERROR; break; } if (TreeItem_ColumnFromObj(tree, item, objv[5], &column, NULL, &columnIndex, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) { result = TCL_ERROR; break; } if ((column == NULL) || (column->style == NULL) || TreeStyle_IsHeaderStyle(tree, column->style)) { NoStyleMsg(tree, item, columnIndex); result = TCL_ERROR; break; } TreeStyle_ListElements(tree, column->style); break; } /* T item style map I C S map */ case COMMAND_MAP: { TreeStyle style; TreeColumnList columns; TreeColumn treeColumn; TreeItemColumn column; int columnIndex; int objcM; Tcl_Obj **objvM; ItemForEach iter; ColumnForEach citer; int redoRanges = !doHeaders; if (objc != 8) { Tcl_WrongNumArgs(interp, 4, objv, doHeaders ? "header column style map" : "item column style map"); return TCL_ERROR; } if (TreeColumnList_FromObj(tree, objv[5], &columns, CFO_NOT_NULL | tailFlag) != TCL_OK) { result = TCL_ERROR; break; } if (TreeStyle_FromObj(tree, objv[6], &style) != TCL_OK) { result = TCL_ERROR; goto doneMAP; } if (TreeStyle_GetStateDomain(tree, style) != domain) { StateDomainErrMsg(tree, item, style); result = TCL_ERROR; goto doneMAP; } if (Tcl_ListObjGetElements(interp, objv[7], &objcM, &objvM) != TCL_OK) { result = TCL_ERROR; goto doneMAP; } if (objcM & 1) { FormatResult(interp, "list must contain even number of elements"); result = TCL_ERROR; goto doneMAP; } ITEM_FOR_EACH(item, &itemList, NULL, &iter) { COLUMN_FOR_EACH(treeColumn, &columns, NULL, &citer) { columnIndex = TreeColumn_Index(treeColumn); column = Item_CreateColumn(tree, item, columnIndex, NULL); if ((column->style != NULL) && !TreeStyle_IsHeaderStyle(tree, column->style)) { if (TreeStyle_Remap(tree, column->style, style, objcM, objvM) != TCL_OK) { result = TCL_ERROR; break; } } else { TreeItemColumn_ForgetStyle(tree, column); column->style = TreeStyle_NewInstance(tree, style); } TreeItemColumn_InvalidateSize(tree, column); TreeColumns_InvalidateWidthOfItems(tree, treeColumn); } TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); if (result != TCL_OK) break; } if (redoRanges) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); doneMAP: TreeColumnList_Free(&columns); break; } /* T item style set I ?C? ?S? ?C S ...?*/ case COMMAND_SET: { struct columnStyle { TreeColumnList columns; TreeStyle style; }; struct columnStyle staticCS[STATIC_SIZE], *cs = staticCS; TreeColumn treeColumn; TreeItemColumn column; int i, count = 0, length, changed = FALSE, changedI; ItemForEach iter; ColumnForEach citer; if (objc < 5) { Tcl_WrongNumArgs(interp, 4, objv, doHeaders ? "header ?column? ?style? ?column style ...?" : "item ?column? ?style? ?column style ...?"); return TCL_ERROR; } /* Return list of styles. */ if (objc == 5) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); int tailOK = item->header != NULL; treeColumn = Tree_FirstColumn(tree, -1, tailOK); column = item->columns; while (treeColumn != NULL) { if ((column != NULL) && (column->style != NULL) && !TreeStyle_IsHeaderStyle(tree, column->style)) Tcl_ListObjAppendElement(interp, listObj, TreeStyle_ToObj(TreeStyle_GetMaster( tree, column->style))); else Tcl_ListObjAppendElement(interp, listObj, Tcl_NewObj()); treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK); if (column != NULL) column = column->next; } Tcl_SetObjResult(interp, listObj); break; } /* Return style in one column. */ if (objc == 6) { if (TreeItem_ColumnFromObj(tree, item, objv[5], &column, NULL, NULL, CFO_NOT_NULL | tailFlag) != TCL_OK) return TCL_ERROR; if ((column != NULL) && (column->style != NULL) && !TreeStyle_IsHeaderStyle(tree, column->style)) Tcl_SetObjResult(interp, TreeStyle_ToObj( TreeStyle_GetMaster(tree, column->style))); break; } /* Get column/style pairs. */ STATIC_ALLOC(cs, struct columnStyle, objc / 2); for (i = 5; i < objc; i += 2) { if (TreeColumnList_FromObj(tree, objv[i], &cs[count].columns, CFO_NOT_NULL | tailFlag) != TCL_OK) { result = TCL_ERROR; goto doneSET; } if (i + 1 == objc) { FormatResult(interp, "missing style for column \"%s\"", Tcl_GetString(objv[i])); result = TCL_ERROR; goto doneSET; } (void) Tcl_GetStringFromObj(objv[i + 1], &length); if (length == 0) { cs[count].style = NULL; } else { if (TreeStyle_FromObj(tree, objv[i + 1], &cs[count].style) != TCL_OK) { result = TCL_ERROR; goto doneSET; } if (TreeStyle_GetStateDomain(tree, cs[count].style) != domain) { StateDomainErrMsg(tree, item, cs[count].style); result = TCL_ERROR; goto doneSET; } } count++; } ITEM_FOR_EACH(item, &itemList, NULL, &iter) { changedI = FALSE; for (i = 0; i < count; i++) { COLUMN_FOR_EACH(treeColumn, &cs[i].columns, NULL, &citer) { if (cs[i].style == NULL) { column = TreeItem_FindColumn(tree, item, TreeColumn_Index(treeColumn)); if (column == NULL || column->style == NULL || TreeStyle_IsHeaderStyle(tree, column->style)) continue; TreeItemColumn_ForgetStyle(tree, column); if (doHeaders) TreeHeaderColumn_EnsureStyleExists(item->header, column->headerColumn, treeColumn); } else { column = Item_CreateColumn(tree, item, TreeColumn_Index(treeColumn), NULL); if (column->style != NULL) { if (TreeStyle_GetMaster(tree, column->style) == cs[i].style) continue; TreeItemColumn_ForgetStyle(tree, column); } column->style = TreeStyle_NewInstance(tree, cs[i].style); } TreeItemColumn_InvalidateSize(tree, column); TreeColumns_InvalidateWidthOfItems(tree, treeColumn); changedI = TRUE; } if (changedI) { TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); changed = TRUE; } } } if (changed && !doHeaders) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); doneSET: for (i = 0; i < count; i++) { TreeColumnList_Free(&cs[i].columns); } STATIC_FREE(cs, struct columnStyle, objc / 2); break; } } TreeItemList_Free(&itemList); return result; } static int ItemStyleCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; return TreeItemCmd_Style(tree, objc, objv, FALSE); } /* *---------------------------------------------------------------------- * * TreeItemCmd_ImageOrText -- * * This procedure is invoked to process the [item image] and * [item text] widget commands. See the user documentation for * details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeItemCmd_ImageOrText( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int doImage, /* TRUE if this is [item image] */ int doHeaders /* TRUE to operate on headers, FALSE * to operate on items. */ ) { Tcl_Interp *interp = tree->interp; TreeColumn treeColumn = tree->columns; TreeItemList itemList; TreeItem item; TreeElement elem = NULL; TreeItemColumn column; Tcl_Obj *objPtr; int isImage = doImage; struct columnObj { TreeColumnList columns; Tcl_Obj *obj; } staticCO[STATIC_SIZE], *co = staticCO; int i, count = 0, changed = FALSE, columnIndex; ItemForEach iter; ColumnForEach citer; int flags = 0, result = TCL_OK; int tailFlag = /*doHeaders ? 0 : */CFO_NOT_TAIL; /* T item text I ?C? ?text? ?C text ...? */ if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, doHeaders ? "header ?column? ?text? ?column text ...?" : "item ?column? ?text? ?column text ...?"); return TCL_ERROR; } if (objc < 6) flags = IFO_NOT_NULL | IFO_NOT_MANY; if (doHeaders) { if (TreeHeaderList_FromObj(tree, objv[3], &itemList, flags) != TCL_OK) return TCL_ERROR; } else { if (TreeItemList_FromObj(tree, objv[3], &itemList, flags) != TCL_OK) return TCL_ERROR; } item = TreeItemList_Nth(&itemList, 0); if (objc == 4) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); column = item->columns; while (treeColumn != NULL) { if ((column != NULL) && (column->style != NULL) && !TreeStyle_IsHeaderStyle(tree, column->style)) { objPtr = isImage ? TreeStyle_GetImage(tree, column->style, &elem) : TreeStyle_GetText(tree, column->style, &elem); } else objPtr = NULL; if (doHeaders && elem == NULL) objPtr = TreeHeaderColumn_GetImageOrText(item->header, column->headerColumn, isImage); if (objPtr == NULL) objPtr = Tcl_NewObj(); Tcl_ListObjAppendElement(interp, listObj, objPtr); treeColumn = TreeColumn_Next(treeColumn); if (column != NULL) column = column->next; } Tcl_SetObjResult(interp, listObj); goto okExit; } if (objc == 5) { if (TreeItem_ColumnFromObj(tree, item, objv[4], &column, NULL, NULL, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) { goto errorExit; } if ((column != NULL) && (column->style != NULL) && !TreeStyle_IsHeaderStyle(tree, column->style)) { objPtr = isImage ? TreeStyle_GetImage(tree, column->style, &elem) : TreeStyle_GetText(tree, column->style, &elem); } else objPtr = NULL; if (doHeaders && elem == NULL) objPtr = TreeHeaderColumn_GetImageOrText(item->header, column->headerColumn, isImage); if (objPtr != NULL) Tcl_SetObjResult(interp, objPtr); goto okExit; } if ((objc - 4) & 1) { FormatResult(interp, "missing argument after column \"%s\"", Tcl_GetString(objv[objc - 1])); goto errorExit; } /* Gather column/obj pairs. */ STATIC_ALLOC(co, struct columnObj, objc / 2); for (i = 4; i < objc; i += 2) { if (TreeColumnList_FromObj(tree, objv[i], &co[count].columns, CFO_NOT_NULL | tailFlag) != TCL_OK) { result = TCL_ERROR; goto doneTEXT; } co[count].obj = objv[i + 1]; count++; } ITEM_FOR_EACH(item, &itemList, NULL, &iter) { int changedI = FALSE; for (i = 0; i < count; i++) { COLUMN_FOR_EACH(treeColumn, &co[i].columns, NULL, &citer) { columnIndex = TreeColumn_Index(treeColumn); column = TreeItem_FindColumn(tree, item, columnIndex); if ((column == NULL) || (column->style == NULL) || TreeStyle_IsHeaderStyle(tree, column->style)) { if (doHeaders) { result = TreeHeaderColumn_SetImageOrText(item->header, column->headerColumn, treeColumn, co[i].obj, isImage); if (result != TCL_OK) goto doneTEXT; continue; } NoStyleMsg(tree, item, columnIndex); result = TCL_ERROR; goto doneTEXT; } result = isImage ? TreeStyle_SetImage(tree, item, column, column->style, co[i].obj, &elem) : TreeStyle_SetText(tree, item, column, column->style, co[i].obj, &elem); if (result != TCL_OK) goto doneTEXT; if (elem == NULL) { if (doHeaders) { result = TreeHeaderColumn_SetImageOrText(item->header, column->headerColumn, treeColumn, co[i].obj, isImage); if (result != TCL_OK) goto doneTEXT; } } else { TreeItemColumn_InvalidateSize(tree, column); TreeColumns_InvalidateWidthOfItems(tree, treeColumn); changedI = TRUE; } } } if (changedI) { TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); changed = TRUE; } } if (changed && !doHeaders) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); doneTEXT: for (i = 0; i < count; i++) { TreeColumnList_Free(&co[i].columns); } STATIC_FREE(co, struct columnObj, objc / 2); TreeItemList_Free(&itemList); return result; okExit: TreeItemList_Free(&itemList); return TCL_OK; errorExit: TreeItemList_Free(&itemList); return TCL_ERROR; } static int ItemImageCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; return TreeItemCmd_ImageOrText(tree, objc, objv, TRUE, FALSE); } static int ItemTextCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; return TreeItemCmd_ImageOrText(tree, objc, objv, FALSE, FALSE); } /* Quicksort is not a "stable" sorting algorithm, but it can become a * stable sort by using the pre-sort order of two items as a tie-breaker * for items that would otherwise be considered equal. */ #define STABLE_SORT /* one per column per SortItem */ struct SortItem1 { long longValue; double doubleValue; char *string; }; /* one per Item */ struct SortItem { TreeItem item; struct SortItem1 *item1; Tcl_Obj *obj; /* TreeItem_ToObj() */ #ifdef STABLE_SORT int index; /* The pre-sort order of the item */ #endif }; typedef struct SortData SortData; /* Used to process -element option */ struct SortElement { TreeStyle style; TreeElement elem; int elemIndex; }; /* One per TreeColumn */ struct SortColumn { int (*proc)(SortData *, struct SortItem *, struct SortItem *, int); int sortBy; int column; int order; Tcl_Obj *command; struct SortElement elems[20]; int elemCount; }; /* Data for sort as a whole */ struct SortData { TreeCtrl *tree; struct SortItem *items; struct SortItem1 *item1s; /* SortItem.item1 points in here */ #define MAX_SORT_COLUMNS 40 struct SortColumn columns[MAX_SORT_COLUMNS]; int columnCount; /* max number of columns to compare */ int result; }; /* from Tcl 8.4.0 */ static int DictionaryCompare( char *left, char *right ) { Tcl_UniChar uniLeft, uniRight, uniLeftLower, uniRightLower; int diff, zeros; int secondaryDiff = 0; while (1) { if (isdigit(UCHAR(*right)) && isdigit(UCHAR(*left))) { /* INTL: digit */ /* * 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))) { /* INTL: digit */ if (isdigit(UCHAR(*left))) { /* INTL: digit */ 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))) { /* INTL: digit */ return -1; } } continue; } /* * Convert character to Unicode for comparison purposes. If either * string is at the terminating null, do a byte-wise comparison and * bail out immediately. */ if ((*left != '\0') && (*right != '\0')) { left += Tcl_UtfToUniChar(left, &uniLeft); right += Tcl_UtfToUniChar(right, &uniRight); /* * Convert both chars to lower for the comparison, because * dictionary sorts are case insensitve. Covert to lower, not * upper, so chars between Z and a will sort before A (where most * other interesting punctuations occur) */ uniLeftLower = Tcl_UniCharToLower(uniLeft); uniRightLower = Tcl_UniCharToLower(uniRight); } else { diff = UCHAR(*left) - UCHAR(*right); break; } diff = uniLeftLower - uniRightLower; if (diff) { return diff; } else if (secondaryDiff == 0) { if (Tcl_UniCharIsUpper(uniLeft) && Tcl_UniCharIsLower(uniRight)) { secondaryDiff = -1; } else if (Tcl_UniCharIsUpper(uniRight) && Tcl_UniCharIsLower(uniLeft)) { secondaryDiff = 1; } } } if (diff == 0) { diff = secondaryDiff; } return diff; } static int CompareAscii( SortData *sortData, struct SortItem *a, struct SortItem *b, int n /* Column index. */ ) { char *left = a->item1[n].string; char *right = b->item1[n].string; /* make sure to handle case where no string value has been set */ if (left == NULL) { return ((right == NULL) ? 0 : (0 - UCHAR(*right))); } else if (right == NULL) { return UCHAR(*left); } else { return strcmp(left, right); } } static int CompareDict( SortData *sortData, struct SortItem *a, struct SortItem *b, int n /* Column index. */ ) { char *left = a->item1[n].string; char *right = b->item1[n].string; /* make sure to handle case where no string value has been set */ if (left == NULL) { return ((right == NULL) ? 0 : (0 - UCHAR(*right))); } else if (right == NULL) { return UCHAR(*left); } else { return DictionaryCompare(left, right); } } static int CompareDouble( SortData *sortData, struct SortItem *a, struct SortItem *b, int n /* Column index. */ ) { return (a->item1[n].doubleValue < b->item1[n].doubleValue) ? -1 : ((a->item1[n].doubleValue == b->item1[n].doubleValue) ? 0 : 1); } static int CompareLong( SortData *sortData, struct SortItem *a, struct SortItem *b, int n /* Column index. */ ) { return (a->item1[n].longValue < b->item1[n].longValue) ? -1 : ((a->item1[n].longValue == b->item1[n].longValue) ? 0 : 1); } static int CompareCmd( SortData *sortData, struct SortItem *a, struct SortItem *b, int n /* Column index. */ ) { Tcl_Interp *interp = sortData->tree->interp; Tcl_Obj **objv, *paramObjv[2]; int objc, v; paramObjv[0] = a->obj; paramObjv[1] = b->obj; Tcl_ListObjLength(interp, sortData->columns[n].command, &objc); Tcl_ListObjReplace(interp, sortData->columns[n].command, objc - 2, 2, 2, paramObjv); Tcl_ListObjGetElements(interp, sortData->columns[n].command, &objc, &objv); sortData->result = Tcl_EvalObjv(interp, objc, objv, 0); if (sortData->result != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (evaluating item sort -command)"); return 0; } sortData->result = Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &v); if (sortData->result != TCL_OK) { Tcl_ResetResult(interp); Tcl_AppendToObj(Tcl_GetObjResult(interp), "-command returned non-numeric result", -1); return 0; } return v; } static int CompareProc( SortData *sortData, struct SortItem *a, struct SortItem *b ) { int i, v; if (a->item == b->item) return 0; for (i = 0; i < sortData->columnCount; i++) { v = (*sortData->columns[i].proc)(sortData, a, b, i); /* -command returned error */ if (sortData->result != TCL_OK) return 0; if (v != 0) { if (i && (sortData->columns[i].order != sortData->columns[0].order)) v *= -1; return v; } } #ifdef STABLE_SORT return ((a->index < b->index) == sortData->columns[0].order) ? -1 : 1; #else return 0; #endif } /* BEGIN custom quicksort() */ static int find_pivot( SortData *sortData, struct SortItem *left, struct SortItem *right, struct SortItem *pivot ) { struct SortItem *a, *b, *c, *p, *tmp; int v; a = left; b = (left + (right - left) / 2); c = right; /* Arrange a <= b <= c. */ v = CompareProc(sortData, a, b); if (sortData->result != TCL_OK) return 0; if (v > 0) { tmp = a; a = b; b = tmp; } v = CompareProc(sortData, a, c); if (sortData->result != TCL_OK) return 0; if (v > 0) { tmp = a; a = c; c = tmp; } v = CompareProc(sortData, b, c); if (sortData->result != TCL_OK) return 0; if (v > 0) { tmp = b; b = c; c = tmp; } /* if (a < b) pivot = b */ v = CompareProc(sortData, a, b); if (sortData->result != TCL_OK) return 0; if (v < 0) { (*pivot) = *b; return 1; } /* if (b < c) pivot = c */ v = CompareProc(sortData, b, c); if (sortData->result != TCL_OK) return 0; if (v < 0) { (*pivot) = *c; return 1; } for (p = left + 1; p <= right; p++) { int v = CompareProc(sortData, p, left); if (sortData->result != TCL_OK) return 0; if (v != 0) { (*pivot) = (v < 0) ? *left : *p; return 1; } } return 0; } /* If the user provides a -command which does not properly compare two * elements, quicksort may go into an infinite loop or access illegal memory. * This #define indicates parts of the code which are not part of a normal * quicksort, but are present to detect the aforementioned bugs. */ #define BUGGY_COMMAND static struct SortItem * partition( SortData *sortData, struct SortItem *left, struct SortItem *right, struct SortItem *pivot ) { int v; #ifdef BUGGY_COMMAND struct SortItem *min = left, *max = right; #endif while (left <= right) { /* while (*left < *pivot) ++left; */ while (1) { v = CompareProc(sortData, left, pivot); if (sortData->result != TCL_OK) return NULL; if (v >= 0) break; #ifdef BUGGY_COMMAND /* If -command always returns < 0, 'left' becomes invalid */ if (left == max) goto buggy; #endif left++; } /* while (*right >= *pivot) --right; */ while (1) { v = CompareProc(sortData, right, pivot); if (sortData->result != TCL_OK) return NULL; if (v < 0) break; #ifdef BUGGY_COMMAND /* If -command always returns >= 0, 'right' becomes invalid */ if (right == min) goto buggy; #endif right--; } if (left < right) { struct SortItem tmp = *left; *left = *right; *right = tmp; left++; right--; } } return left; #ifdef BUGGY_COMMAND buggy: FormatResult(sortData->tree->interp, "buggy item sort -command detected"); sortData->result = TCL_ERROR; return NULL; #endif } static void quicksort( SortData *sortData, struct SortItem *left, struct SortItem *right ) { struct SortItem *p, pivot; if (sortData->result != TCL_OK) return; if (left == right) return; /* FIXME: switch to insertion sort or similar when the number of * elements is small. */ if (find_pivot(sortData, left, right, &pivot) == 1) { p = partition(sortData, left, right, &pivot); quicksort(sortData, left, p - 1); quicksort(sortData, p, right); } } /* END custom quicksort() */ /* *---------------------------------------------------------------------- * * ItemSortCmd -- * * This procedure is invoked to process the [item sort] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int ItemSortCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; TreeItem item, first, last, walk, lastChild; TreeItemColumn column; int i, j, count, elemIndex, index, indexF = 0, indexL = 0; int sawColumn = FALSE, sawCmd = FALSE; static int (*sortProc[5])(SortData *, struct SortItem *, struct SortItem *, int) = { CompareAscii, CompareDict, CompareDouble, CompareLong, CompareCmd }; SortData sortData; TreeColumn treeColumn; struct SortElement *elemPtr; int notReally = FALSE; int result = TCL_OK; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "item ?option ...?"); return TCL_ERROR; } if (TreeItem_FromObj(tree, objv[3], &item, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; /* If the item has no children, then nothing is done and no error * is generated. */ if (item->numChildren < 1) return TCL_OK; /* Defaults: sort ascii strings in column 0 only */ sortData.tree = tree; sortData.columnCount = 1; sortData.columns[0].column = 0; sortData.columns[0].sortBy = SORT_ASCII; sortData.columns[0].order = 1; sortData.columns[0].elemCount = 0; sortData.result = TCL_OK; first = item->firstChild; last = item->lastChild; for (i = 4; i < objc; ) { static CONST char *optionName[] = { "-ascii", "-column", "-command", "-decreasing", "-dictionary", "-element", "-first", "-increasing", "-integer", "-last", "-notreally", "-real", NULL }; int numArgs[] = { 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1 }; enum { OPT_ASCII, OPT_COLUMN, OPT_COMMAND, OPT_DECREASING, OPT_DICT, OPT_ELEMENT, OPT_FIRST, OPT_INCREASING, OPT_INTEGER, OPT_LAST, OPT_NOT_REALLY, OPT_REAL }; if (Tcl_GetIndexFromObj(interp, objv[i], optionName, "option", 0, &index) != TCL_OK) return TCL_ERROR; if (objc - i < numArgs[index]) { FormatResult(interp, "missing value for \"%s\" option", optionName[index]); return TCL_ERROR; } switch (index) { case OPT_ASCII: sortData.columns[sortData.columnCount - 1].sortBy = SORT_ASCII; break; case OPT_COLUMN: if (TreeColumn_FromObj(tree, objv[i + 1], &treeColumn, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) return TCL_ERROR; /* The first -column we see is the first column we compare */ if (sawColumn) { if (sortData.columnCount + 1 > MAX_SORT_COLUMNS) { FormatResult(interp, "can't compare more than %d columns", MAX_SORT_COLUMNS); return TCL_ERROR; } sortData.columnCount++; /* Defaults for this column */ sortData.columns[sortData.columnCount - 1].sortBy = SORT_ASCII; sortData.columns[sortData.columnCount - 1].order = 1; sortData.columns[sortData.columnCount - 1].elemCount = 0; } sortData.columns[sortData.columnCount - 1].column = TreeColumn_Index(treeColumn); sawColumn = TRUE; break; case OPT_COMMAND: sortData.columns[sortData.columnCount - 1].command = objv[i + 1]; sortData.columns[sortData.columnCount - 1].sortBy = SORT_COMMAND; sawCmd = TRUE; break; case OPT_DECREASING: sortData.columns[sortData.columnCount - 1].order = 0; break; case OPT_DICT: sortData.columns[sortData.columnCount - 1].sortBy = SORT_DICT; break; case OPT_ELEMENT: { int listObjc; Tcl_Obj **listObjv; if (Tcl_ListObjGetElements(interp, objv[i + 1], &listObjc, &listObjv) != TCL_OK) return TCL_ERROR; elemPtr = sortData.columns[sortData.columnCount - 1].elems; sortData.columns[sortData.columnCount - 1].elemCount = 0; if (listObjc == 0) { } else if (listObjc == 1) { if (TreeElement_FromObj(tree, listObjv[0], &elemPtr->elem) != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (processing -element option)"); return TCL_ERROR; } if (!TreeElement_IsType(tree, elemPtr->elem, "text")) { FormatResult(interp, "element %s is not of type \"text\"", Tcl_GetString(listObjv[0])); Tcl_AddErrorInfo(interp, "\n (processing -element option)"); return TCL_ERROR; } elemPtr->style = NULL; elemPtr->elemIndex = -1; sortData.columns[sortData.columnCount - 1].elemCount++; } else { if (listObjc & 1) { FormatResult(interp, "list must have even number of elements"); Tcl_AddErrorInfo(interp, "\n (processing -element option)"); return TCL_ERROR; } for (j = 0; j < listObjc; j += 2) { if ((TreeStyle_FromObj(tree, listObjv[j], &elemPtr->style) != TCL_OK) || (TreeElement_FromObj(tree, listObjv[j + 1], &elemPtr->elem) != TCL_OK) || (TreeStyle_FindElement(tree, elemPtr->style, elemPtr->elem, &elemPtr->elemIndex) != TCL_OK)) { Tcl_AddErrorInfo(interp, "\n (processing -element option)"); return TCL_ERROR; } if (!TreeElement_IsType(tree, elemPtr->elem, "text")) { FormatResult(interp, "element %s is not of type \"text\"", Tcl_GetString(listObjv[j + 1])); Tcl_AddErrorInfo(interp, "\n (processing -element option)"); return TCL_ERROR; } sortData.columns[sortData.columnCount - 1].elemCount++; elemPtr++; } } break; } case OPT_FIRST: if (TreeItem_FromObj(tree, objv[i + 1], &first, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; if (first->parent != item) { FormatResult(interp, "item %s%d is not a child of item %s%d", tree->itemPrefix, first->id, tree->itemPrefix, item->id); return TCL_ERROR; } break; case OPT_INCREASING: sortData.columns[sortData.columnCount - 1].order = 1; break; case OPT_INTEGER: sortData.columns[sortData.columnCount - 1].sortBy = SORT_LONG; break; case OPT_LAST: if (TreeItem_FromObj(tree, objv[i + 1], &last, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; if (last->parent != item) { FormatResult(interp, "item %s%d is not a child of item %s%d", tree->itemPrefix, last->id, tree->itemPrefix, item->id); return TCL_ERROR; } break; case OPT_NOT_REALLY: notReally = TRUE; break; case OPT_REAL: sortData.columns[sortData.columnCount - 1].sortBy = SORT_DOUBLE; break; } i += numArgs[index]; } /* If there are no columns, we cannot perform a sort unless -command * is specified. */ if ((tree->columnCount < 1) && (sortData.columns[0].sortBy != SORT_COMMAND)) { FormatResult(interp, "there are no columns"); return TCL_ERROR; } /* If there is only one item to sort, then return early. */ if (first == last) { if (notReally) Tcl_SetObjResult(interp, TreeItem_ToObj(tree, first)); return TCL_OK; } for (i = 0; i < sortData.columnCount; i++) { /* Initialize the sort procedure for this column. */ sortData.columns[i].proc = sortProc[sortData.columns[i].sortBy]; /* Append two dummy args to the -command argument. These two dummy * args are replaced by the 2 item ids being compared. See * CompareCmd(). */ if (sortData.columns[i].sortBy == SORT_COMMAND) { Tcl_Obj *obj = Tcl_DuplicateObj(sortData.columns[i].command); Tcl_Obj *obj2 = Tcl_NewObj(); Tcl_IncrRefCount(obj); if (Tcl_ListObjAppendElement(interp, obj, obj2) != TCL_OK) { Tcl_DecrRefCount(obj); Tcl_IncrRefCount(obj2); Tcl_DecrRefCount(obj2); for (j = 0; j < i; j++) { if (sortData.columns[j].sortBy == SORT_COMMAND) { Tcl_DecrRefCount(sortData.columns[j].command); } } return TCL_ERROR; } (void) Tcl_ListObjAppendElement(interp, obj, obj2); sortData.columns[i].command = obj; } } index = 0; walk = item->firstChild; while (walk != NULL) { if (walk == first) indexF = index; if (walk == last) indexL = index; index++; walk = walk->nextSibling; } if (indexF > indexL) { walk = last; last = first; first = walk; index = indexL; indexL = indexF; indexF = index; } count = indexL - indexF + 1; sortData.item1s = (struct SortItem1 *) ckalloc(sizeof(struct SortItem1) * count * sortData.columnCount); sortData.items = (struct SortItem *) ckalloc(sizeof(struct SortItem) * count); for (i = 0; i < count; i++) { sortData.items[i].item1 = sortData.item1s + i * sortData.columnCount; sortData.items[i].obj = NULL; } index = 0; walk = first; while (walk != last->nextSibling) { struct SortItem *sortItem = &sortData.items[index]; sortItem->item = walk; #ifdef STABLE_SORT sortItem->index = index; #endif if (sawCmd) { Tcl_Obj *obj = TreeItem_ToObj(tree, walk); Tcl_IncrRefCount(obj); sortData.items[index].obj = obj; } for (i = 0; i < sortData.columnCount; i++) { struct SortItem1 *sortItem1 = sortItem->item1 + i; if (sortData.columns[i].sortBy == SORT_COMMAND) continue; column = TreeItem_FindColumn(tree, walk, sortData.columns[i].column); if ((column == NULL) || (column->style == NULL)) { NoStyleMsg(tree, walk, sortData.columns[i].column); result = TCL_ERROR; goto done; } /* -element was empty. Find the first text element in the style */ if (sortData.columns[i].elemCount == 0) elemIndex = -1; /* -element was element name. Find the element in the style */ else if ((sortData.columns[i].elemCount == 1) && (sortData.columns[i].elems[0].style == NULL)) { if (TreeStyle_FindElement(tree, column->style, sortData.columns[i].elems[0].elem, &elemIndex) != TCL_OK) { result = TCL_ERROR; goto done; } } /* -element was style/element pair list */ else { TreeStyle masterStyle = TreeStyle_GetMaster(tree, column->style); /* If the item style does not match any in the -element list, * we will use the first text element in the item style. */ elemIndex = -1; /* Match a style from the -element list. Look in reverse order * to handle duplicates. */ for (j = sortData.columns[i].elemCount - 1; j >= 0; j--) { if (sortData.columns[i].elems[j].style == masterStyle) { elemIndex = sortData.columns[i].elems[j].elemIndex; break; } } } if (TreeStyle_GetSortData(tree, column->style, elemIndex, sortData.columns[i].sortBy, &sortItem1->longValue, &sortItem1->doubleValue, &sortItem1->string) != TCL_OK) { char msg[128]; sprintf(msg, "\n (preparing to sort item %s%d column %s%d)", tree->itemPrefix, walk->id, tree->columnPrefix, TreeColumn_GetID( Tree_FindColumn(tree, sortData.columns[i].column))); Tcl_AddErrorInfo(interp, msg); result = TCL_ERROR; goto done; } } index++; walk = walk->nextSibling; } quicksort(&sortData, sortData.items, sortData.items + count - 1); if (sortData.result != TCL_OK) { result = sortData.result; goto done; } if (sawCmd) Tcl_ResetResult(interp); if (notReally) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); Tcl_Obj *itemObj; /* Smallest to largest */ if (sortData.columns[0].order == 1) { for (i = 0; i < count; i++) { itemObj = sortData.items[i].obj; if (itemObj == NULL) itemObj = TreeItem_ToObj(tree, sortData.items[i].item); Tcl_ListObjAppendElement(interp, listObj, itemObj); } } /* Largest to smallest */ else { for (i = count - 1; i >= 0; i--) { itemObj = sortData.items[i].obj; if (itemObj == NULL) itemObj = TreeItem_ToObj(tree, sortData.items[i].item); Tcl_ListObjAppendElement(interp, listObj, itemObj); } } Tcl_SetObjResult(interp, listObj); goto done; } first = first->prevSibling; last = last->nextSibling; /* Smallest to largest */ if (sortData.columns[0].order == 1) { for (i = 0; i < count - 1; i++) { sortData.items[i].item->nextSibling = sortData.items[i + 1].item; sortData.items[i + 1].item->prevSibling = sortData.items[i].item; } indexF = 0; indexL = count - 1; } /* Largest to smallest */ else { for (i = count - 1; i > 0; i--) { sortData.items[i].item->nextSibling = sortData.items[i - 1].item; sortData.items[i - 1].item->prevSibling = sortData.items[i].item; } indexF = count - 1; indexL = 0; } lastChild = item->lastChild; sortData.items[indexF].item->prevSibling = first; if (first) first->nextSibling = sortData.items[indexF].item; else item->firstChild = sortData.items[indexF].item; sortData.items[indexL].item->nextSibling = last; if (last) last->prevSibling = sortData.items[indexL].item; else item->lastChild = sortData.items[indexL].item; /* Redraw the lines of the old/new lastchild */ if ((item->lastChild != lastChild) && tree->showLines && (tree->columnTree != NULL)) { if (lastChild->dInfo != NULL) Tree_InvalidateItemDInfo(tree, tree->columnTree, lastChild, NULL); if (item->lastChild->dInfo != NULL) Tree_InvalidateItemDInfo(tree, tree->columnTree, item->lastChild, NULL); } tree->updateIndex = 1; Tree_DInfoChanged(tree, DINFO_REDO_RANGES); done: for (i = 0; i < count; i++) { if (sortData.items[i].obj != NULL) { Tcl_DecrRefCount(sortData.items[i].obj); } } for (i = 0; i < sortData.columnCount; i++) { if (sortData.columns[i].sortBy == SORT_COMMAND) { Tcl_DecrRefCount(sortData.columns[i].command); } } ckfree((char *) sortData.item1s); ckfree((char *) sortData.items); if (tree->debug.enable && tree->debug.data) { Tree_Debug(tree); } return result; } /* *---------------------------------------------------------------------- * * TreeItemList_Sort -- * * Sorts a list of items. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TILSCompare( CONST VOID *first_, CONST VOID *second_ ) { TreeItem first = *(TreeItem *) first_; TreeItem second = *(TreeItem *) second_; return first->index - second->index; } void TreeItemList_Sort( TreeItemList *items ) { Tree_UpdateItemIndex(items->tree); /* TkTable uses this, but mentions possible lack of thread-safety. */ qsort((VOID *) TreeItemList_Items(items), (size_t) TreeItemList_Count(items), sizeof(TreeItem), TILSCompare); } /* *---------------------------------------------------------------------- * * TreeItemCmd_Span -- * * The body of the [item span] and [header span] commands. * * Results: * A standard Tcl result. * * Side effects: * May change the layout and schedule a redraw of the widget. * *---------------------------------------------------------------------- */ int TreeItemCmd_Span( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int doHeaders /* TRUE to operate on headers, FALSE * to operate on items. */ ) { Tcl_Interp *interp = tree->interp; TreeColumn treeColumn = tree->columns; TreeItemList itemList; TreeItem item; TreeItemColumn column; Tcl_Obj *listObj; struct columnSpan { TreeColumnList columns; int span; } staticCS[STATIC_SIZE], *cs = staticCS; int i, count = 0, span, changed = FALSE; ItemForEach iter; ColumnForEach citer; int flags = 0, result = TCL_OK; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, doHeaders ? "header ?column? ?span? ?column span ...?": "item ?column? ?span? ?column span ...?"); return TCL_ERROR; } if (objc < 6) flags |= IFO_NOT_NULL | IFO_NOT_MANY; if (doHeaders) { if (TreeHeaderList_FromObj(tree, objv[3], &itemList, flags) != TCL_OK) return TCL_ERROR; } else { if (TreeItemList_FromObj(tree, objv[3], &itemList, flags) != TCL_OK) return TCL_ERROR; } item = TreeItemList_Nth(&itemList, 0); if (objc == 4) { listObj = Tcl_NewListObj(0, NULL); column = item->columns; while (treeColumn != NULL) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(column ? column->span : 1)); treeColumn = TreeColumn_Next(treeColumn); if (column != NULL) column = column->next; } Tcl_SetObjResult(interp, listObj); goto okExit; } if (objc == 5) { if (TreeItem_ColumnFromObj(tree, item, objv[4], &column, NULL, NULL, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) { goto errorExit; } Tcl_SetObjResult(interp, Tcl_NewIntObj(column ? column->span : 1)); goto okExit; } if (objc & 1) { FormatResult(interp, "missing argument after column \"%s\"", Tcl_GetString(objv[objc - 1])); goto errorExit; } /* Gather column/span pairs. */ STATIC_ALLOC(cs, struct columnSpan, objc / 2); for (i = 4; i < objc; i += 2) { if (TreeColumnList_FromObj(tree, objv[i], &cs[count].columns, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) { result = TCL_ERROR; goto doneSPAN; } if (Tcl_GetIntFromObj(interp, objv[i + 1], &span) != TCL_OK) { result = TCL_ERROR; goto doneSPAN; } if (span <= 0) { FormatResult(interp, "bad span \"%d\": must be > 0", span); result = TCL_ERROR; goto doneSPAN; } cs[count].span = span; count++; } ITEM_FOR_EACH(item, &itemList, NULL, &iter) { int changedI = FALSE; for (i = 0; i < count; i++) { COLUMN_FOR_EACH(treeColumn, &cs[i].columns, NULL, &citer) { column = Item_CreateColumn(tree, item, TreeColumn_Index(treeColumn), NULL); if (column->span != cs[i].span) { if (cs[i].span > 1) { item->flags &= ~ITEM_FLAG_SPANS_SIMPLE; } TreeItem_SpansInvalidate(tree, item); column->span = cs[i].span; TreeItemColumn_InvalidateSize(tree, column); changedI = TRUE; TreeColumns_InvalidateWidthOfItems(tree, treeColumn); } } } if (changedI) { TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); changed = TRUE; } } if (changed && !doHeaders) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); doneSPAN: for (i = 0; i < count; i++) { TreeColumnList_Free(&cs[i].columns); } STATIC_FREE(cs, struct columnSpan, objc / 2); TreeItemList_Free(&itemList); return result; okExit: TreeItemList_Free(&itemList); return TCL_OK; errorExit: TreeItemList_Free(&itemList); return TCL_ERROR; } static int ItemSpanCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; return TreeItemCmd_Span(tree, objc, objv, FALSE); } /* *---------------------------------------------------------------------- * * ItemStateCmd -- * * This procedure is invoked to process the [item state] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeItemCmd_State( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int doHeaders /* TRUE to operate on headers, FALSE * to operate on items. */ ) { Tcl_Interp *interp = tree->interp; int domain = doHeaders ? STATE_DOMAIN_HEADER : STATE_DOMAIN_ITEM; TreeStateDomain *domainPtr = &tree->stateDomain[domain]; int tailFlag = doHeaders ? 0 : CFO_NOT_TAIL; static CONST char *commandNames[] = { "define", "forcolumn", "get", "linkage", "names", "set", "undefine", (char *) NULL }; enum { COMMAND_DEFINE, COMMAND_FORCOLUMN, COMMAND_GET, COMMAND_LINKAGE, COMMAND_NAMES, COMMAND_SET, COMMAND_UNDEFINE }; int index; TreeItem item; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, doHeaders ? "command header ?arg ...?" : "command item ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[3], commandNames, "command", 0, &index) != TCL_OK) return TCL_ERROR; switch (index) { /* T item state define stateName */ case COMMAND_DEFINE: { char *string; int i, length, slot = -1; if (objc != 5) { Tcl_WrongNumArgs(interp, 4, objv, "stateName"); return TCL_ERROR; } string = Tcl_GetStringFromObj(objv[4], &length); if (!length || (*string == '~') || (*string == '!')) { FormatResult(interp, "invalid state name \"%s\"", string); return TCL_ERROR; } for (i = 0; i < 32; i++) { if (domainPtr->stateNames[i] == NULL) { if (slot == -1) slot = i; continue; } if (strcmp(domainPtr->stateNames[i], string) == 0) { FormatResult(interp, "state \"%s\" already defined in domain \"%s\"", string, domainPtr->name); return TCL_ERROR; } } if (slot == -1) { FormatResult(interp, "cannot define any more states in domain \"%s\"", domainPtr->name); return TCL_ERROR; } domainPtr->stateNames[slot] = ckalloc(length + 1); strcpy(domainPtr->stateNames[slot], string); break; } /* T item state forcolumn I C ?stateList? */ case COMMAND_FORCOLUMN: { TreeItemList itemList; TreeColumnList columns; TreeColumn treeColumn; Tcl_Obj *listObj; TreeItemColumn column; int columnIndex; int i, states[3], stateOn, stateOff; ItemForEach iter; ColumnForEach citer; int flags = IFO_NOT_NULL; int result = TCL_OK; if (objc < 6 || objc > 7) { Tcl_WrongNumArgs(interp, 4, objv, doHeaders ? "header column ?stateList?" : "item column ?stateList?"); return TCL_ERROR; } /* Without a stateList only one item is accepted. */ if (objc == 6) flags |= IFO_NOT_MANY; if (doHeaders) { if (TreeHeaderList_FromObj(tree, objv[4], &itemList, flags) != TCL_OK) return TCL_ERROR; } else { if (TreeItemList_FromObj(tree, objv[4], &itemList, flags) != TCL_OK) return TCL_ERROR; } TreeColumnList_Init(tree, &columns, 0); if (objc == 6) { item = TreeItemList_Nth(&itemList, 0); if (TreeItem_ColumnFromObj(tree, item, objv[5], &column, NULL, &columnIndex, CFO_NOT_NULL | CFO_NOT_TAIL) != TCL_OK) { result = TCL_ERROR; goto doneFORC; } if ((column == NULL) || !column->cstate) goto doneFORC; listObj = Tcl_NewListObj(0, NULL); for (i = 0; i < 32; i++) { if (domainPtr->stateNames[i] == NULL) continue; if (column->cstate & (1L << i)) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(domainPtr->stateNames[i], -1)); } } Tcl_SetObjResult(interp, listObj); goto doneFORC; } if (TreeColumnList_FromObj(tree, objv[5], &columns, CFO_NOT_NULL | tailFlag) != TCL_OK) { result = TCL_ERROR; goto doneFORC; } if (Tree_StateFromListObj(tree, domain, objv[6], states, SFO_NOT_STATIC) != TCL_OK) { result = TCL_ERROR; goto doneFORC; } if ((states[0] | states[1] | states[2]) == 0) goto doneFORC; ITEM_FOR_EACH(item, &itemList, NULL, &iter) { COLUMN_FOR_EACH(treeColumn, &columns, NULL, &citer) { columnIndex = TreeColumn_Index(treeColumn); column = Item_CreateColumn(tree, item, columnIndex, NULL); stateOn = states[STATE_OP_ON]; stateOff = states[STATE_OP_OFF]; stateOn |= ~column->cstate & states[STATE_OP_TOGGLE]; stateOff |= column->cstate & states[STATE_OP_TOGGLE]; TreeItemColumn_ChangeState(tree, item, column, treeColumn, stateOff, stateOn); } } doneFORC: TreeColumnList_Free(&columns); TreeItemList_Free(&itemList); return result; } /* T item state get I ?state? */ case COMMAND_GET: { Tcl_Obj *listObj; int i, states[3]; if (objc < 5 || objc > 6) { Tcl_WrongNumArgs(interp, 4, objv, doHeaders ? "header ?state?" : "item ?state?"); return TCL_ERROR; } if (doHeaders) { TreeItemList itemList; if (TreeHeaderList_FromObj(tree, objv[4], &itemList, IFO_NOT_NULL | IFO_NOT_MANY) != TCL_OK) return TCL_ERROR; item = TreeItemList_Nth(&itemList, 0); TreeItemList_Free(&itemList); } else { if (TreeItem_FromObj(tree, objv[4], &item, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; } if (objc == 6) { states[STATE_OP_ON] = 0; if (Tree_StateFromObj(tree, domain, objv[5], states, NULL, SFO_NOT_OFF | SFO_NOT_TOGGLE) != TCL_OK) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewBooleanObj((item->state & states[STATE_OP_ON]) != 0)); break; } listObj = Tcl_NewListObj(0, NULL); for (i = 0; i < 32; i++) { if (domainPtr->stateNames[i] == NULL) continue; if (item->state & (1L << i)) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(domainPtr->stateNames[i], -1)); } } Tcl_SetObjResult(interp, listObj); break; } /* T item state linkage state */ case COMMAND_LINKAGE: { int index; if (objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "state"); return TCL_ERROR; } if (Tree_StateFromObj(tree, domain, objv[4], NULL, &index, SFO_NOT_OFF | SFO_NOT_TOGGLE) != TCL_OK) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewStringObj( (index < domainPtr->staticCount) ? "static" : "dynamic", -1)); break; } /* T item state names */ case COMMAND_NAMES: { Tcl_Obj *listObj; int i; if (objc != 4) { Tcl_WrongNumArgs(interp, 4, objv, (char *) NULL); return TCL_ERROR; } listObj = Tcl_NewListObj(0, NULL); for (i = domainPtr->staticCount; i < 32; i++) { if (domainPtr->stateNames[i] != NULL) Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(domainPtr->stateNames[i], -1)); } Tcl_SetObjResult(interp, listObj); break; } /* T item state set I ?I? {state ...} */ case COMMAND_SET: { TreeItemList itemList, item2List; int states[3], stateOn, stateOff; ItemForEach iter; int result = TCL_OK; if (objc < 6 || objc > 7) { Tcl_WrongNumArgs(interp, 4, objv, doHeaders ? "header ?last? stateList" : "item ?last? stateList"); return TCL_ERROR; } if (doHeaders) { if (TreeHeaderList_FromObj(tree, objv[4], &itemList, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; } else { if (TreeItemList_FromObj(tree, objv[4], &itemList, IFO_NOT_NULL) != TCL_OK) return TCL_ERROR; } if (objc == 6) { TreeItemList_Init(tree, &item2List, 0); } if (objc == 7) { if (TreeItemList_FromObj(tree, objv[5], &item2List, IFO_NOT_NULL) != TCL_OK) { result = TCL_ERROR; goto doneSET; } } if (Tree_StateFromListObj(tree, domain, objv[objc - 1], states, SFO_NOT_STATIC) != TCL_OK) { result = TCL_ERROR; goto doneSET; } if ((states[0] | states[1] | states[2]) == 0) goto doneSET; ITEM_FOR_EACH(item, &itemList, &item2List, &iter) { stateOn = states[STATE_OP_ON]; stateOff = states[STATE_OP_OFF]; stateOn |= ~item->state & states[STATE_OP_TOGGLE]; stateOff |= item->state & states[STATE_OP_TOGGLE]; TreeItem_ChangeState(tree, item, stateOff, stateOn); } if (iter.error) result = TCL_ERROR; doneSET: TreeItemList_Free(&itemList); TreeItemList_Free(&item2List); return result; } /* T item state undefine ?state ...? */ case COMMAND_UNDEFINE: { int i, index; for (i = 4; i < objc; i++) { if (Tree_StateFromObj(tree, domain, objv[i], NULL, &index, SFO_NOT_STATIC | SFO_NOT_OFF | SFO_NOT_TOGGLE) != TCL_OK) return TCL_ERROR; Tree_UndefineState(tree, domain, 1L << index); PerStateInfo_Undefine(tree, &pstBitmap, &tree->buttonBitmap, domain, 1L << index); PerStateInfo_Undefine(tree, &pstImage, &tree->buttonImage, domain, 1L << index); ckfree(domainPtr->stateNames[index]); domainPtr->stateNames[index] = NULL; } break; } } return TCL_OK; } static int ItemStateCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; return TreeItemCmd_State(tree, objc, objv, FALSE); } /* *---------------------------------------------------------------------- * * ItemTagCmd -- * * This procedure is invoked to process the [item tag] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeItemCmd_Tag( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int doHeaders /* TRUE to operate on headers, FALSE * to operate on items. */ ) { Tcl_Interp *interp = tree->interp; static CONST char *commandNames[] = { "add", "expr", "names", "remove", (char *) NULL }; enum { COMMAND_ADD, COMMAND_EXPR, COMMAND_NAMES, COMMAND_REMOVE }; int index; ItemForEach iter; TreeItemList items; TreeItem item; int result = TCL_OK; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[3], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { /* T item tag add I tagList */ case COMMAND_ADD: { int i, numTags; Tcl_Obj **listObjv; Tk_Uid staticTags[STATIC_SIZE], *tags = staticTags; if (objc != 6) { Tcl_WrongNumArgs(interp, 4, objv, doHeaders ? "header tagList" : "item tagList"); return TCL_ERROR; } if (doHeaders) { if (TreeHeaderList_FromObj(tree, objv[4], &items, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } } else { if (TreeItemList_FromObj(tree, objv[4], &items, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } } if (Tcl_ListObjGetElements(interp, objv[5], &numTags, &listObjv) != TCL_OK) { result = TCL_ERROR; break; } STATIC_ALLOC(tags, Tk_Uid, numTags); for (i = 0; i < numTags; i++) { tags[i] = Tk_GetUid(Tcl_GetString(listObjv[i])); } ITEM_FOR_EACH(item, &items, NULL, &iter) { item->tagInfo = TagInfo_Add(tree, item->tagInfo, tags, numTags); } STATIC_FREE(tags, Tk_Uid, numTags); break; } /* T item tag expr I tagExpr */ case COMMAND_EXPR: { TagExpr expr; int ok = TRUE; if (objc != 6) { Tcl_WrongNumArgs(interp, 4, objv, doHeaders ? "header tagExpr" : "item tagExpr"); return TCL_ERROR; } if (doHeaders) { if (TreeHeaderList_FromObj(tree, objv[4], &items, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } } else { if (TreeItemList_FromObj(tree, objv[4], &items, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } } if (TagExpr_Init(tree, objv[5], &expr) != TCL_OK) { result = TCL_ERROR; break; } ITEM_FOR_EACH(item, &items, NULL, &iter) { if (!TagExpr_Eval(&expr, item->tagInfo)) { ok = FALSE; break; } } TagExpr_Free(&expr); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(ok)); break; } /* T item tag names I */ case COMMAND_NAMES: { Tcl_Obj *listObj; Tk_Uid *tags = NULL; int i, tagSpace = 0, numTags = 0; if (objc != 5) { Tcl_WrongNumArgs(interp, 4, objv, doHeaders ? "header" : "item"); return TCL_ERROR; } if (doHeaders) { if (TreeHeaderList_FromObj(tree, objv[4], &items, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } } else { if (TreeItemList_FromObj(tree, objv[4], &items, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } } ITEM_FOR_EACH(item, &items, NULL, &iter) { tags = TagInfo_Names(tree, item->tagInfo, tags, &numTags, &tagSpace); } if (numTags) { listObj = Tcl_NewListObj(0, NULL); for (i = 0; i < numTags; i++) { Tcl_ListObjAppendElement(NULL, listObj, Tcl_NewStringObj((char *) tags[i], -1)); } Tcl_SetObjResult(interp, listObj); ckfree((char *) tags); } break; } /* T item tag remove I tagList */ case COMMAND_REMOVE: { int i, numTags; Tcl_Obj **listObjv; Tk_Uid staticTags[STATIC_SIZE], *tags = staticTags; if (objc != 6) { Tcl_WrongNumArgs(interp, 4, objv, doHeaders ? "header tagList" : "item tagList"); return TCL_ERROR; } if (doHeaders) { if (TreeHeaderList_FromObj(tree, objv[4], &items, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } } else { if (TreeItemList_FromObj(tree, objv[4], &items, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } } if (Tcl_ListObjGetElements(interp, objv[5], &numTags, &listObjv) != TCL_OK) { result = TCL_ERROR; break; } STATIC_ALLOC(tags, Tk_Uid, numTags); for (i = 0; i < numTags; i++) { tags[i] = Tk_GetUid(Tcl_GetString(listObjv[i])); } ITEM_FOR_EACH(item, &items, NULL, &iter) { item->tagInfo = TagInfo_Remove(tree, item->tagInfo, tags, numTags); } STATIC_FREE(tags, Tk_Uid, numTags); break; } } TreeItemList_Free(&items); return result; } static int ItemTagCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; return TreeItemCmd_Tag(tree, objc, objv, FALSE); } /* *---------------------------------------------------------------------- * * TreeItem_GetTagInfo -- * * Returns item->tagInfo. * * Results: * TagInfo pointer or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TagInfo * TreeItem_GetTagInfo( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return item->tagInfo; } #ifdef SELECTION_VISIBLE /* *---------------------------------------------------------------------- * * Tree_DeselectHidden -- * * Removes any selected items which are no longer ReallyVisible() * from the selection. * * Results: * None. * * Side effects: * event may be generated. * *---------------------------------------------------------------------- */ /* * FIXME: optimize all calls to this routine. * Optionally call Tree_DInfoChanged(tree, DINFO_REDO_SELECTION) instead. */ void Tree_DeselectHidden( TreeCtrl *tree /* Widget info. */ ) { TreeItemList items; Tcl_HashEntry *hPtr; Tcl_HashSearch search; TreeItem item; int i; if (tree->selectCount < 1) return; /* This call is slow for large lists. */ Tree_UpdateItemIndex(tree); TreeItemList_Init(tree, &items, tree->selectCount); hPtr = Tcl_FirstHashEntry(&tree->selection, &search); while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashKey(&tree->selection, hPtr); if (!TreeItem_ReallyVisible(tree, item)) TreeItemList_Append(&items, item); hPtr = Tcl_NextHashEntry(&search); } for (i = 0; i < TreeItemList_Count(&items); i++) Tree_RemoveFromSelection(tree, TreeItemList_Nth(&items, i)); if (TreeItemList_Count(&items)) { TreeNotify_Selection(tree, NULL, &items); } TreeItemList_Free(&items); } #endif /* SELECTION_VISIBLE */ /* *---------------------------------------------------------------------- * * TreeItemCmd -- * * This procedure is invoked to process the [item] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeItemCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; enum { COMMAND_ANCESTORS, COMMAND_BBOX, COMMAND_BUTTONSTATE, COMMAND_CGET, COMMAND_CHILDREN, COMMAND_COLLAPSE, COMMAND_COMPARE, #ifdef DEPRECATED COMMAND_COMPLEX, #endif COMMAND_CONFIGURE, COMMAND_COUNT, COMMAND_CREATE, COMMAND_DELETE, COMMAND_DESCENDANTS, COMMAND_DUMP, COMMAND_ELEMENT, COMMAND_ENABLED, COMMAND_EXPAND, COMMAND_FIRSTCHILD, COMMAND_ID, COMMAND_IMAGE, COMMAND_ISANCESTOR, COMMAND_ISOPEN, COMMAND_LASTCHILD, COMMAND_NEXTSIBLING, COMMAND_NUMCHILDREN, COMMAND_ORDER, COMMAND_PARENT, COMMAND_PREVSIBLING, COMMAND_RANGE, COMMAND_REMOVE, COMMAND_RNC, COMMAND_SORT, COMMAND_SPAN, COMMAND_STATE, COMMAND_STYLE, COMMAND_TAG, COMMAND_TEXT, COMMAND_TOGGLE }; /* AF_xxx must not conflict with IFO_xxx. */ #define AF_NOT_ANCESTOR 0x00010000 /* item can't be ancestor of other item */ #define AF_NOT_EQUAL 0x00020000 /* second item can't be same as first */ #define AF_SAMEROOT 0x00040000 /* both items must be descendants of a * common ancestor */ #define AF_NOT_ITEM 0x00080000 /* arg is not an Item */ #define AF_NOT_DELETED 0x00100000 /* item can't be deleted */ struct { char *cmdName; int minArgs; int maxArgs; int flags; /* AF_xxx | IFO_xxx for 1st arg. */ int flags2; /* AF_xxx | IFO_xxx for 2nd arg. */ int flags3; /* AF_xxx | IFO_xxx for 3rd arg. */ char *argString; Tcl_ObjCmdProc *proc; } argInfo[] = { { "ancestors", 1, 1, IFO_NOT_MANY | IFO_NOT_NULL, 0, 0, "item", NULL }, { "bbox", 0, 0, 0, 0, 0, NULL, ItemBboxCmd }, { "buttonstate", 1, 2, IFO_NOT_MANY | IFO_NOT_NULL, AF_NOT_ITEM, 0, "item ?state?", NULL }, { "cget", 2, 2, IFO_NOT_MANY | IFO_NOT_NULL, AF_NOT_ITEM, 0, "item option", NULL }, { "children", 1, 1, IFO_NOT_MANY | IFO_NOT_NULL, 0, 0, "item", NULL }, { "collapse", 1, 2, IFO_NOT_NULL, AF_NOT_ITEM, 0, "item ?-recurse?", NULL}, { "compare", 3, 3, IFO_NOT_MANY | IFO_NOT_NULL, AF_NOT_ITEM, IFO_NOT_MANY | IFO_NOT_NULL, "item1 op item2", NULL }, #ifdef DEPRECATED { "complex", 2, 100000, IFO_NOT_MANY | IFO_NOT_NULL, AF_NOT_ITEM, AF_NOT_ITEM, "item list ...", NULL }, #endif { "configure", 1, 100000, IFO_NOT_NULL, AF_NOT_ITEM, AF_NOT_ITEM, "item ?option? ?value? ?option value ...?", NULL }, { "count", 0, 1, 0, 0, 0, "?itemDesc?" , NULL}, { "create", 0, 0, 0, 0, 0, NULL, ItemCreateCmd }, { "delete", 1, 2, IFO_NOT_NULL, IFO_NOT_NULL | AF_SAMEROOT, 0, "first ?last?", NULL }, { "descendants", 1, 1, IFO_NOT_MANY | IFO_NOT_NULL, 0, 0, "item", NULL }, { "dump", 1, 1, IFO_NOT_MANY | IFO_NOT_NULL, 0, 0, "item", NULL }, { "element", 0, 0, 0, 0, 0, NULL, ItemElementCmd }, { "enabled", 1, 2, IFO_NOT_NULL, AF_NOT_ITEM, 0, "item ?boolean?", NULL }, { "expand", 1, 2, IFO_NOT_NULL, AF_NOT_ITEM, 0, "item ?-recurse?", NULL}, { "firstchild", 1, 2, IFO_NOT_MANY | IFO_NOT_NULL | AF_NOT_DELETED, IFO_NOT_MANY | IFO_NOT_NULL | IFO_NOT_ROOT | AF_NOT_ANCESTOR | AF_NOT_EQUAL | AF_NOT_DELETED, 0, "item ?newFirstChild?", NULL }, { "id", 1, 1, 0, 0, 0, "item", NULL }, { "image", 0, 0, 0, 0, 0, NULL, ItemImageCmd }, { "isancestor", 2, 2, IFO_NOT_MANY | IFO_NOT_NULL, IFO_NOT_MANY | IFO_NOT_NULL, 0, "item item2", NULL }, { "isopen", 1, 1, IFO_NOT_MANY | IFO_NOT_NULL, 0, 0, "item", NULL }, { "lastchild", 1, 2, IFO_NOT_MANY | IFO_NOT_NULL | AF_NOT_DELETED, IFO_NOT_MANY | IFO_NOT_NULL | IFO_NOT_ROOT | AF_NOT_ANCESTOR | AF_NOT_EQUAL | AF_NOT_DELETED, 0, "item ?newLastChild?", NULL }, { "nextsibling", 1, 2, IFO_NOT_MANY | IFO_NOT_NULL | IFO_NOT_ROOT | IFO_NOT_ORPHAN, IFO_NOT_MANY | IFO_NOT_NULL | IFO_NOT_ROOT | AF_NOT_ANCESTOR | AF_NOT_EQUAL, 0, "item ?newNextSibling?", NULL }, { "numchildren", 1, 1, IFO_NOT_MANY | IFO_NOT_NULL, 0, 0, "item", NULL }, { "order", 1, 2, IFO_NOT_MANY | IFO_NOT_NULL, AF_NOT_ITEM, 0, "item ?-visible?", NULL }, { "parent", 1, 1, IFO_NOT_MANY | IFO_NOT_NULL, 0, 0, "item", NULL }, { "prevsibling", 1, 2, IFO_NOT_MANY | IFO_NOT_NULL | IFO_NOT_ROOT | IFO_NOT_ORPHAN, IFO_NOT_MANY | IFO_NOT_NULL | IFO_NOT_ROOT | AF_NOT_ANCESTOR | AF_NOT_EQUAL, 0, "item ?newPrevSibling?", NULL }, { "range", 2, 2, IFO_NOT_MANY | IFO_NOT_NULL, IFO_NOT_MANY | IFO_NOT_NULL | AF_SAMEROOT, 0, "first last", NULL }, { "remove", 1, 1, IFO_NOT_NULL | IFO_NOT_ROOT, 0, 0, "item", NULL }, { "rnc", 1, 1, IFO_NOT_MANY | IFO_NOT_NULL, 0, 0, "item", NULL }, { "sort", 0, 0, 0, 0, 0, NULL, ItemSortCmd }, { "span", 0, 0, 0, 0, 0, NULL, ItemSpanCmd }, { "state", 0, 0, 0, 0, 0, NULL, ItemStateCmd }, { "style", 0, 0, 0, 0, 0, NULL, ItemStyleCmd }, { "tag", 0, 0, 0, 0, 0, NULL, ItemTagCmd }, { "text", 0, 0, 0, 0, 0, NULL, ItemTextCmd }, { "toggle", 1, 2, IFO_NOT_NULL, AF_NOT_ITEM, 0, "item ?-recurse?", NULL}, { NULL } }; int index; int numArgs = objc - 3; TreeItemList itemList, item2List; TreeItem item = NULL, item2 = NULL, child; ItemForEach iter; int result = TCL_OK; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObjStruct(interp, objv[2], argInfo, sizeof(argInfo[0]), "command", 0, &index) != TCL_OK) { return TCL_ERROR; } if (argInfo[index].proc != NULL) return argInfo[index].proc(clientData, interp, objc, objv); if ((numArgs < argInfo[index].minArgs) || (numArgs > argInfo[index].maxArgs)) { Tcl_WrongNumArgs(interp, 3, objv, argInfo[index].argString); return TCL_ERROR; } TreeItemList_Init(tree, &itemList, 0); TreeItemList_Init(tree, &item2List, 0); if ((numArgs >= 1) && !(argInfo[index].flags & AF_NOT_ITEM)) { if (TreeItemList_FromObj(tree, objv[3], &itemList, argInfo[index].flags & 0xFFFF) != TCL_OK) { goto errorExit; } item = TreeItemList_Nth(&itemList, 0); /* May be NULL. */ if ((argInfo[index].flags & AF_NOT_DELETED) && IS_DELETED(item)) { FormatResult(interp, "item %s%d is being deleted", tree->itemPrefix, item->id); goto errorExit; } } if (((numArgs >= 2) && !(argInfo[index].flags2 & AF_NOT_ITEM)) || ((numArgs >= 3) && !(argInfo[index].flags3 & AF_NOT_ITEM))) { int flags, obji; if (argInfo[index].flags2 & AF_NOT_ITEM) { obji = 5; flags = argInfo[index].flags3; } else { obji = 4; flags = argInfo[index].flags2; } if (TreeItemList_FromObj(tree, objv[obji], &item2List, flags & 0xFFFF) != TCL_OK) { goto errorExit; } ITEM_FOR_EACH(item2, &item2List, NULL, &iter) { if ((flags & AF_NOT_DELETED) && IS_DELETED(item2)) { FormatResult(interp, "item %s%d is being deleted", tree->itemPrefix, item2->id); goto errorExit; } if ((flags & AF_NOT_EQUAL) && (item == item2)) { FormatResult(interp, "item %s%d same as second item", tree->itemPrefix, item->id); goto errorExit; } if ((argInfo[index].flags & AF_NOT_ANCESTOR) && TreeItem_IsAncestor(tree, item, item2)) { FormatResult(interp, "item %s%d is ancestor of item %s%d", tree->itemPrefix, item->id, tree->itemPrefix, item2->id); goto errorExit; } if ((flags & AF_NOT_ANCESTOR) && TreeItem_IsAncestor(tree, item2, item)) { FormatResult(interp, "item %s%d is ancestor of item %s%d", tree->itemPrefix, item2->id, tree->itemPrefix, item->id); goto errorExit; } if ((flags & AF_SAMEROOT) && TreeItem_RootAncestor(tree, item) != TreeItem_RootAncestor(tree, item2)) { reqSameRoot: FormatResult(interp, "item %s%d and item %s%d don't share a common ancestor", tree->itemPrefix, item->id, tree->itemPrefix, item2->id); goto errorExit; } } item2 = TreeItemList_Nth(&item2List, 0); /* May be NULL. */ } switch (index) { case COMMAND_ANCESTORS: { Tcl_Obj *listObj; TreeItem parent = item->parent; if (parent == NULL) break; /* empty list */ listObj = Tcl_NewListObj(0, NULL); while (parent != NULL) { Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, parent)); parent = parent->parent; } Tcl_SetObjResult(interp, listObj); break; } /* T item buttonstate I ?state? */ case COMMAND_BUTTONSTATE: { static const char *stateNames[] = { "active", "normal", "pressed", NULL }; int state; if (numArgs == 2) { int prevFlags = item->flags; if (Tcl_GetIndexFromObj(interp, objv[4], stateNames, "state", 0, &state) != TCL_OK) { goto errorExit; } item->flags &= ~ITEM_FLAGS_BUTTONSTATE; if (state == 0) item->flags |= ITEM_FLAG_BUTTONSTATE_ACTIVE; else if (state == 2) item->flags |= ITEM_FLAG_BUTTONSTATE_PRESSED; if (item->flags != prevFlags && tree->columnTree != NULL) Tree_InvalidateItemDInfo(tree, tree->columnTree, item, NULL); } else { if (item->flags & ITEM_FLAG_BUTTONSTATE_ACTIVE) state = 0; else if (item->flags & ITEM_FLAG_BUTTONSTATE_PRESSED) state = 2; else state = 1; } Tcl_SetObjResult(interp, Tcl_NewStringObj(stateNames[state], -1)); break; } case COMMAND_CGET: { Tcl_Obj *resultObjPtr; resultObjPtr = Tk_GetOptionValue(interp, (char *) item, tree->itemOptionTable, objv[4], tree->tkwin); if (resultObjPtr == NULL) goto errorExit; Tcl_SetObjResult(interp, resultObjPtr); break; } case COMMAND_CHILDREN: { if (item->numChildren != 0) { Tcl_Obj *listObj; listObj = Tcl_NewListObj(0, NULL); child = item->firstChild; while (child != NULL) { Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, child)); child = child->nextSibling; } Tcl_SetObjResult(interp, listObj); } break; } case COMMAND_COLLAPSE: case COMMAND_EXPAND: case COMMAND_TOGGLE: { int animate = 0; int recurse = 0; int mode = 0; /* lint */ int i, count; TreeItemList items; if (numArgs > 1) { static const char *optionName[] = { "-animate", "-recurse", NULL }; int option; for (i = 4; i < objc; i++) { if (Tcl_GetIndexFromObj(interp, objv[i], optionName, "option", 0, &option) != TCL_OK) { goto errorExit; } switch (option) { case 0: /* -animate */ animate = 1; break; case 1: /* -recurse */ recurse = 1; break; } } } switch (index) { case COMMAND_COLLAPSE: mode = 0; break; case COMMAND_EXPAND: mode = 1; break; case COMMAND_TOGGLE: mode = -1; break; } if (animate) { Tk_Image image; Pixmap bitmap; int open; if (IS_ALL(item) || TreeItemList_Count(&itemList) != 1) { FormatResult(interp, "only 1 item may be specified with -animate"); goto errorExit; } image = PerStateImage_ForState(tree, &tree->buttonImage, item->state, NULL); bitmap = PerStateBitmap_ForState(tree, &tree->buttonBitmap, item->state, NULL); if (image != NULL || bitmap != None || !tree->useTheme || !TreeItem_HasButton(tree, item)) { TreeItem_OpenClose(tree, item, mode); break; } open = (item->state & STATE_ITEM_OPEN) != 0; if (mode == -1 || open != mode) { (void) TreeTheme_AnimateButtonStart(tree, item); } break; } TreeItemList_Init(tree, &items, 0); ITEM_FOR_EACH(item, &itemList, NULL, &iter) { TreeItemList_Append(&items, item); if (!iter.all && recurse) { TreeItem_ListDescendants(tree, item, &items); } } count = TreeItemList_Count(&items); for (i = 0; i < count; i++) { item = TreeItemList_Nth(&items, i); TreeItem_OpenClose(tree, item, mode); } TreeItemList_Free(&items); #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif break; } /* T item compare I op I */ case COMMAND_COMPARE: { static CONST char *opName[] = { "<", "<=", "==", ">=", ">", "!=", NULL }; enum { COP_LT, COP_LE, COP_EQ, COP_GE, COP_GT, COP_NE }; int op, compare = 0, index1 = 0, index2 = 0; if (Tcl_GetIndexFromObj(interp, objv[4], opName, "comparison operator", 0, &op) != TCL_OK) { goto errorExit; } if (op != COP_EQ && op != COP_NE) { if (TreeItem_RootAncestor(tree, item) != TreeItem_RootAncestor(tree, item2)) { goto reqSameRoot; } TreeItem_ToIndex(tree, item, &index1, NULL); TreeItem_ToIndex(tree, item2, &index2, NULL); } switch (op) { case COP_LT: compare = index1 < index2; break; case COP_LE: compare = index1 <= index2; break; case COP_EQ: compare = item == item2; break; case COP_GE: compare = index1 >= index2; break; case COP_GT: compare = index1 > index2; break; case COP_NE: compare = item != item2; break; } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(compare)); break; } #ifdef DEPRECATED case COMMAND_COMPLEX: { int i, j, columnIndex; int objc1, objc2; Tcl_Obj **objv1, **objv2; TreeColumn treeColumn = tree->columns; TreeItemColumn column; int eMask, cMask, iMask = 0; if (objc <= 4) break; columnIndex = 0; for (i = 4; i < objc; i++, columnIndex++, treeColumn = TreeColumn_Next(treeColumn)) { if (treeColumn == NULL) { FormatResult(interp, "column #%d doesn't exist", columnIndex); result = TCL_ERROR; goto doneComplex; } column = TreeItem_FindColumn(tree, item, columnIndex); if (column == NULL) { FormatResult(interp, "item %s%d doesn't have column %s%d", tree->itemPrefix, item->id, tree->columnPrefix, TreeColumn_GetID(treeColumn)); result = TCL_ERROR; goto doneComplex; } /* List of element-configs per column */ if (Tcl_ListObjGetElements(interp, objv[i], &objc1, &objv1) != TCL_OK) { result = TCL_ERROR; goto doneComplex; } if (objc1 == 0) continue; if (column->style == NULL) { FormatResult(interp, "item %s%d column %s%d has no style", tree->itemPrefix, item->id, tree->columnPrefix, TreeColumn_GetID(treeColumn)); result = TCL_ERROR; goto doneComplex; } cMask = 0; for (j = 0; j < objc1; j++) { /* elem option value... */ if (Tcl_ListObjGetElements(interp, objv1[j], &objc2, &objv2) != TCL_OK) { result = TCL_ERROR; goto doneComplex; } if (objc2 < 3) { FormatResult(interp, "wrong # args: should be \"element option value ...\""); result = TCL_ERROR; goto doneComplex; } if (TreeStyle_ElementConfigureFromObj(tree, item, column, column->style, objv2[0], objc2 - 1, objv2 + 1, &eMask) != TCL_OK) { result = TCL_ERROR; goto doneComplex; } cMask |= eMask; iMask |= eMask; } if (cMask & CS_LAYOUT) TreeItemColumn_InvalidateSize(tree, column); } doneComplex: if (iMask & CS_DISPLAY) Tree_InvalidateItemDInfo(tree, NULL, item, NULL); if (iMask & CS_LAYOUT) { TreeColumns_InvalidateWidthOfItems(tree, NULL); TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); Tree_DInfoChanged(tree, DINFO_REDO_RANGES); } break; } #endif /* DEPRECATED*/ /* T item configure I ?option? ?value? ?option value ...? */ case COMMAND_CONFIGURE: { if (objc <= 5) { Tcl_Obj *resultObjPtr; if (IS_ALL(item) || (TreeItemList_Count(&itemList) > 1)) { NotManyMsg(tree, FALSE); goto errorExit; } resultObjPtr = Tk_GetOptionInfo(interp, (char *) item, tree->itemOptionTable, (objc == 4) ? (Tcl_Obj *) NULL : objv[4], tree->tkwin); if (resultObjPtr == NULL) goto errorExit; Tcl_SetObjResult(interp, resultObjPtr); break; } ITEM_FOR_EACH(item, &itemList, NULL, &iter) { result = Item_Configure(tree, item, objc - 4, objv + 4); if (result != TCL_OK) break; } break; } case COMMAND_COUNT: { int count = tree->itemCount; if (objc == 4) { count = 0; ITEM_FOR_EACH(item, &itemList, &item2List, &iter) { count++; } } Tcl_SetObjResult(interp, Tcl_NewIntObj(count)); break; } case COMMAND_DELETE: { TreeItemList deleted, selected; int i, count; /* The root is never deleted */ if (tree->itemCount == 1) break; if (objc == 5) { if (item == NULL || item2 == NULL) { FormatResult(interp, "invalid range \"%s\" to \"%s\"", Tcl_GetString(objv[3]), Tcl_GetString(objv[4])); goto errorExit; } } /* * ITEM_FLAG_DELETED prevents us from adding the same item * twice to the 'deleted' list. It also prevents nested * calls to this command (through binding scripts) deleting * the same item twice. */ TreeItemList_Init(tree, &deleted, tree->itemCount - 1); TreeItemList_Init(tree, &selected, tree->selectCount); ITEM_FOR_EACH(item, &itemList, &item2List, &iter) { if (IS_ROOT(item)) continue; if (IS_DELETED(item)) continue; item->flags |= ITEM_FLAG_DELETED; TreeItemList_Append(&deleted, item); if (TreeItem_GetSelected(tree, item)) TreeItemList_Append(&selected, item); if (iter.all) continue; /* Check every descendant. */ if (item->firstChild == NULL) continue; item2 = item; while (item2->lastChild != NULL) item2 = item2->lastChild; item = item->firstChild; while (1) { if (IS_DELETED(item)) { /* Skip all descendants (they are already flagged). */ while (item->lastChild != NULL) item = item->lastChild; } else { item->flags |= ITEM_FLAG_DELETED; TreeItemList_Append(&deleted, item); if (TreeItem_GetSelected(tree, item)) TreeItemList_Append(&selected, item); } if (item == item2) break; item = TreeItem_Next(tree, item); } } count = TreeItemList_Count(&selected); if (count) { for (i = 0; i < count; i++) { item = TreeItemList_Nth(&selected, i); Tree_RemoveFromSelection(tree, item); } /* Generate event for selected items being deleted. */ TreeNotify_Selection(tree, NULL, &selected); } count = TreeItemList_Count(&deleted); if (count) { int redoColumns = 0; /* Generate event for items being deleted. */ TreeNotify_ItemDeleted(tree, &deleted); /* Remove every item from its parent. Needed because items * are deleted recursively. */ for (i = 0; i < count; i++) { item = TreeItemList_Nth(&deleted, i); /* Deleting a visible item may change the needed width * of any column. */ if (TreeItem_ReallyVisible(tree, item)) redoColumns = 1; TreeItem_RemoveFromParent(tree, item); } /* Delete the items. The item record will be freed when no * longer in use; however, the item cannot be referred to * by commands from this point on. */ for (i = 0; i < count; i++) { item = TreeItemList_Nth(&deleted, i); TreeItem_Delete(tree, item); } if (redoColumns) { TreeColumns_InvalidateWidthOfItems(tree, NULL); TreeColumns_InvalidateSpans(tree); } } TreeItemList_Free(&selected); TreeItemList_Free(&deleted); break; } case COMMAND_DESCENDANTS: { Tcl_Obj *listObj; if (item->firstChild == NULL) break; item2 = item; while (item2->lastChild != NULL) item2 = item2->lastChild; item = item->firstChild; listObj = Tcl_NewListObj(0, NULL); while (1) { Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, item)); if (item == item2) break; item = TreeItem_Next(tree, item); } Tcl_SetObjResult(interp, listObj); break; } case COMMAND_DUMP: { Tree_UpdateItemIndex(tree); FormatResult(interp, "index %d indexVis %d", item->index, item->indexVis); break; } /* T item enabled I ?boolean? */ case COMMAND_ENABLED: { int enabled; TreeItemList newD; int stateOff, stateOn; if (objc == 4) { if (IS_ALL(item) || (TreeItemList_Count(&itemList) > 1)) { NotManyMsg(tree, FALSE); goto errorExit; } Tcl_SetObjResult(interp, Tcl_NewBooleanObj(item->state & STATE_ITEM_ENABLED)); break; } if (Tcl_GetBooleanFromObj(interp, objv[4], &enabled) != TCL_OK) goto errorExit; stateOff = enabled ? 0 : STATE_ITEM_ENABLED; stateOn = enabled ? STATE_ITEM_ENABLED : 0; TreeItemList_Init(tree, &newD, tree->selectCount); ITEM_FOR_EACH(item, &itemList, NULL, &iter) { if (enabled != TreeItem_GetEnabled(tree, item)) { TreeItem_ChangeState(tree, item, stateOff, stateOn); /* Disabled items cannot be selected. */ if (!enabled && TreeItem_GetSelected(tree, item)) { Tree_RemoveFromSelection(tree, item); TreeItemList_Append(&newD, item); } } } if (TreeItemList_Count(&newD)) TreeNotify_Selection(tree, NULL, &newD); TreeItemList_Free(&newD); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(enabled)); break; } case COMMAND_FIRSTCHILD: { if (item2 != NULL && item2 != item->firstChild) { TreeItem_RemoveFromParent(tree, item2); item2->nextSibling = item->firstChild; if (item->firstChild != NULL) item->firstChild->prevSibling = item2; else item->lastChild = item2; item->firstChild = item2; item2->parent = item; item->numChildren++; TreeItem_AddToParent(tree, item2); #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif } if (item->firstChild != NULL) Tcl_SetObjResult(interp, TreeItem_ToObj(tree, item->firstChild)); break; } /* T item id I */ case COMMAND_ID: { Tcl_Obj *listObj; listObj = Tcl_NewListObj(0, NULL); ITEM_FOR_EACH(item, &itemList, NULL, &iter) { Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, item)); } Tcl_SetObjResult(interp, listObj); break; } case COMMAND_ISANCESTOR: { Tcl_SetObjResult(interp, Tcl_NewBooleanObj( TreeItem_IsAncestor(tree, item, item2))); break; } case COMMAND_ISOPEN: { Tcl_SetObjResult(interp, Tcl_NewBooleanObj(item->state & STATE_ITEM_OPEN)); break; } case COMMAND_LASTCHILD: { /* Don't allow non-deleted items to become children of a * deleted item. */ if (item2 != NULL && item2 != item->lastChild) { TreeItem_RemoveFromParent(tree, item2); item2->prevSibling = item->lastChild; if (item->lastChild != NULL) item->lastChild->nextSibling = item2; else item->firstChild = item2; item->lastChild = item2; item2->parent = item; item->numChildren++; TreeItem_AddToParent(tree, item2); #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif } if (item->lastChild != NULL) Tcl_SetObjResult(interp, TreeItem_ToObj(tree, item->lastChild)); break; } case COMMAND_NEXTSIBLING: { if (item2 != NULL && item2 != item->nextSibling) { TreeItem_RemoveFromParent(tree, item2); item2->prevSibling = item; if (item->nextSibling != NULL) { item->nextSibling->prevSibling = item2; item2->nextSibling = item->nextSibling; } else item->parent->lastChild = item2; item->nextSibling = item2; item2->parent = item->parent; item->parent->numChildren++; TreeItem_AddToParent(tree, item2); #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif } if (item->nextSibling != NULL) Tcl_SetObjResult(interp, TreeItem_ToObj(tree, item->nextSibling)); break; } case COMMAND_NUMCHILDREN: { Tcl_SetObjResult(interp, Tcl_NewIntObj(item->numChildren)); break; } /* T item order I ?-visible? */ case COMMAND_ORDER: { int visible = FALSE; if (objc == 5) { int len; char *s = Tcl_GetStringFromObj(objv[4], &len); if ((s[0] == '-') && (strncmp(s, "-visible", len) == 0)) visible = TRUE; else { FormatResult(interp, "bad switch \"%s\": must be -visible", s); goto errorExit; } } Tree_UpdateItemIndex(tree); Tcl_SetObjResult(interp, Tcl_NewIntObj(visible ? item->indexVis : item->index)); break; } /* T item range I I */ case COMMAND_RANGE: { TreeItem itemFirst = item; TreeItem itemLast = item2; Tcl_Obj *listObj; if (itemFirst == itemLast) { Tcl_SetObjResult(interp, TreeItem_ToObj(tree, itemFirst)); break; } (void) TreeItem_FirstAndLast(tree, &itemFirst, &itemLast); listObj = Tcl_NewListObj(0, NULL); while (itemFirst != NULL) { Tcl_ListObjAppendElement(interp, listObj, TreeItem_ToObj(tree, itemFirst)); if (itemFirst == itemLast) break; itemFirst = TreeItem_Next(tree, itemFirst); } Tcl_SetObjResult(interp, listObj); break; } case COMMAND_PARENT: { if (item->parent != NULL) Tcl_SetObjResult(interp, TreeItem_ToObj(tree, item->parent)); break; } case COMMAND_PREVSIBLING: { if (item2 != NULL && item2 != item->prevSibling) { TreeItem_RemoveFromParent(tree, item2); item2->nextSibling = item; if (item->prevSibling != NULL) { item->prevSibling->nextSibling = item2; item2->prevSibling = item->prevSibling; } else item->parent->firstChild = item2; item->prevSibling = item2; item2->parent = item->parent; item->parent->numChildren++; TreeItem_AddToParent(tree, item2); #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif } if (item->prevSibling != NULL) Tcl_SetObjResult(interp, TreeItem_ToObj(tree, item->prevSibling)); break; } case COMMAND_REMOVE: { int removed = FALSE; ITEM_FOR_EACH(item, &itemList, NULL, &iter) { if (item->parent != NULL) { TreeItem_RemoveFromParent(tree, item); Tree_FreeItemDInfo(tree, item, NULL); removed = TRUE; } } if (!removed) break; if (tree->debug.enable && tree->debug.data) Tree_Debug(tree); TreeColumns_InvalidateWidthOfItems(tree, NULL); TreeColumns_InvalidateSpans(tree); #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif break; } case COMMAND_RNC: { int row,col; if (Tree_ItemToRNC(tree, item, &row, &col) == TCL_OK) FormatResult(interp, "%d %d", row, col); break; } } TreeItemList_Free(&itemList); TreeItemList_Free(&item2List); return result; errorExit: TreeItemList_Free(&itemList); TreeItemList_Free(&item2List); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeItem_Debug -- * * Perform some sanity checks on an Item and its descendants. * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_Debug( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { TreeItem child; Tcl_Interp *interp = tree->interp; int count; if (item->parent == item) { FormatResult(interp, "parent of %d is itself", item->id); return TCL_ERROR; } if (item->parent == NULL) { if (item->prevSibling != NULL) { FormatResult(interp, "parent of %d is nil, prevSibling is not nil", item->id); return TCL_ERROR; } if (item->nextSibling != NULL) { FormatResult(interp, "parent of %d is nil, nextSibling is not nil", item->id); return TCL_ERROR; } } if (item->prevSibling != NULL) { if (item->prevSibling == item) { FormatResult(interp, "prevSibling of %d is itself", item->id); return TCL_ERROR; } if (item->prevSibling->nextSibling != item) { FormatResult(interp, "item%d.prevSibling.nextSibling is not it", item->id); return TCL_ERROR; } } if (item->nextSibling != NULL) { if (item->nextSibling == item) { FormatResult(interp, "nextSibling of %d is itself", item->id); return TCL_ERROR; } if (item->nextSibling->prevSibling != item) { FormatResult(interp, "item%d.nextSibling->prevSibling is not it", item->id); return TCL_ERROR; } } if (item->numChildren < 0) { FormatResult(interp, "numChildren of %d is %d", item->id, item->numChildren); return TCL_ERROR; } if (item->numChildren == 0) { if (item->firstChild != NULL) { FormatResult(interp, "item%d.numChildren is zero, firstChild is not nil", item->id); return TCL_ERROR; } if (item->lastChild != NULL) { FormatResult(interp, "item%d.numChildren is zero, lastChild is not nil", item->id); return TCL_ERROR; } } if (item->numChildren > 0) { if (item->firstChild == NULL) { FormatResult(interp, "item%d.firstChild is nil", item->id); return TCL_ERROR; } if (item->firstChild == item) { FormatResult(interp, "item%d.firstChild is itself", item->id); return TCL_ERROR; } if (item->firstChild->parent != item) { FormatResult(interp, "item%d.firstChild.parent is not it", item->id); return TCL_ERROR; } if (item->firstChild->prevSibling != NULL) { FormatResult(interp, "item%d.firstChild.prevSibling is not nil", item->id); return TCL_ERROR; } if (item->lastChild == NULL) { FormatResult(interp, "item%d.lastChild is nil", item->id); return TCL_ERROR; } if (item->lastChild == item) { FormatResult(interp, "item%d.lastChild is itself", item->id); return TCL_ERROR; } if (item->lastChild->parent != item) { FormatResult(interp, "item%d.lastChild.parent is not it", item->id); return TCL_ERROR; } if (item->lastChild->nextSibling != NULL) { FormatResult(interp, "item%d.lastChild.nextSibling is not nil", item->id); return TCL_ERROR; } /* Count number of children */ count = 0; child = item->firstChild; while (child != NULL) { count++; child = child->nextSibling; } if (count != item->numChildren) { FormatResult(interp, "item%d.numChildren is %d, but counted %d", item->id, item->numChildren, count); return TCL_ERROR; } /* Debug each child recursively */ child = item->firstChild; while (child != NULL) { if (child->parent != item) { FormatResult(interp, "child->parent of %d is not it", item->id); return TCL_ERROR; } if (TreeItem_Debug(tree, child) != TCL_OK) return TCL_ERROR; child = child->nextSibling; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * SpanWalkProc_Identify -- * * Callback routine to TreeItem_WalkSpans for TreeItem_Identify. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SpanWalkProc_Identify( TreeCtrl *tree, TreeItem item, SpanInfo *spanPtr, StyleDrawArgs *drawArgs, ClientData clientData ) { struct { int x; int y; TreeColumn *columnPtr; TreeElement *elemPtr; } *data = clientData; if (item->header != NULL) { if ((data->x < drawArgs->x /*+ drawArgs->indent*/) || (data->x >= drawArgs->x + drawArgs->width)) return 0; } else { if ((data->x < drawArgs->x + drawArgs->indent) || (data->x >= drawArgs->x + drawArgs->width)) return 0; } (*data->columnPtr) = spanPtr->treeColumn; if ((drawArgs->style != NULL) && !TreeStyle_IsHeaderStyle(tree, drawArgs->style)) (*data->elemPtr) = TreeStyle_Identify(drawArgs, data->x, data->y); return 1; /* stop */ } /* *---------------------------------------------------------------------- * * TreeItem_Identify -- * * Determine which column and element the given point is in. * This is used by the [identify] widget command. * * Results: * If the Item is not ReallyVisible() or no columns are visible * or the given coordinates are not in a span then both the returned * column and element are NULL. Otherwise the returned column is * set to the column at the start of the span containing the coordinate; * the returned element may be NULL if the item-column has no style or * if the coordinates are not over an element. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_Identify( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int lock, /* Columns to hit-test. */ int x, int y, /* Item coords to hit-test with. */ TreeColumn *columnPtr, TreeElement *elemPtr ) { TreeRectangle tr; struct { int x; int y; TreeColumn *columnPtr; TreeElement *elemPtr; } clientData; (*columnPtr) = NULL; (*elemPtr) = NULL; if (Tree_ItemBbox(tree, item, lock, &tr) < 0) return; /* Tree_ItemBbox returns canvas coords. x/y are item coords. */ clientData.x = x; clientData.y = y; clientData.columnPtr = columnPtr; clientData.elemPtr = elemPtr; TreeItem_WalkSpans(tree, item, lock, 0, 0, TreeRect_Width(tr), TreeRect_Height(tr), WALKSPAN_IGNORE_DND, SpanWalkProc_Identify, (ClientData) &clientData); } /* *---------------------------------------------------------------------- * * SpanWalkProc_Identify2 -- * * Callback routine to TreeItem_WalkSpans for TreeItem_Identify2. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SpanWalkProc_Identify2( TreeCtrl *tree, TreeItem item, SpanInfo *spanPtr, StyleDrawArgs *drawArgs, ClientData clientData ) { Tcl_Obj *subListObj; struct { int x1; int y1; int x2; int y2; Tcl_Obj *listObj; } *data = clientData; if ((data->x2 < drawArgs->x + drawArgs->indent) || (data->x1 >= drawArgs->x + drawArgs->width)) return 0; subListObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(tree->interp, subListObj, TreeColumn_ToObj(tree, spanPtr->treeColumn)); if (drawArgs->style != NULL) { StyleDrawArgs drawArgsCopy = *drawArgs; TreeStyle_Identify2(&drawArgsCopy, data->x1, data->y1, data->x2, data->y2, subListObj); } Tcl_ListObjAppendElement(tree->interp, data->listObj, subListObj); return drawArgs->x + drawArgs->width >= data->x2; } /* *---------------------------------------------------------------------- * * TreeItem_Identify2 -- * * Determine which columns and elements intersect the given * area. This is used by the [marquee identify] widget command. * * Results: * If the Item is not ReallyVisible() or no columns are visible * then listObj is untouched. Otherwise the list is appended * with C {E ...} C {E...}. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_Identify2( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int x1, int y1, /* Top-left of area to hit-test. */ int x2, int y2, /* Bottom-right of area to hit-test. */ Tcl_Obj *listObj /* Initialized list object. */ ) { TreeRectangle tr; struct { int x1; int y1; int x2; int y2; Tcl_Obj *listObj; } clientData; if (Tree_ItemBbox(tree, item, COLUMN_LOCK_NONE, &tr) < 0) return; /* Tree_ItemBbox returns canvas coords. x1 etc are canvas coords. */ clientData.x1 = x1; clientData.y1 = y1; clientData.x2 = x2; clientData.y2 = y2; clientData.listObj = listObj; TreeItem_WalkSpans(tree, item, COLUMN_LOCK_NONE, TreeRect_Left(tr), TreeRect_Top(tr), TreeRect_Width(tr), TreeRect_Height(tr), WALKSPAN_IGNORE_DND, SpanWalkProc_Identify2, (ClientData) &clientData); } /* *---------------------------------------------------------------------- * * SpanWalkProc_GetRects -- * * Callback routine to TreeItem_WalkSpans for TreeItem_GetRects. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int SpanWalkProc_GetRects( TreeCtrl *tree, TreeItem item, SpanInfo *spanPtr, StyleDrawArgs *drawArgs, ClientData clientData ) { int objc; Tcl_Obj *CONST *objv; struct { TreeColumn treeColumn; int count; Tcl_Obj *CONST *objv; TreeRectangle *rects; int result; } *data = clientData; if (spanPtr->treeColumn != data->treeColumn) return 0; /* Bounds of span. */ if (data->count == 0) { /* Not sure why I add 'indent' but for compatibility I will leave * it in. */ data->rects[0].x = drawArgs->x + drawArgs->indent; data->rects[0].y = drawArgs->y; data->rects[0].width = drawArgs->width - drawArgs->indent; data->rects[0].height = drawArgs->height; #if 1 if (item->header != NULL) { data->rects[0].x = drawArgs->x; data->rects[0].width = drawArgs->width; } #endif data->result = 1; /* # of rects */ return 1; /* stop */ } if (drawArgs->style == NULL) { NoStyleMsg(tree, item, TreeColumn_Index(spanPtr->treeColumn)); data->result = -1; /* error */ return 1; /* stop */ } if (data->count == -1) { /* All the elements. */ objc = 0; objv = NULL; } else { objc = data->count; objv = data->objv; } data->result = TreeStyle_GetElemRects(drawArgs, objc, objv, data->rects); return 1; /* stop */ } /* *---------------------------------------------------------------------- * * TreeItem_GetRects -- * * Returns zero or more bounding boxes for an item-column or * element(s) in an item-column. * * Results: * If the item is not visible, or has zero height/width, or the given * column is obscurred by a preceding span, or the column has zero * width or is not visible, the return value is zero. * * If count==0, the bounding box of the span is returned and the * return value is 1 (for a single rect). * * If count!=0, and the item-column does not have a style assigned, an * error is left in the interpreter result and the return value is -1. * * If count==-1, the bounding box of each element in the style is * returned and the return value is the number of elements in the style. * * If count>0, the bounding box of each element specified by the objv[] * array is returned and the return value is equal to count. If any of * the objv[] elements in not in the style, an error is left in the * interpreter result and the return value is -1. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_GetRects( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ TreeColumn treeColumn, /* The column to get rects for. */ int count, /* -1 means get rects for all elements. * 0 means get bounds of the span. * 1+ means objv[] contains names of elements * to get rects for. */ Tcl_Obj *CONST objv[], /* Array of element names or NULL. */ TreeRectangle rects[] /* Out: returned bounding boxes. */ ) { TreeRectangle tr; int lock = TreeColumn_Lock(treeColumn); struct { TreeColumn treeColumn; int count; Tcl_Obj *CONST *objv; TreeRectangle *rects; int result; } clientData; if (Tree_ItemBbox(tree, item, lock, &tr) < 0) return 0; clientData.treeColumn = treeColumn; clientData.count = count; clientData.objv = objv; clientData.rects = rects; clientData.result = 0; /* -1 error, 0 no rects, 1+ success */ TreeItem_WalkSpans(tree, item, lock, TreeRect_Left(tr), TreeRect_Top(tr), TreeRect_Width(tr), TreeRect_Height(tr), WALKSPAN_IGNORE_DND, SpanWalkProc_GetRects, (ClientData) &clientData); return clientData.result; } /* *---------------------------------------------------------------------- * * TreeItem_MakeColumnExist -- * * Wrapper around Item_CreateColumn, called when a tree-column is * created. * * Results: * A TreeItemColumn. * * Side effects: * Memory allocation. * *---------------------------------------------------------------------- */ TreeItemColumn TreeItem_MakeColumnExist( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Header token. */ int columnIndex /* Index of new column. */ ) { return Item_CreateColumn(tree, item, columnIndex, NULL); } /* *---------------------------------------------------------------------- * * TreeItem_CreateHeader -- * * Create a new TreeHeader. Both the header and underlying item * are created. For each tree-column that exists (including the * tail), a new header-column and associated item-column are * created. * * Results: * A TreeItem. * * Side effects: * Memory allocation. * *---------------------------------------------------------------------- */ TreeItem TreeItem_CreateHeader( TreeCtrl *tree /* Widget info. */ ) { TreeItem item, walk; TreeHeader header; item = Item_Alloc(tree, TRUE); header = TreeHeader_CreateWithItem(tree, item); if (header == NULL) { } item->header = header; /* This will create a TreeItemColumn and TreeHeaderColumn for every * TreeColumn, including the tail column. */ (void) Item_CreateColumn(tree, item, tree->columnCount, NULL); if (tree->headerItems == NULL) tree->headerItems = item; else { walk = tree->headerItems; while (walk->nextSibling != NULL) { walk = walk->nextSibling; } walk->nextSibling = item; item->prevSibling = walk; } return item; } /* *---------------------------------------------------------------------- * * TreeItem_GetHeader -- * * Return the header associated with an item. * * Results: * A TreeHeader or NULL if this is not a header-item. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeHeader TreeItem_GetHeader( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item token. */ ) { return item->header; } /* *---------------------------------------------------------------------- * * TreeItemColumn_GetHeaderColumn -- * * Return the header-column associated with an item-column. * * Results: * A TreeHeaderColumn or NULL if this is not a item-column in a * header-item. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeHeaderColumn TreeItemColumn_GetHeaderColumn( TreeCtrl *tree, TreeItemColumn column ) { return column->headerColumn; } /* *---------------------------------------------------------------------- * * IsHeaderOption -- * * Determine if an option is a valid option implemented for a header * by its underlying item. * * Results: * TRUE if the optoin. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int IsHeaderOption( Tcl_Interp *interp, /* Interp. */ Tcl_Obj *objPtr /* Name of the option. */ ) { static CONST char *headerOptions[] = { "-height", "-tags", "-visible", NULL }; int index; if (Tcl_GetIndexFromObj(interp, objPtr, headerOptions, "option", 0, &index) != TCL_OK) return FALSE; return TRUE; } /* *---------------------------------------------------------------------- * * TreeItem_ConsumeHeaderCget -- * * Sets the interpreter result with the value of a single * configuration option for an item. This is called when an * unknown option is passed to [header cget]. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_ConsumeHeaderCget( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ Tcl_Obj *objPtr /* Option name. */ ) { Tcl_Interp *interp = tree->interp; Tcl_Obj *resultObjPtr; if (!IsHeaderOption(interp, objPtr)) { FormatResult(interp, "unknown option \"%s\"", Tcl_GetString(objPtr)); return TCL_ERROR; } resultObjPtr = Tk_GetOptionValue(interp, (char *) item, tree->itemOptionTable, objPtr, tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeItem_ConsumeHeaderConfig -- * * Configures an item with option/value pairs. This is * called with any unknown options passed to [header configure]. * * Results: * A standard Tcl result. * * Side effects: * Whatever [item configure] does. * *---------------------------------------------------------------------- */ int TreeItem_ConsumeHeaderConfig( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tcl_Interp *interp = tree->interp; int i; if (objc <= 0) return TCL_OK; for (i = 0; i < objc; i += 2) { if (!IsHeaderOption(interp, objv[i])) { FormatResult(interp, "unknown option \"%s\"", Tcl_GetString(objv[i])); return TCL_ERROR; } } return Item_Configure(tree, item, objc, objv); } /* *---------------------------------------------------------------------- * * TreeItem_AppendHeaderOptionInfo -- * * Gets a config list for each item option that is relevent * to a header. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeItem_GetHeaderOptionInfo( TreeCtrl *tree, /* Widget info. */ TreeHeader header, /* Header token. */ Tcl_Obj *objPtr, /* Option name, or NULL for all options. */ Tcl_Obj *resultObjPtr /* List object to append to, or NULL * if objPtr is not NULL. */ ) { Tcl_Interp *interp = tree->interp; TreeItem item = TreeHeader_GetItem(header); Tcl_Obj *listObjPtr; static CONST char *headerOptions[] = { "-height", "-tags", "-visible", NULL }; int i; if (objPtr != NULL) { if (!IsHeaderOption(interp, objPtr)) { FormatResult(interp, "unknown option \"%s\"", Tcl_GetString(objPtr)); return TCL_ERROR; } listObjPtr = Tk_GetOptionInfo(tree->interp, (char *) item, tree->itemOptionTable, objPtr, tree->tkwin); if (listObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, listObjPtr); return TCL_OK; } for (i = 0; headerOptions[i] != NULL; i++) { objPtr = Tcl_NewStringObj(headerOptions[i], -1); Tcl_IncrRefCount(objPtr); listObjPtr = Tk_GetOptionInfo(tree->interp, (char *) item, tree->itemOptionTable, objPtr, tree->tkwin); Tcl_DecrRefCount(objPtr); if (listObjPtr == NULL) return TCL_ERROR; if (Tcl_ListObjAppendElement(tree->interp, resultObjPtr, listObjPtr) != TCL_OK) return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeItem_InitWidget -- * * Perform item-related initialization when a new TreeCtrl is * created. * * Results: * TCL_OK. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ int TreeItem_InitWidget( TreeCtrl *tree /* Widget info. */ ) { ItemButtonCO_Init(itemOptionSpecs, "-button", ITEM_FLAG_BUTTON, ITEM_FLAG_BUTTON_AUTO); BooleanFlagCO_Init(itemOptionSpecs, "-visible", ITEM_FLAG_VISIBLE); BooleanFlagCO_Init(itemOptionSpecs, "-wrap", ITEM_FLAG_WRAP); tree->itemOptionTable = Tk_CreateOptionTable(tree->interp, itemOptionSpecs); tree->root = Item_AllocRoot(tree); tree->activeItem = tree->root; /* always non-null */ tree->anchorItem = tree->root; /* always non-null */ return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeItem_FreeWidget -- * * Free item-related resources for a deleted TreeCtrl. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeItem_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { SpanInfoStack *siStack = tree->itemSpanPriv; while (siStack != NULL) { SpanInfoStack *next = siStack->next; if (siStack->spans != NULL) ckfree((char *) siStack->spans); if (siStack->columns != NULL) ckfree((char *) siStack->columns); ckfree((char *) siStack); siStack = next; } } tktreectrl-2.4.1/generic/tkTreeMarquee.c0000644000076400010400000004345711562306426020573 0ustar TimAdministrators/* * tkTreeMarquee.c -- * * This module implements the selection rectangle for treectrl widgets. * * Copyright (c) 2002-2011 Tim Baker */ #include "tkTreeCtrl.h" typedef struct TreeMarquee_ TreeMarquee_; /* * The following structure holds info about the selection rectangle. * There is one of these per TreeCtrl. */ struct TreeMarquee_ { TreeCtrl *tree; Tk_OptionTable optionTable; int visible; /* -visible option. */ int x1, y1, x2, y2; /* Opposing corners. */ int onScreen; /* TRUE if it was drawn. */ int sx, sy; /* Offset of canvas from top-left * corner of the window when we * were drawn. */ int sw, sh; /* Width & height when drawn. */ TreeColor *fillColorPtr; /* -fill */ Tcl_Obj *fillObj; /* -fill */ TreeColor *outlineColorPtr; /* -outline */ Tcl_Obj *outlineObj; /* -outline */ int outlineWidth; /* -outlinewidth */ Tcl_Obj *outlineWidthObj; /* -outlinewidth */ }; #define MARQ_CONF_VISIBLE 0x0001 #define MARQ_CONF_COLORS 0x0002 static Tk_OptionSpec optionSpecs[] = { {TK_OPTION_CUSTOM, "-fill", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TreeMarquee_, fillObj), Tk_Offset(TreeMarquee_, fillColorPtr), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_treecolor, MARQ_CONF_COLORS}, {TK_OPTION_CUSTOM, "-outline", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(TreeMarquee_, outlineObj), Tk_Offset(TreeMarquee_, outlineColorPtr), TK_OPTION_NULL_OK, (ClientData) &TreeCtrlCO_treecolor, MARQ_CONF_COLORS}, {TK_OPTION_PIXELS, "-outlinewidth", (char *) NULL, (char *) NULL, "1", Tk_Offset(TreeMarquee_, outlineWidthObj), Tk_Offset(TreeMarquee_, outlineWidth), 0, (ClientData) NULL, MARQ_CONF_COLORS}, {TK_OPTION_BOOLEAN, "-visible", (char *) NULL, (char *) NULL, "0", -1, Tk_Offset(TreeMarquee_, visible), 0, (ClientData) NULL, MARQ_CONF_VISIBLE}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, 0, 0} }; /* *---------------------------------------------------------------------- * * TreeMarquee_InitWidget -- * * Perform marquee-related initialization when a new TreeCtrl is * created. * * Results: * A standard Tcl result. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ int TreeMarquee_InitWidget( TreeCtrl *tree /* Widget info. */ ) { TreeMarquee marquee; marquee = (TreeMarquee) ckalloc(sizeof(TreeMarquee_)); memset(marquee, '\0', sizeof(TreeMarquee_)); marquee->tree = tree; marquee->optionTable = Tk_CreateOptionTable(tree->interp, optionSpecs); if (Tk_InitOptions(tree->interp, (char *) marquee, marquee->optionTable, tree->tkwin) != TCL_OK) { WFREE(marquee, TreeMarquee_); return TCL_ERROR; } tree->marquee = marquee; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeMarquee_FreeWidget -- * * Free marquee-related resources when a TreeCtrl is deleted. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ void TreeMarquee_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { TreeMarquee marquee = tree->marquee; Tk_FreeConfigOptions((char *) marquee, marquee->optionTable, marquee->tree->tkwin); WFREE(marquee, TreeMarquee_); } /* *---------------------------------------------------------------------- * * TreeMarquee_IsXOR -- * * Return true if the marquee is being drawn with XOR. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeMarquee_IsXOR(TreeMarquee marquee) { if (marquee->fillColorPtr || marquee->outlineColorPtr) return FALSE; #if defined(WIN32) return FALSE; /* TRUE on XP, FALSE on Win7 (lots of flickering) */ #elif defined(MAC_OSX_TK) return FALSE; #else return TRUE; /* X11 */ #endif } /* *---------------------------------------------------------------------- * * TreeMarquee_IsVisible -- * * Return true if the marquee is being drawn. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeMarquee_IsVisible(TreeMarquee marquee) { return marquee->visible; } /* *---------------------------------------------------------------------- * * TreeMarquee_Display -- * * Draw the selection rectangle if it is not already displayed and if * it's -visible option is TRUE. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void TreeMarquee_Display( TreeMarquee marquee /* Marquee token. */ ) { TreeCtrl *tree = marquee->tree; if (!marquee->onScreen && marquee->visible) { if (TreeMarquee_IsXOR(marquee)) { marquee->sx = 0 - tree->xOrigin; marquee->sy = 0 - tree->yOrigin; TreeMarquee_DrawXOR(marquee, Tk_WindowId(tree->tkwin), marquee->sx, marquee->sy); } else { marquee->sx = MIN(marquee->x1, marquee->x2) - tree->xOrigin; marquee->sy = MIN(marquee->y1, marquee->y2) - tree->yOrigin; marquee->sw = abs(marquee->x2 - marquee->x1) + 1; marquee->sh = abs(marquee->y2 - marquee->y1) + 1; /* Tree_InvalidateItemArea(tree, marquee->sx, marquee->sy, marquee->sx + marquee->sw, marquee->sy + marquee->sh);*/ Tree_EventuallyRedraw(tree); } marquee->onScreen = TRUE; } } /* *---------------------------------------------------------------------- * * TreeMarquee_Undisplay -- * * Erase the selection rectangle if it is displayed. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void TreeMarquee_Undisplay( TreeMarquee marquee /* Marquee token. */ ) { TreeCtrl *tree = marquee->tree; if (marquee->onScreen) { if (TreeMarquee_IsXOR(marquee)) { TreeMarquee_DrawXOR(marquee, Tk_WindowId(tree->tkwin), marquee->sx, marquee->sy); } else { /* Tree_InvalidateItemArea(tree, marquee->sx, marquee->sy, marquee->sx + marquee->sw, marquee->sy + marquee->sh);*/ Tree_EventuallyRedraw(tree); } marquee->onScreen = FALSE; } } /* *---------------------------------------------------------------------- * * TreeMarquee_DrawXOR -- * * Draw (or erase) the selection rectangle. * * Results: * None. * * Side effects: * Stuff is drawn (or erased, since this is XOR drawing). * *---------------------------------------------------------------------- */ void TreeMarquee_DrawXOR( TreeMarquee marquee, /* Marquee token. */ Drawable drawable, /* Where to draw. */ int x1, int y1 /* Offset of canvas from top-left corner * of the window. */ ) { TreeCtrl *tree = marquee->tree; int x, y, w, h; DotState dotState; x = MIN(marquee->x1, marquee->x2); w = abs(marquee->x1 - marquee->x2) + 1; y = MIN(marquee->y1, marquee->y2); h = abs(marquee->y1 - marquee->y2) + 1; TreeDotRect_Setup(tree, drawable, &dotState); TreeDotRect_Draw(&dotState, x1 + x, y1 + y, w, h); TreeDotRect_Restore(&dotState); } /* *---------------------------------------------------------------------- * * TreeMarquee_Draw -- * * Draw the selection rectangle if it is visible. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void TreeMarquee_Draw( TreeMarquee marquee, /* Marquee token. */ TreeDrawable td) /* Where to draw. */ { #if 1 /* Use XOR dotted rectangles where possible. */ TreeCtrl *tree = marquee->tree; if (!marquee->visible) return; if (marquee->fillColorPtr || marquee->outlineColorPtr) { TreeRectangle tr; TreeClip clip; tr.x = 0 - tree->xOrigin + MIN(marquee->x1, marquee->x2); tr.width = abs(marquee->x1 - marquee->x2) + 1; tr.y = 0 - tree->yOrigin + MIN(marquee->y1, marquee->y2); tr.height = abs(marquee->y1 - marquee->y2) + 1; clip.type = TREE_CLIP_AREA, clip.area = TREE_AREA_CONTENT; if (marquee->fillColorPtr) { TreeRectangle trBrush; TreeColor_GetBrushBounds(tree, marquee->fillColorPtr, tr, tree->xOrigin, tree->yOrigin, (TreeColumn) NULL, (TreeItem) NULL, &trBrush); TreeColor_FillRect(tree, td, &clip, marquee->fillColorPtr, trBrush, tr); } if (marquee->outlineColorPtr && marquee->outlineWidth > 0) { TreeRectangle trBrush; TreeColor_GetBrushBounds(tree, marquee->outlineColorPtr, tr, tree->xOrigin, tree->yOrigin, (TreeColumn) NULL, (TreeItem) NULL, &trBrush); TreeColor_DrawRect(tree, td, &clip, marquee->outlineColorPtr, trBrush, tr, marquee->outlineWidth, 0); } return; } /* Yes this is XOR drawing but we aren't erasing the previous * marquee as when TreeMarquee_IsXOR() returns TRUE. */ TreeMarquee_DrawXOR(marquee, td.drawable, 0 - tree->xOrigin, 0 - tree->yOrigin); #else /* */ TreeCtrl *tree = marquee->tree; int x, y, w, h; GC gc; XGCValues gcValues; unsigned long mask; #ifdef WIN32 XPoint points[5]; XRectangle rect; #endif #if 0 XColor *colorPtr; #endif if (!marquee->visible) return; x = MIN(marquee->x1, marquee->x2); w = abs(marquee->x1 - marquee->x2) + 1; y = MIN(marquee->y1, marquee->y2); h = abs(marquee->y1 - marquee->y2) + 1; #if 0 colorPtr = Tk_GetColor(tree->interp, tree->tkwin, "gray50"); gc = Tk_GCForColor(colorPtr, Tk_WindowId(tree->tkwin)); XFillRectangle(tree->display, td.drawable, gc, x - tree->drawableXOrigin, y - tree->drawableYOrigin, w - 1, h - 1); #else /* Stippled rectangles: BUG not clipped to contentbox. */ gcValues.stipple = Tk_GetBitmap(tree->interp, tree->tkwin, "gray50"); gcValues.fill_style = FillStippled; mask = GCStipple|GCFillStyle; gc = Tk_GetGC(tree->tkwin, mask, &gcValues); #ifdef WIN32 /* XDrawRectangle ignores the stipple pattern. */ rect.x = x - tree->drawableXOrigin; rect.y = y - tree->drawableYOrigin; rect.width = w; rect.height = h; points[0].x = rect.x, points[0].y = rect.y; points[1].x = rect.x + rect.width - 1, points[1].y = rect.y; points[2].x = rect.x + rect.width - 1, points[2].y = rect.y + rect.height - 1; points[3].x = rect.x, points[3].y = rect.y + rect.height - 1; points[4] = points[0]; XDrawLines(tree->display, td.drawable, gc, points, 5, CoordModeOrigin); #else XDrawRectangle(tree->display, td.drawable, gc, x - tree->drawableXOrigin, y - tree->drawableYOrigin, w - 1, h - 1); #endif Tk_FreeGC(tree->display, gc); #endif #endif /* */ } /* *---------------------------------------------------------------------- * * Marquee_Config -- * * This procedure is called to process an objc/objv list to set * configuration options for a Marquee. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then an error message is left in interp's result. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for marquee; old resources get freed, if there * were any. Display changes may occur. * *---------------------------------------------------------------------- */ static int Marquee_Config( TreeMarquee marquee, /* Marquee record. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = marquee->tree; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; int mask; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tk_SetOptions(tree->interp, (char *) marquee, marquee->optionTable, objc, objv, tree->tkwin, &savedOptions, &mask) != TCL_OK) { mask = 0; continue; } /* xxx */ Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); /* xxx */ Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } if (mask & MARQ_CONF_VISIBLE) { TreeMarquee_Undisplay(marquee); TreeMarquee_Display(marquee); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeMarqueeCmd -- * * This procedure is invoked to process the [marquee] widget * command. See the user documentation for details on what it * does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeMarqueeCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; TreeMarquee marquee = tree->marquee; static CONST char *commandNames[] = { "anchor", "cget", "configure", "coords", "corner", "identify", (char *) NULL }; enum { COMMAND_ANCHOR, COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_COORDS, COMMAND_CORNER, COMMAND_IDENTIFY }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { /* T marquee anchor ?x y?*/ case COMMAND_ANCHOR: { int x, y; if (objc != 3 && objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "?x y?"); return TCL_ERROR; } if (objc == 3) { FormatResult(interp, "%d %d", marquee->x1, marquee->y1); break; } if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) return TCL_ERROR; if ((x == marquee->x1) && (y == marquee->y1)) break; TreeMarquee_Undisplay(tree->marquee); marquee->x1 = x; marquee->y1 = y; TreeMarquee_Display(tree->marquee); break; } /* T marquee cget option */ case COMMAND_CGET: { Tcl_Obj *resultObjPtr; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "option"); return TCL_ERROR; } resultObjPtr = Tk_GetOptionValue(interp, (char *) marquee, marquee->optionTable, objv[3], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } /* T marquee configure ?option? ?value? ?option value ...? */ case COMMAND_CONFIGURE: { Tcl_Obj *resultObjPtr; if (objc < 3) { Tcl_WrongNumArgs(interp, 3, objv, "?option? ?value?"); return TCL_ERROR; } if (objc <= 4) { resultObjPtr = Tk_GetOptionInfo(interp, (char *) marquee, marquee->optionTable, (objc == 3) ? (Tcl_Obj *) NULL : objv[3], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } return Marquee_Config(marquee, objc - 3, objv + 3); } /* T marquee coords ?x y x y? */ case COMMAND_COORDS: { int x1, y1, x2, y2; if (objc != 3 && objc != 7) { Tcl_WrongNumArgs(interp, 3, objv, "?x y x y?"); return TCL_ERROR; } if (objc == 3) { FormatResult(interp, "%d %d %d %d", marquee->x1, marquee->y1, marquee->x2, marquee->y2); break; } if (Tcl_GetIntFromObj(interp, objv[3], &x1) != TCL_OK) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[4], &y1) != TCL_OK) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[5], &x2) != TCL_OK) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[6], &y2) != TCL_OK) return TCL_ERROR; if (x1 == marquee->x1 && y1 == marquee->y1 && x2 == marquee->x2 && y2 == marquee->y2) break; TreeMarquee_Undisplay(tree->marquee); marquee->x1 = x1; marquee->y1 = y1; marquee->x2 = x2; marquee->y2 = y2; TreeMarquee_Display(tree->marquee); break; } /* T marquee corner ?x y?*/ case COMMAND_CORNER: { int x, y; if (objc != 3 && objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "?x y?"); return TCL_ERROR; } if (objc == 3) { FormatResult(interp, "%d %d", marquee->x2, marquee->y2); break; } if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) return TCL_ERROR; if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) return TCL_ERROR; if (x == marquee->x2 && y == marquee->y2) break; TreeMarquee_Undisplay(tree->marquee); marquee->x2 = x; marquee->y2 = y; TreeMarquee_Display(tree->marquee); break; } /* T marquee identify */ case COMMAND_IDENTIFY: { int x1, y1, x2, y2, n = 0; int totalWidth = Tree_CanvasWidth(tree); int totalHeight = Tree_CanvasHeight(tree); TreeItemList items; Tcl_Obj *listObj; if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL); return TCL_ERROR; } x1 = MIN(marquee->x1, marquee->x2); x2 = MAX(marquee->x1, marquee->x2); y1 = MIN(marquee->y1, marquee->y2); y2 = MAX(marquee->y1, marquee->y2); if (x2 <= 0) break; if (x1 >= totalWidth) break; if (y2 <= 0) break; if (y1 >= totalHeight) break; if (x1 < 0) x1 = 0; if (x2 > totalWidth) x2 = totalWidth; if (y1 < 0) y1 = 0; if (y2 > totalHeight) y2 = totalHeight; Tree_ItemsInArea(tree, &items, x1, y1, x2, y2); if (TreeItemList_Count(&items) == 0) { TreeItemList_Free(&items); break; } listObj = Tcl_NewListObj(0, NULL); for (n = 0; n < TreeItemList_Count(&items); n++) { Tcl_Obj *subListObj = Tcl_NewListObj(0, NULL); TreeItem item = TreeItemList_Nth(&items, n); Tcl_ListObjAppendElement(interp, subListObj, TreeItem_ToObj(tree, item)); TreeItem_Identify2(tree, item, x1, y1, x2, y2, subListObj); Tcl_ListObjAppendElement(interp, listObj, subListObj); } TreeItemList_Free(&items); Tcl_SetObjResult(interp, listObj); break; } } return TCL_OK; } tktreectrl-2.4.1/generic/tkTreeNotify.c0000644000076400010400000004612011562306435020432 0ustar TimAdministrators/* * tkTreeNotify.c -- * * This module implements "qebind.c" events for treectrl widgets. * * Copyright (c) 2002-2011 Tim Baker */ #include "tkTreeCtrl.h" /* Even though these are static globals and initialized for each new * treectrl widget, the values are exactly the same for every widget. */ static int EVENT_EXPAND, DETAIL_EXPAND_BEFORE, DETAIL_EXPAND_AFTER; static int EVENT_COLLAPSE, DETAIL_COLLAPSE_BEFORE, DETAIL_COLLAPSE_AFTER; static int EVENT_SELECTION; static int EVENT_ACTIVEITEM; static int EVENT_SCROLL, DETAIL_SCROLL_X, DETAIL_SCROLL_Y; static int EVENT_ITEM_DELETE; static int EVENT_ITEM_VISIBILITY; /* *---------------------------------------------------------------------- * * ExpandItem -- * * Append an item ID to a dynamic string. * * Results: * DString gets longer. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void ExpandItem( TreeCtrl *tree, /* Widget info. */ int id, /* Item ID. */ Tcl_DString *result /* Gets appended. Caller must initialize. */ ) { char buf[10 + TCL_INTEGER_SPACE]; (void) sprintf(buf, "%s%d", (tree->itemPrefixLen ? tree->itemPrefix : ""), id); Tcl_DStringAppend(result, buf, -1); } /* *---------------------------------------------------------------------- * * ExpandItemList -- * * Append a list of item IDs to a dynamic string. * * Results: * DString gets longer. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void ExpandItemList( TreeCtrl *tree, /* Widget info. */ TreeItemList *itemList, /* list of item IDs */ Tcl_DString *result /* Gets appended. Caller must initialize. */ ) { if (itemList == NULL) { Tcl_DStringAppend(result, "{}", 2); } else { int i, count; char buf[10 + TCL_INTEGER_SPACE]; Tcl_DStringStartSublist(result); count = TreeItemList_Count(itemList); for (i = 0; i < count; i++) { (void) sprintf(buf, "%s%d", (tree->itemPrefixLen ? tree->itemPrefix : ""), TreeItem_GetID(tree, TreeItemList_Nth(itemList, i))); Tcl_DStringAppendElement(result, buf); } Tcl_DStringEndSublist(result); } } /* *---------------------------------------------------------------------- * * DumpPercents -- * * Appends a sublist to a dynamic string. The sublist contains * %-char,value pairs. This is to handle the %? substitution. * * Results: * DString gets longer. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void DumpPercents( QE_ExpandArgs *args, /* %-substitution args. */ QE_ExpandProc proc, /* Function to return value for a given * %-char. */ CONST char *chars /* NULL-terminated list of %-chars. */ ) { char which = args->which; char buf[2]; int i; buf[1] = '\0'; Tcl_DStringStartSublist(args->result); for (i = 0; chars[i]; i++) { args->which = chars[i]; buf[0] = chars[i]; Tcl_DStringAppendElement(args->result, buf); Tcl_DStringAppend(args->result, " ", 1); (*proc)(args); } Tcl_DStringEndSublist(args->result); args->which = which; } /* *---------------------------------------------------------------------- * * Percents_Any -- * * Append a value for a single %-char to a dynamic string. This * function handles the default %-chars (d,e,P,W,T, and ?) and * calls QE_ExpandUnknown() for any unrecognized %-char. * * Results: * DString gets longer. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void Percents_Any( QE_ExpandArgs *args, /* %-substitution args. */ QE_ExpandProc proc, /* Function to return value for a given * %-char. */ CONST char *chars /* NULL-terminated list of %-chars. */ ) { struct { TreeCtrl *tree; } *data = args->clientData; char chars2[64]; switch (args->which) { case 'd': /* detail */ QE_ExpandDetail(args->bindingTable, args->event, args->detail, args->result); break; case 'e': /* event */ QE_ExpandEvent(args->bindingTable, args->event, args->result); break; case 'P': /* pattern */ QE_ExpandPattern(args->bindingTable, args->event, args->detail, args->result); break; case 'W': /* object */ QE_ExpandString((char *) args->object, args->result); break; case 'T': /* tree */ QE_ExpandString(Tk_PathName(data->tree->tkwin), args->result); break; case '?': strcpy(chars2, "TWPed"); strcat(chars2, chars); DumpPercents(args, proc, chars2); break; default: QE_ExpandUnknown(args->which, args->result); break; } } /* *---------------------------------------------------------------------- * * Percents_Expand -- * * %-substitution callback for . * * Results: * DString gets longer. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void Percents_Expand( QE_ExpandArgs *args /* %-substitution args. */ ) { struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ int id; } *data = args->clientData; switch (args->which) { case 'I': ExpandItem(data->tree, data->id, args->result); break; default: Percents_Any(args, Percents_Expand, "I"); break; } } /* *---------------------------------------------------------------------- * * Percents_ItemVisibility -- * * %-substitution callback for . * * Results: * DString gets longer. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void Percents_ItemVisibility( QE_ExpandArgs *args /* %-substitution args. */ ) { struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ TreeItemList *v; TreeItemList *h; } *data = args->clientData; TreeItemList *table; switch (args->which) { case 'v': case 'h': table = (args->which == 'v') ? data->v : data->h; ExpandItemList(data->tree, table, args->result); break; default: Percents_Any(args, Percents_ItemVisibility, "vh"); break; } } /* *---------------------------------------------------------------------- * * Percents_Selection -- * * %-substitution callback for . * * Results: * DString gets longer. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void Percents_Selection( QE_ExpandArgs *args /* %-substitution args. */ ) { struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ TreeItemList *select; TreeItemList *deselect; int count; } *data = args->clientData; TreeItemList *itemList; switch (args->which) { case 'c': QE_ExpandNumber(data->count, args->result); break; case 'D': case 'S': itemList = (args->which == 'D') ? data->deselect : data->select; ExpandItemList(data->tree, itemList, args->result); break; default: Percents_Any(args, Percents_Selection, "cSD"); break; } } /* *---------------------------------------------------------------------- * * Percents_ActiveItem -- * * %-substitution callback for . * * Results: * DString gets longer. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void Percents_ActiveItem( QE_ExpandArgs *args /* %-substitution args. */ ) { struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ int prev; int current; } *data = args->clientData; switch (args->which) { case 'c': ExpandItem(data->tree, data->current, args->result); break; case 'p': ExpandItem(data->tree, data->prev, args->result); break; default: Percents_Any(args, Percents_ActiveItem, "cp"); break; } } /* *---------------------------------------------------------------------- * * Percents_Scroll -- * * %-substitution callback for . * * Results: * DString gets longer. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void Percents_Scroll( QE_ExpandArgs *args /* %-substitution args. */ ) { struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ double lower; double upper; } *data = args->clientData; switch (args->which) { case 'l': QE_ExpandDouble(data->lower, args->result); break; case 'u': QE_ExpandDouble(data->upper, args->result); break; default: Percents_Any(args, Percents_Scroll, "lu"); break; } } /* *---------------------------------------------------------------------- * * TreeNotifyCmd -- * * This procedure is invoked to process the [notify] widget * command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeNotifyCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; static CONST char *commandName[] = { "bind", "configure", "detailnames", "eventnames", "generate", "install", "linkage", "unbind", "uninstall", (char *) NULL }; enum { COMMAND_BIND, COMMAND_CONFIGURE, COMMAND_DETAILNAMES, COMMAND_EVENTNAMES, COMMAND_GENERATE, COMMAND_INSTALL, COMMAND_LINKAGE, COMMAND_UNBIND, COMMAND_UNINSTALL }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandName, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case COMMAND_BIND: { return QE_BindCmd(tree->bindingTable, 2, objc, objv); } case COMMAND_CONFIGURE: { return QE_ConfigureCmd(tree->bindingTable, 2, objc, objv); } /* T notify detailnames $eventName */ case COMMAND_DETAILNAMES: { char *eventName; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "eventName"); return TCL_ERROR; } eventName = Tcl_GetString(objv[3]); return QE_GetDetailNames(tree->bindingTable, eventName); } /* T notify eventnames */ case COMMAND_EVENTNAMES: { if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL); return TCL_ERROR; } return QE_GetEventNames(tree->bindingTable); } case COMMAND_GENERATE: { return QE_GenerateCmd(tree->bindingTable, 2, objc, objv); } case COMMAND_INSTALL: { return QE_InstallCmd(tree->bindingTable, 2, objc, objv); } case COMMAND_LINKAGE: { return QE_LinkageCmd(tree->bindingTable, 2, objc, objv); } case COMMAND_UNBIND: { return QE_UnbindCmd(tree->bindingTable, 2, objc, objv); } case COMMAND_UNINSTALL: { return QE_UninstallCmd(tree->bindingTable, 2, objc, objv); } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeNotify_OpenClose -- * * Generate an or event. * * Results: * Any scripts bound to the event are evaluated. * * Side effects: * Whatever binding scripts do. * *---------------------------------------------------------------------- */ void TreeNotify_OpenClose( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item token. */ int state, /* STATE_ITEM_OPEN or 0 */ int before /* TRUE for event, FALSE for * event. */ ) { QE_Event event; struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ int id; } data; data.tree = tree; data.id = TreeItem_GetID(tree, item); if (state & STATE_ITEM_OPEN) { event.type = EVENT_EXPAND; event.detail = before ? DETAIL_EXPAND_BEFORE : DETAIL_EXPAND_AFTER; } else { event.type = EVENT_COLLAPSE; event.detail = before ? DETAIL_COLLAPSE_BEFORE : DETAIL_COLLAPSE_AFTER; } event.clientData = (ClientData) &data; (void) QE_BindEvent(tree->bindingTable, &event); } /* *---------------------------------------------------------------------- * * TreeNotify_Selection -- * * Generate a event. * * Results: * Any scripts bound to the event are evaluated. * * Side effects: * Whatever binding scripts do. * *---------------------------------------------------------------------- */ void TreeNotify_Selection( TreeCtrl *tree, /* Widget info. */ TreeItemList *select, /* List of items or NULL. */ TreeItemList *deselect /* List of items or NULL. */ ) { QE_Event event; struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ TreeItemList *select; TreeItemList *deselect; int count; } data; data.tree = tree; data.select = select; data.deselect = deselect; data.count = tree->selectCount; event.type = EVENT_SELECTION; event.detail = 0; event.clientData = (ClientData) &data; (void) QE_BindEvent(tree->bindingTable, &event); } /* *---------------------------------------------------------------------- * * TreeNotify_ActiveItem -- * * Generate an event. * * Results: * Any scripts bound to the event are evaluated. * * Side effects: * Whatever binding scripts do. * *---------------------------------------------------------------------- */ void TreeNotify_ActiveItem( TreeCtrl *tree, /* Widget info. */ TreeItem itemPrev, /* Previous active item. */ TreeItem itemCur /* Current active item. */ ) { QE_Event event; struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ int prev; int current; } data; data.tree = tree; data.prev = TreeItem_GetID(tree, itemPrev); data.current = TreeItem_GetID(tree, itemCur); event.type = EVENT_ACTIVEITEM; event.detail = 0; event.clientData = (ClientData) &data; (void) QE_BindEvent(tree->bindingTable, &event); } /* *---------------------------------------------------------------------- * * TreeNotify_Scroll -- * * Generate a event. * * Results: * Any scripts bound to the event are evaluated. * * Side effects: * Whatever binding scripts do. * *---------------------------------------------------------------------- */ void TreeNotify_Scroll( TreeCtrl *tree, /* Widget info. */ double fractions[2], /* Fractions suitable for a scrollbar's * [set] command. */ int vertical /* TRUE for , FALSE for * . */ ) { QE_Event event; struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ double lower; double upper; } data; data.tree = tree; data.lower = fractions[0]; data.upper = fractions[1]; event.type = EVENT_SCROLL; event.detail = vertical ? DETAIL_SCROLL_Y : DETAIL_SCROLL_X; event.clientData = (ClientData) &data; (void) QE_BindEvent(tree->bindingTable, &event); } /* *---------------------------------------------------------------------- * * Percents_ItemDelete -- * * %-substitution callback for . * * Results: * DString gets longer. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ static void Percents_ItemDelete( QE_ExpandArgs *args /* %-substitution args. */ ) { struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ TreeItemList *items; } *data = args->clientData; switch (args->which) { case 'i': ExpandItemList(data->tree, data->items, args->result); break; default: Percents_Any(args, Percents_ItemDelete, "i"); break; } } /* *---------------------------------------------------------------------- * * TreeNotify_ItemDeleted -- * * Generate an event. * * Results: * Any scripts bound to the event are evaluated. * * Side effects: * Whatever binding scripts do. * *---------------------------------------------------------------------- */ void TreeNotify_ItemDeleted( TreeCtrl *tree, /* Widget info. */ TreeItemList *items /* List of items. */ ) { QE_Event event; struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ TreeItemList *items; } data; data.tree = tree; data.items = items; event.type = EVENT_ITEM_DELETE; event.detail = 0; event.clientData = (ClientData) &data; (void) QE_BindEvent(tree->bindingTable, &event); } /* *---------------------------------------------------------------------- * * TreeNotify_ItemVisibility -- * * Generate an event. * * Results: * Any scripts bound to the event are evaluated. * * Side effects: * Whatever binding scripts do. * *---------------------------------------------------------------------- */ void TreeNotify_ItemVisibility( TreeCtrl *tree, /* Widget info. */ TreeItemList *v, /* List of newly-visible items. */ TreeItemList *h /* List of newly-hidden items. */ ) { QE_Event event; struct { TreeCtrl *tree; /* Must be first. See Percents_Any(). */ TreeItemList *v; TreeItemList *h; } data; data.tree = tree; data.v = v; data.h = h; event.type = EVENT_ITEM_VISIBILITY; event.detail = 0; event.clientData = (ClientData) &data; (void) QE_BindEvent(tree->bindingTable, &event); } /* *---------------------------------------------------------------------- * * TreeNotify_InitWidget -- * * Perform event-related initialization when a new TreeCtrl is * created. * * Results: * Installs all the static events and details. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ int TreeNotify_InitWidget( TreeCtrl *tree /* Widget info. */ ) { tree->bindingTable = QE_CreateBindingTable(tree->interp); EVENT_EXPAND = QE_InstallEvent(tree->bindingTable, "Expand", Percents_Expand); DETAIL_EXPAND_BEFORE = QE_InstallDetail(tree->bindingTable, "before", EVENT_EXPAND, NULL); DETAIL_EXPAND_AFTER = QE_InstallDetail(tree->bindingTable, "after", EVENT_EXPAND, NULL); EVENT_COLLAPSE = QE_InstallEvent(tree->bindingTable, "Collapse", Percents_Expand); DETAIL_COLLAPSE_BEFORE = QE_InstallDetail(tree->bindingTable, "before", EVENT_COLLAPSE, NULL); DETAIL_COLLAPSE_AFTER = QE_InstallDetail(tree->bindingTable, "after", EVENT_COLLAPSE, NULL); EVENT_SELECTION = QE_InstallEvent(tree->bindingTable, "Selection", Percents_Selection); EVENT_ACTIVEITEM = QE_InstallEvent(tree->bindingTable, "ActiveItem", Percents_ActiveItem); EVENT_SCROLL = QE_InstallEvent(tree->bindingTable, "Scroll", Percents_Scroll); DETAIL_SCROLL_X = QE_InstallDetail(tree->bindingTable, "x", EVENT_SCROLL, NULL); DETAIL_SCROLL_Y = QE_InstallDetail(tree->bindingTable, "y", EVENT_SCROLL, NULL); EVENT_ITEM_DELETE = QE_InstallEvent(tree->bindingTable, "ItemDelete", Percents_ItemDelete); EVENT_ITEM_VISIBILITY = QE_InstallEvent(tree->bindingTable, "ItemVisibility", Percents_ItemVisibility); return TCL_OK; } tktreectrl-2.4.1/generic/tkTreeStyle.c0000644000076400010400000066726111571511221020270 0ustar TimAdministrators/* * tkTreeStyle.c -- * * This module implements styles for treectrl widgets. * * Copyright (c) 2002-2011 Tim Baker */ #include "tkTreeCtrl.h" #include "tkTreeElem.h" /* This is the roundUp argument to TreeAlloc_CAlloc. */ #define ELEMENT_LINK_ROUND 1 /* Define this for performance gain and increased memory usage. */ /* When undefined, there is quite a performance hit when elements are * squeezable and a style has less than its needed width. The memory * savings are not too great when undefined. */ #define CACHE_STYLE_SIZE /* Define this for performance gain and increased memory usage. */ #define CACHE_ELEM_SIZE typedef struct MStyle MStyle; typedef struct IStyle IStyle; typedef struct MElementLink MElementLink; typedef struct IElementLink IElementLink; /* * A data structure of the following type is kept for each master style. * Master styles are created by the [style create] widget command. */ struct MStyle { MStyle *master; /* Always NULL. Needed to distinguish between * an MStyle and IStyle. */ Tk_Uid name; /* Unique identifier. */ int numElements; /* Size of elements[]. */ MElementLink *elements; /* Array of master elements. */ int vertical; /* -orient */ int buttonY; /* -buttony */ Tcl_Obj *buttonYObj; /* -buttony */ int stateDomain; /* STATE_DOMAIN_XXX index. */ int hasWindowElem; /* TRUE if style has any window elements. */ int hidden; /* Hackish flag for hidden header styles. */ int hasHeaderElem; /* Hackish flag to remember if the style has * any elements of type 'header'. Headers * are a fixed height on Aqua. */ }; /* * A data structure of the following type is kept for each instance style. * Instance styles are created when a style is assigned to an item-column. */ struct IStyle { MStyle *master; /* Always non-NULL. */ IElementLink *elements; /* Array of master or instance elements. */ int neededWidth; /* Requested size of this style based on */ int neededHeight; /* layout of the elements. */ #ifdef TREECTRL_DEBUG int neededState; #endif #ifdef CACHE_STYLE_SIZE int minWidth; int minHeight; int layoutWidth; int layoutHeight; #endif }; #define ELF_eEXPAND_W 0x0001 /* expand Layout.ePadX[0] */ #define ELF_eEXPAND_N 0x0002 #define ELF_eEXPAND_E 0x0004 #define ELF_eEXPAND_S 0x0008 #define ELF_iEXPAND_W 0x0010 /* expand Layout.iPadX[0] */ #define ELF_iEXPAND_N 0x0020 #define ELF_iEXPAND_E 0x0040 #define ELF_iEXPAND_S 0x0080 #define ELF_SQUEEZE_X 0x0100 /* shrink Layout.useWidth if needed */ #define ELF_SQUEEZE_Y 0x0200 #define ELF_DETACH 0x0400 #define ELF_INDENT 0x0800 /* don't layout under button&line area */ #define ELF_STICKY_W 0x1000 #define ELF_STICKY_N 0x2000 #define ELF_STICKY_E 0x4000 #define ELF_STICKY_S 0x8000 #define ELF_iEXPAND_X 0x00010000 /* expand Layout.useWidth */ #define ELF_iEXPAND_Y 0x00020000 #define ELF_CENTER_X 0x00040000 #define ELF_CENTER_Y 0x00080000 #define ELF_eEXPAND_WE (ELF_eEXPAND_W | ELF_eEXPAND_E) #define ELF_eEXPAND_NS (ELF_eEXPAND_N | ELF_eEXPAND_S) #define ELF_eEXPAND (ELF_eEXPAND_WE | ELF_eEXPAND_NS) #define ELF_iEXPAND_WE (ELF_iEXPAND_W | ELF_iEXPAND_E) #define ELF_iEXPAND_NS (ELF_iEXPAND_N | ELF_iEXPAND_S) #define ELF_iEXPAND (ELF_iEXPAND_WE | ELF_iEXPAND_NS) #define ELF_EXPAND_WE (ELF_eEXPAND_WE | ELF_iEXPAND_WE) #define ELF_EXPAND_NS (ELF_eEXPAND_NS | ELF_iEXPAND_NS) #define ELF_EXPAND_W (ELF_eEXPAND_W | ELF_iEXPAND_W) #define ELF_EXPAND_N (ELF_eEXPAND_N | ELF_iEXPAND_N) #define ELF_EXPAND_E (ELF_eEXPAND_E | ELF_iEXPAND_E) #define ELF_EXPAND_S (ELF_eEXPAND_S | ELF_iEXPAND_S) #define ELF_STICKY (ELF_STICKY_W | ELF_STICKY_N | ELF_STICKY_E | ELF_STICKY_S) #define IS_CENTER_X(e) (((e)->flags & ELF_CENTER_X) != 0) #define IS_CENTER_Y(e) (((e)->flags & ELF_CENTER_Y) != 0) #define IS_DETACH(e) (((e)->flags & ELF_DETACH) != 0) #define IS_UNION(e) ((e)->onion != NULL) #define DETACH_OR_UNION(e) (IS_DETACH(e) || IS_UNION(e)) /* * An array of these is kept for each master style, one per element. * Most of the fields are set by the [style layout] widget command. */ struct MElementLink { TreeElement elem; /* Master element. */ int ePadX[2]; /* external horizontal padding */ int ePadY[2]; /* external vertical padding */ int iPadX[2]; /* internal horizontal padding */ int iPadY[2]; /* internal vertical padding */ int flags; /* ELF_xxx */ int *onion, onionCount; /* -union option info */ int minWidth, fixedWidth, maxWidth; int minHeight, fixedHeight, maxHeight; PerStateInfo draw; /* -draw */ PerStateInfo visible; /* -visible */ }; /* * An array of these is kept for each instance style, one per element. */ struct IElementLink { TreeElement elem; /* Master or instance element. */ #ifdef CACHE_ELEM_SIZE int neededWidth; int neededHeight; int layoutWidth; int layoutHeight; #endif }; static CONST char *MStyleUid = "MStyle", *IStyleUid = "IStyle", *MElementLinkUid = "MElementLink", *IElementLinkUid = "IElementLink"; static char *orientStringTable[] = { "horizontal", "vertical", (char *) NULL }; static Tk_OptionSpec styleOptionSpecs[] = { {TK_OPTION_PIXELS, "-buttony", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(MStyle, buttonYObj), Tk_Offset(MStyle, buttonY), TK_OPTION_NULL_OK, (ClientData) NULL, 0}, {TK_OPTION_STRING_TABLE, "-orient", (char *) NULL, (char *) NULL, "horizontal", -1, Tk_Offset(MStyle, vertical), 0, (ClientData) orientStringTable, 0}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} }; /* * The following structure is used to hold layout information about a * single element. This information is not cached anywhere. */ struct Layout { MElementLink *master; IElementLink *eLink; int useWidth; int useHeight; #ifndef CACHE_ELEM_SIZE int neededWidth; int neededHeight; #endif int x; /* left of ePad */ int y; /* above ePad */ int eWidth; /* ePad + iPad + useWidth + iPad + ePad */ int eHeight; /* ePad + iPad + useHeight + iPad + ePad */ int iWidth; /* iPad + useWidth + iPad */ int iHeight; /* iPad + useHeight + iPad */ int ePadX[2]; /* external horizontal padding */ int ePadY[2]; /* external vertical padding */ int iPadX[2]; /* internal horizontal padding */ int iPadY[2]; /* internal vertical padding */ int uPadX[2]; /* padding due to -union */ int uPadY[2]; /* padding due to -union */ int temp; int visible; /* TRUE if the element should be displayed. */ int unionFirst, unionLast; /* First and last visible elements in this * element's -union */ int unionParent; /* TRUE if this element is in one or more element's * -union */ /* These are all hacks for header elements. */ int eMargins[4]; /* Content margins, including arrow width but not -arrowpadx */ int uMargins[4]; /* Content margins, including arrow width and -arrowpadx */ int eUnionBbox[4]; /* Bounds of elements in a this element's -union, * including external padding of those elements. */ int iUnionBbox[4]; /* Bounds of elements in a this element's -union, * not including external padding of those elements. */ int arrowHeight; /* Height of the sort arrow + -arrowpady. */ }; #define IS_HIDDEN(L) ((L)->visible == 0) /* *---------------------------------------------------------------------- * * Style_DoExpandH -- * * Add extra horizontal space to a single element. The space is * distributed from right to left until all available space * is used or expansion is not possible. * * Results: * Layout.ePadX, Layout.iPadX, and Layout.useWidth may be * updated. The amount of available space that was used is * returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Style_DoExpandH( struct Layout *layout, /* Layout to be adjusted. */ int extraSpace /* Amount of extra space to add. */ ) { MElementLink *eLink1 = layout->master; int flags = eLink1->flags; int numExpand = 0, spaceRemaining, spaceUsed = 0; int *ePadX, *iPadX, *uPadX; if (!(flags & (ELF_EXPAND_WE | ELF_iEXPAND_X))) return 0; ePadX = layout->ePadX; iPadX = layout->iPadX; uPadX = layout->uPadX; spaceRemaining = extraSpace; if (spaceRemaining <= 0) return 0; if (layout->temp) numExpand = layout->temp; /* For -detach or vertical layout, just set layout->temp to zero */ else { if (flags & ELF_eEXPAND_W) numExpand++; if (flags & ELF_iEXPAND_W) numExpand++; if (flags & ELF_iEXPAND_X) { if ((eLink1->maxWidth < 0) || (eLink1->maxWidth > layout->useWidth)) numExpand++; } if (flags & ELF_iEXPAND_E) numExpand++; if (flags & ELF_eEXPAND_E) numExpand++; } while ((spaceRemaining > 0) && (numExpand > 0)) { int each = (spaceRemaining >= numExpand) ? (spaceRemaining / numExpand) : 1; numExpand = 0; /* Allocate extra space to the *right* padding first so that any * extra single pixel is given to the right. */ if (flags & ELF_eEXPAND_E) { int add = each; ePadX[PAD_BOTTOM_RIGHT] += add; layout->eWidth += add; spaceRemaining -= add; spaceUsed += add; if (!spaceRemaining) break; numExpand++; } if (flags & ELF_iEXPAND_E) { int add = each; iPadX[PAD_BOTTOM_RIGHT] += add; layout->iWidth += add; layout->eWidth += add; spaceRemaining -= add; spaceUsed += add; if (!spaceRemaining) break; numExpand++; } if (flags & ELF_iEXPAND_X) { int max = eLink1->maxWidth; if ((max < 0) || (layout->useWidth < max)) { int add = (max < 0) ? each : MIN(each, max - layout->useWidth); layout->useWidth += add; layout->iWidth += add; layout->eWidth += add; spaceRemaining -= add; spaceUsed += add; if ((max >= 0) && (max == layout->useWidth)) layout->temp--; if (!spaceRemaining) break; if ((max < 0) || (max > layout->useWidth)) numExpand++; } } if (flags & ELF_iEXPAND_W) { int add = each; iPadX[PAD_TOP_LEFT] += add; layout->iWidth += add; layout->eWidth += add; spaceRemaining -= add; spaceUsed += add; if (!spaceRemaining) break; numExpand++; } if (flags & ELF_eEXPAND_W) { int add = each; ePadX[PAD_TOP_LEFT] += add; layout->eWidth += add; spaceRemaining -= add; spaceUsed += add; if (!spaceRemaining) break; numExpand++; } } return spaceUsed; } /* *---------------------------------------------------------------------- * * Style_DoExpandV -- * * Add extra vertical space to a single element. The space is * distributed from bottom to top until all available space * is used or expansion is not possible. * * Results: * Layout.ePadY, Layout.iPadY, and Layout.useHeight may be * updated. The amount of available space that was used is * returned. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Style_DoExpandV( struct Layout *layout, /* Layout to be adjusted. */ int extraSpace /* Amount of extra space to add. */ ) { MElementLink *eLink1 = layout->master; int flags = eLink1->flags; int numExpand = 0, spaceRemaining, spaceUsed = 0; int *ePadY, *iPadY, *uPadY; if (!(flags & (ELF_EXPAND_NS | ELF_iEXPAND_Y))) return 0; ePadY = layout->ePadY; iPadY = layout->iPadY; uPadY = layout->uPadY; spaceRemaining = extraSpace; if (spaceRemaining <= 0) return 0; if (layout->temp) numExpand = layout->temp; /* For -detach or vertical layout, just set layout->temp to zero */ else { if (flags & ELF_eEXPAND_N) numExpand++; if (flags & ELF_iEXPAND_N) numExpand++; if (flags & ELF_iEXPAND_Y) { if ((eLink1->maxHeight < 0) || (eLink1->maxHeight > layout->useHeight)) numExpand++; } if (flags & ELF_iEXPAND_S) numExpand++; if (flags & ELF_eEXPAND_S) numExpand++; } while ((spaceRemaining > 0) && (numExpand > 0)) { int each = (spaceRemaining >= numExpand) ? (spaceRemaining / numExpand) : 1; numExpand = 0; /* Allocate extra space to the *bottom* padding first so that any * extra single pixel is given to the bottom. */ if (flags & ELF_eEXPAND_S) { int add = each; ePadY[PAD_BOTTOM_RIGHT] += add; layout->eHeight += add; spaceRemaining -= add; spaceUsed += add; if (!spaceRemaining) break; numExpand++; } if (flags & ELF_iEXPAND_S) { int add = each; iPadY[PAD_BOTTOM_RIGHT] += add; layout->iHeight += add; layout->eHeight += add; spaceRemaining -= add; spaceUsed += add; if (!spaceRemaining) break; numExpand++; } if (flags & ELF_iEXPAND_Y) { int max = eLink1->maxHeight; if ((max < 0) || (layout->useHeight < max)) { int add = (max < 0) ? each : MIN(each, max - layout->useHeight); layout->useHeight += add; layout->iHeight += add; layout->eHeight += add; spaceRemaining -= add; spaceUsed += add; if ((max >= 0) && (max == layout->useHeight)) layout->temp--; if (!spaceRemaining) break; if ((max < 0) || (max > layout->useHeight)) numExpand++; } } if (flags & ELF_iEXPAND_N) { int add = each; iPadY[PAD_TOP_LEFT] += add; layout->iHeight += add; layout->eHeight += add; spaceRemaining -= add; spaceUsed += add; if (!spaceRemaining) break; numExpand++; } if (flags & ELF_eEXPAND_N) { int add = each; ePadY[PAD_TOP_LEFT] += add; layout->eHeight += add; spaceRemaining -= add; spaceUsed += add; if (!spaceRemaining) break; numExpand++; } } return spaceUsed; } /* *---------------------------------------------------------------------- * * ElementLink_NeededSize -- * * Calculate the needed width and height of an element. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Element_NeededSize( TreeCtrl *tree, /* Widget info. */ MElementLink *eLink1, /* Master style layout info. */ TreeElement elem, /* Master/Instance element. */ int state, /* STATE_xxx flags. */ int *widthPtr, /* Out: width */ int *heightPtr /* Out: height */ ) { TreeElementArgs args; int width, height; if ((eLink1->fixedWidth >= 0) && (eLink1->fixedHeight >= 0)) { width = eLink1->fixedWidth; height = eLink1->fixedHeight; } else { args.tree = tree; args.state = state; args.elem = elem; args.needed.fixedWidth = eLink1->fixedWidth; args.needed.fixedHeight = eLink1->fixedHeight; if (eLink1->maxWidth > eLink1->minWidth) args.needed.maxWidth = eLink1->maxWidth; else args.needed.maxWidth = -1; if (eLink1->maxHeight > eLink1->minHeight) args.needed.maxHeight = eLink1->maxHeight; else args.needed.maxHeight = -1; (*args.elem->typePtr->neededProc)(&args); width = args.needed.width; height = args.needed.height; if (eLink1->fixedWidth >= 0) width = eLink1->fixedWidth; else if ((eLink1->minWidth >= 0) && (width < eLink1->minWidth)) width = eLink1->minWidth; else if ((eLink1->maxWidth >= 0) && (width > eLink1->maxWidth)) width = eLink1->maxWidth; if (eLink1->fixedHeight >= 0) height = eLink1->fixedHeight; else if ((eLink1->minHeight >= 0) && (height < eLink1->minHeight)) height = eLink1->minHeight; else if ((eLink1->maxHeight >= 0) && (height > eLink1->maxHeight)) height = eLink1->maxHeight; } *widthPtr = width; *heightPtr = height; } /* *---------------------------------------------------------------------- * * Layout_CalcVisibility -- * * Recursively calculate the visibility of each element. * * Results: * Layout.visible is set for each element if it wasn't done * already. For -union elements the first and last visible * elements in the union are determined. If there are no * visible elements in the union then the union element * itself is marked 'not visible'. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Layout_CalcVisibility( TreeCtrl *tree, int state, MStyle *masterStyle, struct Layout layouts[], int iElem ) { struct Layout *layout = &layouts[iElem]; MElementLink *eLink = &masterStyle->elements[iElem]; int i, visible = 0; if (layout->temp != 0) return; /* Already did this one */ layout->temp = 1; layout->visible = PerStateBoolean_ForState(tree, &eLink->visible, state, NULL) != 0; if (IS_HIDDEN(layout) || !IS_UNION(eLink)) return; /* Remember the first and last visible elements surrounded by * this -union element. */ layout->unionFirst = layout->unionLast = -1; for (i = 0; i < eLink->onionCount; i++) { struct Layout *layout2 = &layouts[eLink->onion[i]]; Layout_CalcVisibility(tree, state, masterStyle, layouts, eLink->onion[i]); if (!IS_HIDDEN(layout2)) { if (layout->unionFirst == -1) layout->unionFirst = eLink->onion[i]; layout->unionLast = eLink->onion[i]; visible++; } } /* If there are no visible elements surrounded by this -union * element, then hide it. */ if (visible == 0) layout->visible = 0; } /* *---------------------------------------------------------------------- * * Layout_AddUnionPadding -- * * Recursively determine the amount of -union padding around * each element that is part of a -union. * * Results: * If the element isn't a -union element itself then the * Layout.uPadX and Layout.uPadY fields are updated. * If the element is a -union element itself then its padding * is added to the total padding and passed on to its -union * elements recursively. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Layout_AddUnionPadding( TreeCtrl *tree, /* Widget info. */ MStyle *masterStyle, /* Style being layed out. */ struct Layout layouts[], /* Layout info for every element. */ int iElemParent, /* Whose -union iElem is in. */ int iElem, /* The element to update. */ const int totalPadX[2], /* The cumulative padding around */ const int totalPadY[2] /* iElemParent plus the -ipad */ /* padding of iElemParent itself. */ ) { struct Layout *layoutP = &layouts[iElemParent]; struct Layout *layout = &layouts[iElem]; MElementLink *eLink = &masterStyle->elements[iElem]; int *ePadX, *ePadY, *iPadX, *iPadY, *uPadX, *uPadY; int padX[2], padY[2]; int i; #ifdef TREECTRL_DEBUG if (IS_HIDDEN(layoutP) || IS_HIDDEN(layout)) panic("Layout_AddUnionPadding: element is hidden"); #endif uPadX = layout->uPadX; uPadY = layout->uPadY; if (masterStyle->vertical) { uPadX[PAD_TOP_LEFT] = MAX(uPadX[PAD_TOP_LEFT], totalPadX[PAD_TOP_LEFT]); uPadX[PAD_BOTTOM_RIGHT] = MAX(uPadX[PAD_BOTTOM_RIGHT], totalPadX[PAD_BOTTOM_RIGHT]); if (iElem == layoutP->unionFirst) /* topmost */ uPadY[PAD_TOP_LEFT] = MAX(uPadY[PAD_TOP_LEFT], totalPadY[PAD_TOP_LEFT]); if (iElem == layoutP->unionLast) /* bottommost */ uPadY[PAD_BOTTOM_RIGHT] = MAX(uPadY[PAD_BOTTOM_RIGHT], totalPadY[PAD_BOTTOM_RIGHT]); } else { if (iElem == layoutP->unionFirst) /* leftmost */ uPadX[PAD_TOP_LEFT] = MAX(uPadX[PAD_TOP_LEFT], totalPadX[PAD_TOP_LEFT]); if (iElem == layoutP->unionLast) /* rightmost */ uPadX[PAD_BOTTOM_RIGHT] = MAX(uPadX[PAD_BOTTOM_RIGHT], totalPadX[PAD_BOTTOM_RIGHT]); uPadY[PAD_TOP_LEFT] = MAX(uPadY[PAD_TOP_LEFT], totalPadY[PAD_TOP_LEFT]); uPadY[PAD_BOTTOM_RIGHT] = MAX(uPadY[PAD_BOTTOM_RIGHT], totalPadY[PAD_BOTTOM_RIGHT]); } /* In the original header-layout code, the bitmap/image/text/arrow's * -XXXpady padding did not overlap the content margins, so the top and * bottom external padding of elements in a header element's -union is * added to the union padding around each element. */ /* In the original header-layout code, the -arrowpadx padding would * overlap the padding of the adjacent bitmap/image/text, so any elements * adjacent to the sort arrow have their union padding increased by any * positive difference between their external padding and the sort arrow's * external padding. */ /* In the original header-layout code, the total width of the header was * equal to the width of the bitmap/image/text plus overlapped padding * between them plus padding on the exteme left and right, so, even if * there is no arrow padding, the union padding of elements on the extreme * left or right is increased by those element's external padding. */ if (ELEMENT_TYPE_MATCHES(layoutP->master->elem->typePtr, &treeElemTypeHeader)) { int arrowPadLeft = layoutP->uMargins[2] - layoutP->eMargins[2]; int arrowPadRight = layoutP->uMargins[0] - layoutP->eMargins[0]; if (masterStyle->vertical) { uPadX[PAD_TOP_LEFT] += MAX(layout->ePadX[PAD_TOP_LEFT] - arrowPadRight, 0); uPadX[PAD_BOTTOM_RIGHT] += MAX(layout->ePadX[PAD_BOTTOM_RIGHT] - arrowPadLeft, 0); if (iElem == layoutP->unionFirst) /* topmost */ uPadY[PAD_TOP_LEFT] += layout->ePadY[PAD_TOP_LEFT]; if (iElem == layoutP->unionLast) /* bottommost */ uPadY[PAD_BOTTOM_RIGHT] += layout->ePadY[PAD_BOTTOM_RIGHT]; } else { if (iElem == layoutP->unionFirst) /* leftmost */ uPadX[PAD_TOP_LEFT] += MAX(layout->ePadX[PAD_TOP_LEFT] - arrowPadRight, 0); if (iElem == layoutP->unionLast) /* rightmost */ uPadX[PAD_BOTTOM_RIGHT] += MAX(layout->ePadX[PAD_BOTTOM_RIGHT] - arrowPadLeft, 0); uPadY[PAD_TOP_LEFT] += layout->ePadY[PAD_TOP_LEFT]; uPadY[PAD_BOTTOM_RIGHT] += layout->ePadY[PAD_BOTTOM_RIGHT]; } } if (!IS_UNION(eLink)){ return; } ePadX = layout->ePadX; ePadY = layout->ePadY; iPadX = layout->iPadX; iPadY = layout->iPadY; for (i = 0; i < 2; i++) { padX[i] = MAX(totalPadX[i], ePadX[i]) + iPadX[i] + layout->uMargins[i*2]; padY[i] = MAX(totalPadY[i], ePadY[i]) + iPadY[i] + layout->uMargins[i*2+1]; } for (i = 0; i < eLink->onionCount; i++) { struct Layout *layout2 = &layouts[eLink->onion[i]]; if (IS_HIDDEN(layout2)) continue; Layout_AddUnionPadding(tree, masterStyle, layouts, iElem, eLink->onion[i], padX, padY ); } } /* *---------------------------------------------------------------------- * * Layout_ExpandUnionH -- * * Add extra horizontal space to a single IS_UNION element. * Expansion of -union elements is different than non-union * elements. Expanding a -union element never changes the size or * position of any element other than the -union element itself. * * Results: * Layout.ePadX and Layout.iPadX are given extra space as needed. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Layout_ExpandUnionH( StyleDrawArgs *drawArgs, /* Various args. */ MStyle *masterStyle, /* Style being layed out. */ struct Layout layouts[], /* Layout info for every element. */ int iElem /* The element to update. */ ) { struct Layout *layout = &layouts[iElem]; MElementLink *eLink1 = &masterStyle->elements[iElem]; int *ePadX, *iPadX, *uPadX; int extraWidth, x, indent = drawArgs->indent; #ifdef TREECTRL_DEBUG if (IS_HIDDEN(layout)) panic("Layout_ExpandUnionH: element is hidden"); if (!IS_UNION(eLink1)) panic("Layout_ExpandUnionH: element is !union"); #endif if (!(eLink1->flags & ELF_EXPAND_WE)) return; /* Hack -- header elements may not be indented by -canvaspadx. */ if ((masterStyle->stateDomain == STATE_DOMAIN_HEADER) && !(eLink1->flags & ELF_INDENT)) indent = 0; if (drawArgs->width - (layout->eWidth + indent) <= 0) return; ePadX = layout->ePadX; iPadX = layout->iPadX; uPadX = layout->uPadX; x = layout->x + ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]); extraWidth = x - indent; if ((extraWidth > 0) && (eLink1->flags & ELF_EXPAND_W)) { /* External and internal expansion: W */ if ((eLink1->flags & ELF_EXPAND_W) == ELF_EXPAND_W) { int eExtra = extraWidth / 2; int iExtra = extraWidth - extraWidth / 2; layout->x = indent + uPadX[PAD_TOP_LEFT]; /* External expansion */ ePadX[PAD_TOP_LEFT] += eExtra; layout->eWidth += extraWidth; /* Internal expansion */ iPadX[PAD_TOP_LEFT] += iExtra; layout->iWidth += iExtra; } /* External expansion only: W */ else if (eLink1->flags & ELF_eEXPAND_W) { ePadX[PAD_TOP_LEFT] += extraWidth; layout->x = indent + uPadX[PAD_TOP_LEFT]; layout->eWidth += extraWidth; } /* Internal expansion only: W */ else { iPadX[PAD_TOP_LEFT] += extraWidth; layout->x = indent + uPadX[PAD_TOP_LEFT]; layout->iWidth += extraWidth; layout->eWidth += extraWidth; } } x = layout->x + layout->eWidth - ePadX[PAD_BOTTOM_RIGHT] + MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]); extraWidth = drawArgs->width - x; if ((extraWidth > 0) && (eLink1->flags & ELF_EXPAND_E)) { /* External and internal expansion: E */ if ((eLink1->flags & ELF_EXPAND_E) == ELF_EXPAND_E) { int eExtra = extraWidth / 2; int iExtra = extraWidth - extraWidth / 2; /* External expansion */ ePadX[PAD_BOTTOM_RIGHT] += eExtra; layout->eWidth += extraWidth; /* all the space */ /* Internal expansion */ iPadX[PAD_BOTTOM_RIGHT] += iExtra; layout->iWidth += iExtra; } /* External expansion only: E */ else if (eLink1->flags & ELF_eEXPAND_E) { ePadX[PAD_BOTTOM_RIGHT] += extraWidth; layout->eWidth += extraWidth; } /* Internal expansion only: E */ else { iPadX[PAD_BOTTOM_RIGHT] += extraWidth; layout->iWidth += extraWidth; layout->eWidth += extraWidth; } } } /* *---------------------------------------------------------------------- * * Layout_ExpandUnionV -- * * Add extra vertical space to a single IS_UNION element. * Expansion of -union elements is different than non-union * elements. Expanding a -union element never changes the size or * position of any element other than the -union element itself. * * Results: * Layout.ePadY and Layout.iPadY are given extra space as needed. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Layout_ExpandUnionV( StyleDrawArgs *drawArgs, /* Various args. */ MStyle *masterStyle, /* Style being layed out. */ struct Layout layouts[], /* Layout info for every element. */ int iElem /* The element to update. */ ) { struct Layout *layout = &layouts[iElem]; MElementLink *eLink1 = &masterStyle->elements[iElem]; int *ePadY, *iPadY, *uPadY; int extraHeight, y; #ifdef TREECTRL_DEBUG if (IS_HIDDEN(layout)) panic("Layout_ExpandUnionV: element is hidden"); if (!IS_UNION(eLink1)) panic("Layout_ExpandUnionV: element is !union"); #endif if (!(eLink1->flags & ELF_EXPAND_NS)) return; if (drawArgs->height - layout->eHeight <= 0) return; ePadY = layout->ePadY; iPadY = layout->iPadY; uPadY = layout->uPadY; y = layout->y + ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]); extraHeight = y; if ((extraHeight > 0) && (eLink1->flags & ELF_EXPAND_N)) { /* External and internal expansion: N */ if ((eLink1->flags & ELF_EXPAND_N) == ELF_EXPAND_N) { int eExtra = extraHeight / 2; int iExtra = extraHeight - extraHeight / 2; /* External expansion */ ePadY[PAD_TOP_LEFT] += eExtra; layout->y = uPadY[PAD_TOP_LEFT]; layout->eHeight += extraHeight; /* Internal expansion */ iPadY[PAD_TOP_LEFT] += iExtra; layout->iHeight += iExtra; } /* External expansion only: N */ else if (eLink1->flags & ELF_eEXPAND_N) { ePadY[PAD_TOP_LEFT] += extraHeight; layout->y = uPadY[PAD_TOP_LEFT]; layout->eHeight += extraHeight; } /* Internal expansion only: N */ else { iPadY[PAD_TOP_LEFT] += extraHeight; layout->y = uPadY[PAD_TOP_LEFT]; layout->iHeight += extraHeight; layout->eHeight += extraHeight; } } y = layout->y + layout->eHeight - ePadY[PAD_BOTTOM_RIGHT] + MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]); extraHeight = drawArgs->height - y; if ((extraHeight > 0) && (eLink1->flags & ELF_EXPAND_S)) { /* External and internal expansion: S */ if ((eLink1->flags & ELF_EXPAND_S) == ELF_EXPAND_S) { int eExtra = extraHeight / 2; int iExtra = extraHeight - extraHeight / 2; /* External expansion */ ePadY[PAD_BOTTOM_RIGHT] += eExtra; layout->eHeight += extraHeight; /* all the space */ /* Internal expansion */ iPadY[PAD_BOTTOM_RIGHT] += iExtra; layout->iHeight += iExtra; } /* External expansion only: S */ else if (eLink1->flags & ELF_eEXPAND_S) { ePadY[PAD_BOTTOM_RIGHT] += extraHeight; layout->eHeight += extraHeight; } /* Internal expansion only */ else { iPadY[PAD_BOTTOM_RIGHT] += extraHeight; layout->iHeight += extraHeight; layout->eHeight += extraHeight; } } } /* *---------------------------------------------------------------------- * * Layout_CalcUnionLayoutH -- * * Recursively calculate the horizontal size and position of * a -union element. * * Results: * The Layout record for the element is updated by getting the * horizontal bounds of each element in its -union (after they * have their size and position calculated). Then expansion * is performed. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Layout_CalcUnionLayoutH( StyleDrawArgs *drawArgs, /* Various args. */ MStyle *masterStyle, /* Style being layed out. */ struct Layout layouts[], /* Layout info for every element. */ int iElem /* Index of the union element. */ ) { struct Layout *layout = &layouts[iElem]; MElementLink *eLink = &masterStyle->elements[iElem]; int *ePadX, *iPadX; int i, iW, iE, eW, eE; #ifdef TREECTRL_DEBUG if (IS_HIDDEN(layout)) panic("Layout_CalcUnionLayoutH: element is hidden"); #endif if (!IS_UNION(eLink)) return; eW = iW = 1000000, eE = iE = -1000000; for (i = 0; i < eLink->onionCount; i++) { struct Layout *layout2 = &layouts[eLink->onion[i]]; if (IS_HIDDEN(layout2)) continue; Layout_CalcUnionLayoutH(drawArgs, masterStyle, layouts, eLink->onion[i]); iW = MIN(iW, layout2->x + layout2->ePadX[PAD_TOP_LEFT]); iE = MAX(iE, layout2->x + layout2->ePadX[PAD_TOP_LEFT] + layout2->iWidth); eW = MIN(eW, layout2->x); eE = MAX(eE, layout2->x + layout2->eWidth); } layout->iUnionBbox[0] = iW; layout->iUnionBbox[2] = iE; layout->eUnionBbox[0] = eW; layout->eUnionBbox[2] = eE; ePadX = layout->ePadX; iPadX = layout->iPadX; layout->x = iW - layout->uMargins[0] - iPadX[PAD_TOP_LEFT] - ePadX[PAD_TOP_LEFT]; layout->useWidth = layout->uMargins[0] + (iE - iW) + layout->uMargins[2]; layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT]; layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT]; Layout_ExpandUnionH(drawArgs, masterStyle, layouts, iElem); } /* *---------------------------------------------------------------------- * * Layout_CalcUnionLayoutV -- * * Recursively calculate the vertical size and position of * a -union element. * * Results: * The Layout record for the element is updated by getting the * vertical bounds of each element in its -union (after they * have their size and position calculated). Then expansion * is performed. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Layout_CalcUnionLayoutV( StyleDrawArgs *drawArgs, /* Various args. */ MStyle *masterStyle, /* Style being layed out. */ struct Layout layouts[], /* Layout info for every element. */ int iElem /* Index of the union element. */ ) { struct Layout *layout = &layouts[iElem]; MElementLink *eLink = &masterStyle->elements[iElem]; int *ePadY, *iPadY; int i, iN, iS, eN, eS; #ifdef TREECTRL_DEBUG if (IS_HIDDEN(layout)) panic("Layout_CalcUnionLayoutV: element is hidden"); #endif if (!IS_UNION(eLink)) return; eN = iN = 1000000, eS = iS = -1000000; for (i = 0; i < eLink->onionCount; i++) { struct Layout *layout2 = &layouts[eLink->onion[i]]; if (IS_HIDDEN(layout2)) continue; Layout_CalcUnionLayoutV(drawArgs, masterStyle, layouts, eLink->onion[i]); iN = MIN(iN, layout2->y + layout2->ePadY[PAD_TOP_LEFT]); iS = MAX(iS, layout2->y + layout2->ePadY[PAD_TOP_LEFT] + layout2->iHeight); eN = MIN(eN, layout2->y); eS = MAX(eS, layout2->y + layout2->eHeight); } layout->iUnionBbox[1] = iN; layout->iUnionBbox[3] = iS; layout->eUnionBbox[1] = eN; layout->eUnionBbox[3] = eS; ePadY = layout->ePadY; iPadY = layout->iPadY; layout->y = iN - layout->uMargins[1] - iPadY[PAD_TOP_LEFT] - ePadY[PAD_TOP_LEFT]; layout->useHeight = layout->uMargins[1] + (iS - iN) + layout->uMargins[3]; layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; Layout_ExpandUnionV(drawArgs, masterStyle, layouts, iElem); } /* *---------------------------------------------------------------------- * * Layout_ExpandElementsH -- * * Adds extra horizontal space to a range of elements. * * Results: * layouts[] is updated. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Layout_ExpandElementsH( StyleDrawArgs *drawArgs, /* Various args. */ struct Layout layouts[], /* All the layouts for the style. */ int iElemMin, /* Index of the first element. */ int iElemMax, /* Index of the last element. */ int maxX /* The right edge limiting expansion. */ ) { MElementLink *eLink1; int i, j, numExpand = 0, rightEdge = 0, rightEdgeU = 0; int spaceRemaining, totalUsed = 0; if (iElemMin > iElemMax) return 0; /* Each element has 5 areas that can optionally expand. */ for (i = iElemMin; i <= iElemMax; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = layout->master; layout->temp = 0; if (DETACH_OR_UNION(eLink1)) continue; rightEdge = layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth + layout->ePadX[PAD_BOTTOM_RIGHT]; rightEdgeU = MAX(rightEdgeU, layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth + MAX(layout->ePadX[PAD_BOTTOM_RIGHT], layout->uPadX[PAD_BOTTOM_RIGHT])); if (eLink1->flags & ELF_eEXPAND_W) layout->temp++; if (eLink1->flags & ELF_iEXPAND_W) layout->temp++; if (eLink1->flags & ELF_iEXPAND_X) { if ((eLink1->maxWidth < 0) || (eLink1->maxWidth > layout->useWidth)) layout->temp++; } if (eLink1->flags & ELF_iEXPAND_E) layout->temp++; if (eLink1->flags & ELF_eEXPAND_E) layout->temp++; numExpand += layout->temp; } if (numExpand == 0) return 0; spaceRemaining = maxX - rightEdge; if (drawArgs->width - rightEdgeU < spaceRemaining) spaceRemaining = drawArgs->width - rightEdgeU; if (spaceRemaining <= 0) return 0; while ((spaceRemaining > 0) && (numExpand > 0)) { int each = (spaceRemaining >= numExpand) ? spaceRemaining / numExpand : 1; numExpand = 0; for (i = iElemMin; i <= iElemMax; i++) { struct Layout *layout = &layouts[i]; int spaceUsed; if (IS_HIDDEN(layout)) continue; if (!layout->temp) continue; eLink1 = layout->master; spaceUsed = Style_DoExpandH(layout, MIN(each * layout->temp, spaceRemaining)); if (spaceUsed) { /* Shift following elements to the right */ for (j = i + 1; j <= iElemMax; j++) if (!IS_HIDDEN(&layouts[j]) && !DETACH_OR_UNION(layouts[j].master)) layouts[j].x += spaceUsed; totalUsed += spaceUsed; spaceRemaining -= spaceUsed; if (!spaceRemaining) break; numExpand += layout->temp; } else layout->temp = 0; } } return totalUsed; } /* *---------------------------------------------------------------------- * * Layout_ExpandElementsV -- * * Adds extra vertical space to a range of elements. * * Results: * layouts[] is updated. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int Layout_ExpandElementsV( StyleDrawArgs *drawArgs, /* Various args. */ struct Layout layouts[], /* All the layouts for the style. */ int iElemMin, /* Index of the first element. */ int iElemMax, /* Index of the last element. */ int maxY /* The bottom edge limiting expansion. */ ) { MElementLink *eLink1; int i, j, numExpand = 0, bottomEdge = 0, bottomEdgeU = 0; int spaceRemaining, totalUsed = 0; if (iElemMin > iElemMax) return 0; /* Each element has 5 areas that can optionally expand. */ for (i = iElemMin; i <= iElemMax; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = layout->master; layout->temp = 0; if (DETACH_OR_UNION(eLink1)) continue; bottomEdge = layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight + layout->ePadY[PAD_BOTTOM_RIGHT]; bottomEdgeU = MAX(bottomEdgeU, layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight + MAX(layout->ePadY[PAD_BOTTOM_RIGHT], layout->uPadY[PAD_BOTTOM_RIGHT])); if (eLink1->flags & ELF_eEXPAND_N) layout->temp++; if (eLink1->flags & ELF_iEXPAND_N) layout->temp++; if (eLink1->flags & ELF_iEXPAND_Y) { if ((eLink1->maxHeight < 0) || (eLink1->maxHeight > layout->useHeight)) layout->temp++; } if (eLink1->flags & ELF_iEXPAND_S) layout->temp++; if (eLink1->flags & ELF_eEXPAND_S) layout->temp++; numExpand += layout->temp; } if (numExpand == 0) return 0; spaceRemaining = maxY - bottomEdge; if (drawArgs->height - bottomEdgeU < spaceRemaining) spaceRemaining = drawArgs->height - bottomEdgeU; if (spaceRemaining <= 0) return 0; while ((spaceRemaining > 0) && (numExpand > 0)) { int each = (spaceRemaining >= numExpand) ? spaceRemaining / numExpand : 1; numExpand = 0; for (i = iElemMin; i <= iElemMax; i++) { struct Layout *layout = &layouts[i]; int spaceUsed; if (IS_HIDDEN(layout)) continue; if (!layout->temp) continue; eLink1 = layout->master; spaceUsed = Style_DoExpandV(layout, MIN(each * layout->temp, spaceRemaining)); if (spaceUsed) { /* Shift following elements down */ for (j = i + 1; j <= iElemMax; j++) if (!IS_HIDDEN(&layouts[j]) && !DETACH_OR_UNION(layouts[j].master)) layouts[j].y += spaceUsed; totalUsed += spaceUsed; spaceRemaining -= spaceUsed; if (!spaceRemaining) break; numExpand += layout->temp; } else layout->temp = 0; } } return totalUsed; } /* *---------------------------------------------------------------------- * * Style_DoLayoutH -- * * Calculate the horizontal size and position of each element. * This gets called if the style -orient option is horizontal or * vertical. * * Results: * layouts[] is updated. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Style_DoLayoutH( StyleDrawArgs *drawArgs, /* Various args. */ struct Layout layouts[] /* Array of layout records to be * filled in, one per element. Should be * uninitialized. */ ) { TreeCtrl *tree = drawArgs->tree; IStyle *style = (IStyle *) drawArgs->style; MStyle *masterStyle = style->master; MElementLink *eLinks1, *eLink1; IElementLink *eLinks2, *eLink2; int x = drawArgs->indent; int *ePadX, *iPadX, *uPadX, *ePadY, *iPadY; int numExpandWE = 0; int numSqueezeX = 0; int i, j, eLinkCount = 0; int rightEdge = 0; int iCenterMin = -1, iCenterMax = -1; eLinks1 = masterStyle->elements; eLinks2 = style->elements; eLinkCount = masterStyle->numElements; for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; layout->unionParent = 0; layout->temp = 0; /* see Layout_CalcVisibility */ } for (i = 0; i < eLinkCount; i++) { Layout_CalcVisibility(drawArgs->tree, drawArgs->state, masterStyle, layouts, i); } for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; eLink2 = &eLinks2[i]; if (IS_UNION(eLink1)) { for (j = 0; j < eLink1->onionCount; j++) { struct Layout *layout2 = &layouts[eLink1->onion[j]]; if (!IS_HIDDEN(layout2)) { layout2->unionParent = 1; } } } layout->eLink = eLink2; layout->master = eLink1; /* Width before squeezing/expanding */ if (IS_UNION(eLink1)) { layout->useWidth = 0; } else { #ifdef CACHE_ELEM_SIZE layout->useWidth = eLink2->neededWidth; #else Element_NeededSize(drawArgs->tree, eLink1, eLink2->elem, drawArgs->state, &layout->neededWidth, &layout->neededHeight); layout->useWidth = layout->neededWidth; #endif } for (j = 0; j < 2; j++) { /* Pad values before expansion */ layout->ePadX[j] = eLink1->ePadX[j]; layout->ePadY[j] = eLink1->ePadY[j]; layout->iPadX[j] = eLink1->iPadX[j]; layout->iPadY[j] = eLink1->iPadY[j]; /* No -union padding yet */ layout->uPadX[j] = 0; layout->uPadY[j] = 0; layout->iUnionBbox[j] = layout->iUnionBbox[j+2] = -1; layout->eUnionBbox[j] = layout->eUnionBbox[j+2] = -1; } TreeElement_GetContentMargins(tree, layout->eLink->elem, drawArgs->state, layout->eMargins, layout->uMargins, &layout->arrowHeight); /* Count all non-union, non-detach squeezeable elements */ if (DETACH_OR_UNION(eLink1)) continue; if (eLink1->flags & ELF_SQUEEZE_X) numSqueezeX++; if (IS_CENTER_X(eLink1)) { if (iCenterMin == -1) iCenterMin = i; iCenterMax = i; } } /* e1 { e2 <---------- e3 { e7 e4 { e2 <---------- e5 } } } */ /* Calculate the padding around elements surrounded by -union elements */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int padx[2], pady[2]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; /* Start at the top level of each -union heirarchy. */ if (!IS_UNION(eLink1) || layout->unionParent) continue; ePadX = layout->ePadX; ePadY = layout->ePadY; iPadX = layout->iPadX; iPadY = layout->iPadY; for (j = 0; j < 2; j++) { padx[j] = ePadX[j] + iPadX[j] + layout->uMargins[j*2]; pady[j] = ePadY[j] + iPadY[j] + layout->uMargins[j*2+1]; } for (j = 0; j < eLink1->onionCount; j++) { struct Layout *layout2 = &layouts[eLink1->onion[j]]; if (IS_HIDDEN(layout2)) continue; Layout_AddUnionPadding(tree, masterStyle, layouts, i, eLink1->onion[j], padx, pady ); } } /* Left-to-right layout. Make the width of some elements less than they * need */ if (!masterStyle->vertical && (drawArgs->width < style->neededWidth + drawArgs->indent) && (numSqueezeX > 0)) { int numSqueeze = numSqueezeX; int spaceRemaining = (style->neededWidth + drawArgs->indent) - drawArgs->width; while ((spaceRemaining > 0) && (numSqueeze > 0)) { int each = (spaceRemaining >= numSqueeze) ? (spaceRemaining / numSqueeze) : 1; numSqueeze = 0; for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int min = 0; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (DETACH_OR_UNION(eLink1)) continue; if (!(eLink1->flags & ELF_SQUEEZE_X)) continue; if (eLink1->minWidth >= 0) min = eLink1->minWidth; if (layout->useWidth > min) { int sub = MIN(each, layout->useWidth - min); layout->useWidth -= sub; spaceRemaining -= sub; if (!spaceRemaining) break; if (layout->useWidth > min) numSqueeze++; } } } } /* Reduce the width of all non-union elements, except for the * cases handled above. */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int width, subtract; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (IS_UNION(eLink1)) continue; if (!(eLink1->flags & ELF_SQUEEZE_X)) continue; if (!IS_DETACH(eLink1) && !masterStyle->vertical) continue; ePadX = layout->ePadX; iPadX = layout->iPadX; uPadX = layout->uPadX; width = MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]) + iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT] + MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]); subtract = width - drawArgs->width; if (!IS_DETACH(eLink1) || (eLink1->flags & ELF_INDENT)) subtract += drawArgs->indent; if (subtract > 0) { if ((eLink1->minWidth >= 0) && (eLink1->minWidth <= layout->useWidth) && (layout->useWidth - subtract < eLink1->minWidth)) layout->useWidth = eLink1->minWidth; else layout->useWidth -= subtract; } } /* Calculate the horizontal position and size of all non-union, non-detach * elements. */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int right; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; eLink2 = &eLinks2[i]; if (DETACH_OR_UNION(eLink1)) continue; ePadX = layout->ePadX; iPadX = layout->iPadX; uPadX = layout->uPadX; layout->x = x + abs(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT])); layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT]; layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT]; right = layout->x + ePadX[PAD_TOP_LEFT] + layout->iWidth + MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]); rightEdge = MAX(rightEdge, right); if (!masterStyle->vertical) x = layout->x + layout->eWidth; /* Count number that want to expand */ if (eLink1->flags & (ELF_EXPAND_WE | ELF_iEXPAND_X)) numExpandWE++; } /* Left-to-right layout. Center some elements horizontally. */ if (!masterStyle->vertical && (iCenterMin != -1) /*&& (drawArgs->width > style->neededWidth + drawArgs->indent)*/) { int widthCenter, spaceRemaining; int x1, x2, dx; /* Calculate the new x-coordinate of the left-most centered element * such that all the centered elements are centered in the total * width available to the style (minus indent). The calculation * ignores all padding on the left and right edges of the * centered elements when considered as a group. */ x1 = layouts[iCenterMax].x + layouts[iCenterMax].eWidth - layouts[iCenterMax].ePadX[PAD_BOTTOM_RIGHT]; x2 = layouts[iCenterMin].x + layouts[iCenterMin].ePadX[PAD_TOP_LEFT]; widthCenter = x1 - x2; spaceRemaining = (drawArgs->width - drawArgs->indent - widthCenter); x = drawArgs->indent + spaceRemaining / 2; /* Don't push elements so far to the right that they go past the * right side of the style. */ dx = x - (layouts[iCenterMin].x + layouts[iCenterMin].ePadX[PAD_TOP_LEFT]); if (dx > drawArgs->width - rightEdge) x -= dx - (drawArgs->width - rightEdge); if (x > layouts[iCenterMin].x + layouts[iCenterMin].ePadX[PAD_TOP_LEFT]) { int dx = x - (layouts[iCenterMin].x + layouts[iCenterMin].ePadX[PAD_TOP_LEFT]); for (i = iCenterMin; i < eLinkCount; i++) { if (!IS_HIDDEN(&layouts[i]) && !DETACH_OR_UNION(&eLinks1[i])) layouts[i].x += dx; } } /* Expand all elements to the left of the centered elements. */ Layout_ExpandElementsH(drawArgs, layouts, 0, iCenterMin - 1, /* Left-side union padding does separate the elements. */ x - MAX(layouts[iCenterMin].ePadX[PAD_TOP_LEFT], layouts[iCenterMin].uPadX[PAD_TOP_LEFT])); /* Expand all elements to the right of the centered elements. */ Layout_ExpandElementsH(drawArgs, layouts, iCenterMax + 1, eLinkCount - 1, drawArgs->width); /* Disable justification. */ rightEdge = drawArgs->width; } /* Left-to-right layout. Expand some elements horizontally if we have * more space available horizontally than is needed by the Style. */ if (!masterStyle->vertical && (iCenterMin == -1) && (drawArgs->width > rightEdge) && (numExpandWE > 0)) { rightEdge += Layout_ExpandElementsH(drawArgs, layouts, 0, eLinkCount - 1, drawArgs->width); } /* Top-to-bottom layout. Center individual elements horizontally. */ if (masterStyle->vertical && (iCenterMin != -1)) { for (i = iCenterMin; i <= iCenterMax; i++) { struct Layout *layout = &layouts[i]; int right, spaceRemaining, dx; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (DETACH_OR_UNION(eLink1)) continue; if (!IS_CENTER_X(eLink1)) continue; spaceRemaining = (drawArgs->width - drawArgs->indent - layout->iWidth); x = drawArgs->indent + spaceRemaining / 2; /* Don't push elements so far to the right that they go past the * right side of the style. */ dx = x - (layout->x + layout->ePadX[PAD_TOP_LEFT]); right = layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth + MAX(layout->ePadX[PAD_BOTTOM_RIGHT], layout->uPadX[PAD_BOTTOM_RIGHT]); if (dx > drawArgs->width - right) x -= dx - (drawArgs->width - right); if (x > layout->x + layout->ePadX[PAD_TOP_LEFT]) { dx = x - (layout->x + layout->ePadX[PAD_TOP_LEFT]); layout->x += dx; } } } /* Top-to-bottom layout. Expand some elements horizontally */ if (masterStyle->vertical && (numExpandWE > 0)) { for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int right; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (DETACH_OR_UNION(eLink1)) continue; if (IS_CENTER_X(eLink1)) continue; right = layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth + MAX(layout->ePadX[PAD_BOTTOM_RIGHT], layout->uPadX[PAD_BOTTOM_RIGHT]); layout->temp = 0; right += Style_DoExpandH(layout, drawArgs->width - right); rightEdge = MAX(rightEdge, right); } } /* Now handle column justification */ /* All the non-union, non-detach elements are moved as a group */ if (drawArgs->width > rightEdge) { int dx = drawArgs->width - rightEdge; for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (DETACH_OR_UNION(eLink1)) continue; if (masterStyle->vertical && IS_CENTER_X(eLink1)) continue; switch (drawArgs->justify) { case TK_JUSTIFY_LEFT: break; case TK_JUSTIFY_RIGHT: layout->x += dx; break; case TK_JUSTIFY_CENTER: layout->x += dx / 2; break; } } } /* Position and expand -detach elements */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int right; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; eLink2 = &eLinks2[i]; if (!IS_DETACH(eLink1) || IS_UNION(eLink1)) continue; ePadX = layout->ePadX; iPadX = layout->iPadX; uPadX = layout->uPadX; layout->x = abs(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT])); if (eLink1->flags & ELF_INDENT) layout->x += drawArgs->indent; layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT]; layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT]; right = layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth + MAX(layout->ePadX[PAD_BOTTOM_RIGHT], layout->uPadX[PAD_BOTTOM_RIGHT]); layout->temp = 0; Style_DoExpandH(layout, drawArgs->width - right); } /* Position and expand -union elements. */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; /* Start at the top level of each -union heirarchy. */ if (!IS_UNION(eLink1) || layout->unionParent) continue; Layout_CalcUnionLayoutH(drawArgs, masterStyle, layouts, i); } /* Add internal padding to display area for -union elements */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (!IS_UNION(eLink1)) continue; iPadX = layout->iPadX; layout->useWidth += iPadX[PAD_TOP_LEFT] + iPadX[PAD_BOTTOM_RIGHT]; iPadX[PAD_TOP_LEFT] = iPadX[PAD_BOTTOM_RIGHT] = 0; } } /* *---------------------------------------------------------------------- * * Style_DoLayoutV -- * * Calculate the vertical size and position of each element. * This gets called if the style -orient option is horizontal or * vertical. * * Results: * layouts[] is updated. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Style_DoLayoutV( StyleDrawArgs *drawArgs, /* Various args. */ struct Layout layouts[] /* Array of layout records to be updated, * one per element. Should be initialized * by Style_DoLayoutH(). */ ) { IStyle *style = (IStyle *) drawArgs->style; MStyle *masterStyle = style->master; MElementLink *eLinks1, *eLink1; IElementLink *eLinks2, *eLink2; int y = 0; int *ePadY, *iPadY, *uPadY; int numExpandNS = 0; int numSqueezeY = 0; int i, eLinkCount = 0; int bottomEdge = 0; int iCenterMin = -1, iCenterMax = -1; eLinks1 = masterStyle->elements; eLinks2 = style->elements; eLinkCount = masterStyle->numElements; for (i = 0; i < eLinkCount; i++) { if (IS_HIDDEN(&layouts[i])) continue; eLink1 = &eLinks1[i]; /* Count all non-union, non-detach squeezeable elements */ if (DETACH_OR_UNION(eLink1)) continue; if (eLink1->flags & ELF_SQUEEZE_Y) numSqueezeY++; if (IS_CENTER_Y(eLink1)) { if (iCenterMin == -1) iCenterMin = i; iCenterMax = i; } } /* Top-top-bottom layout. Make the height of some elements less than they * need */ if (masterStyle->vertical && (drawArgs->height < style->neededHeight) && (numSqueezeY > 0)) { int numSqueeze = numSqueezeY; int spaceRemaining = style->neededHeight - drawArgs->height; while ((spaceRemaining > 0) && (numSqueeze > 0)) { int each = (spaceRemaining >= numSqueeze) ? (spaceRemaining / numSqueeze) : 1; numSqueeze = 0; for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int min = 0; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (DETACH_OR_UNION(eLink1)) continue; if (!(eLink1->flags & ELF_SQUEEZE_Y)) continue; if (eLink1->minHeight >= 0) min = eLink1->minHeight; if (layout->useHeight > min) { int sub = MIN(each, layout->useHeight - min); layout->useHeight -= sub; spaceRemaining -= sub; if (!spaceRemaining) break; if (layout->useHeight > min) numSqueeze++; } } } } /* Reduce the height of all non-union elements, except for the * cases handled above. */ if (drawArgs->height < style->neededHeight) { for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int height, subtract; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (IS_UNION(eLink1)) continue; if (!(eLink1->flags & ELF_SQUEEZE_Y)) continue; if (!IS_DETACH(eLink1) && masterStyle->vertical) continue; ePadY = layout->ePadY; iPadY = layout->iPadY; uPadY = layout->uPadY; height = MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]) + iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT] + MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]); subtract = height - drawArgs->height; if (subtract > 0) { if ((eLink1->minHeight >= 0) && (eLink1->minHeight <= layout->useHeight) && (layout->useHeight - subtract < eLink1->minHeight)) layout->useHeight = eLink1->minHeight; else layout->useHeight -= subtract; } } } /* Layout elements top-to-bottom */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int bottom; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; eLink2 = &eLinks2[i]; if (DETACH_OR_UNION(eLink1)) continue; ePadY = layout->ePadY; iPadY = layout->iPadY; uPadY = layout->uPadY; layout->y = y + abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; if (masterStyle->vertical) y = layout->y + layout->eHeight; if (masterStyle->vertical) { bottom = layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight + MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]); bottomEdge = MAX(bottomEdge, bottom); } /* Count number that want to expand */ if (eLink1->flags & (ELF_EXPAND_NS | ELF_iEXPAND_Y)) numExpandNS++; } /* Top-to-bottom layout. Center some elements vertically. */ if (masterStyle->vertical && (iCenterMin != -1) /*&& (drawArgs->height > style->neededHeight)*/) { int heightCenter, spaceRemaining; int y1, y2, dy; /* Calculate the new y-coordinate of the top-most centered element * such that all the centered elements are centered in the total * height available to the style. The calculation * ignores all padding on the top and bottom edges of the * centered elements when considered as a group. */ y1 = layouts[iCenterMax].y + layouts[iCenterMax].eHeight - layouts[iCenterMax].ePadY[PAD_BOTTOM_RIGHT]; y2 = layouts[iCenterMin].y + layouts[iCenterMin].ePadY[PAD_TOP_LEFT]; heightCenter = y1 - y2; spaceRemaining = (drawArgs->height - heightCenter); y = spaceRemaining / 2; /* Don't push elements so far to the bottom that they go past the * bottom side of the style. */ dy = y - (layouts[iCenterMin].y + layouts[iCenterMin].ePadY[PAD_TOP_LEFT]); if (dy > drawArgs->height - bottomEdge) y -= dy - (drawArgs->height - bottomEdge); if (y > layouts[iCenterMin].y + layouts[iCenterMin].ePadY[PAD_TOP_LEFT]) { int dy = y - (layouts[iCenterMin].y + layouts[iCenterMin].ePadY[PAD_TOP_LEFT]); for (i = iCenterMin; i < eLinkCount; i++) { if (!IS_HIDDEN(&layouts[i]) && !DETACH_OR_UNION(&eLinks1[i])) layouts[i].y += dy; } } /* Expand all elements above the centered elements. */ Layout_ExpandElementsV(drawArgs, layouts, 0, iCenterMin - 1, /* Top-side union padding does separate the elements. */ y - MAX(layouts[iCenterMin].ePadY[PAD_TOP_LEFT], layouts[iCenterMin].uPadY[PAD_TOP_LEFT])); /* Expand all elements below the centered elements. */ Layout_ExpandElementsV(drawArgs, layouts, iCenterMax + 1, eLinkCount - 1, drawArgs->height); } /* Top-to-bottom layout. Expand some elements vertically if we have * more space available vertically than is needed by the Style. */ if (masterStyle->vertical && (iCenterMin == -1) && (drawArgs->height > bottomEdge) && (numExpandNS > 0)) { bottomEdge += Layout_ExpandElementsV(drawArgs, layouts, 0, eLinkCount - 1, drawArgs->height); } /* Left-to-right layout. Center individual elements vertically. */ if (!masterStyle->vertical && (iCenterMin != -1)) { for (i = iCenterMin; i <= iCenterMax; i++) { struct Layout *layout = &layouts[i]; int bottom, spaceRemaining, dy; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (DETACH_OR_UNION(eLink1)) continue; if (!IS_CENTER_Y(eLink1)) continue; spaceRemaining = (drawArgs->height - layout->iHeight); y = spaceRemaining / 2; /* Don't push elements so far to the bottom that they go past the * right side of the style. */ dy = y - (layout->y + layout->ePadY[PAD_TOP_LEFT]); bottom = layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight + MAX(layout->ePadY[PAD_BOTTOM_RIGHT], layout->uPadY[PAD_BOTTOM_RIGHT]); if (dy > drawArgs->height - bottom) y -= dy - (drawArgs->height - bottom); if (y > layout->y + layout->ePadY[PAD_TOP_LEFT]) { dy = y - (layout->y + layout->ePadY[PAD_TOP_LEFT]); layout->y += dy; } } } /* Left-to-right layout. Expand some elements vertically */ if (!masterStyle->vertical && (numExpandNS > 0)) { for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int bottom; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (DETACH_OR_UNION(eLink1)) continue; if (IS_CENTER_Y(eLink1)) continue; bottom = layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight + MAX(layout->ePadY[PAD_BOTTOM_RIGHT], layout->uPadY[PAD_BOTTOM_RIGHT]); layout->temp = 0; Style_DoExpandV(layout, drawArgs->height - bottom); } } /* Position and expand -detach elements */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int bottom; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; eLink2 = &eLinks2[i]; if (!IS_DETACH(eLink1) || IS_UNION(eLink1)) continue; ePadY = layout->ePadY; iPadY = layout->iPadY; uPadY = layout->uPadY; layout->y = abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; bottom = layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight + MAX(layout->ePadY[PAD_BOTTOM_RIGHT], layout->uPadY[PAD_BOTTOM_RIGHT]); layout->temp = 0; Style_DoExpandV(layout, drawArgs->height - bottom); } /* Now calculate layout of -union elements. */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; /* Start at the top level of each -union heirarchy. */ if (!IS_UNION(eLink1) || layout->unionParent) continue; Layout_CalcUnionLayoutV(drawArgs, masterStyle, layouts, i); } /* Add internal padding to display area for -union elements */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (!IS_UNION(eLink1)) continue; iPadY = layout->iPadY; layout->useHeight += iPadY[PAD_TOP_LEFT] + iPadY[PAD_BOTTOM_RIGHT]; iPadY[PAD_TOP_LEFT] = iPadY[PAD_BOTTOM_RIGHT] = 0; } } /* *---------------------------------------------------------------------- * * Layout_Size -- * * Calculate the height and width of a style after all the * elements have been arranged. * * Results: * The height and width of the style. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Layout_Size( int vertical, /* TRUE if elements are arranged from top * to bottom. */ int numLayouts, /* Number of layout records. */ struct Layout layouts[], /* Initialized layout records. */ int *widthPtr, /* Returned width. */ int *heightPtr /* Returned height. */ ) { int i, W, N, E, S; int width = 0, height = 0; W = 1000000, N = 1000000, E = -1000000, S = -1000000; for (i = 0; i < numLayouts; i++) { struct Layout *layout = &layouts[i]; int w, n, e, s; int *ePadX, *iPadX, *uPadX, *ePadY, *iPadY, *uPadY; if (IS_HIDDEN(layout)) continue; ePadX = layout->ePadX, iPadX = layout->iPadX, uPadX = layout->uPadX; ePadY = layout->ePadY, iPadY = layout->iPadY, uPadY = layout->uPadY; w = layout->x + ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT]); n = layout->y + ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT]); e = layout->x + layout->eWidth - ePadX[PAD_BOTTOM_RIGHT] + MAX(ePadX[PAD_BOTTOM_RIGHT], uPadX[PAD_BOTTOM_RIGHT]); s = layout->y + layout->eHeight - ePadY[PAD_BOTTOM_RIGHT] + MAX(ePadY[PAD_BOTTOM_RIGHT], uPadY[PAD_BOTTOM_RIGHT]); if (vertical) { N = MIN(N, n); S = MAX(S, s); width = MAX(width, e - w); } else { W = MIN(W, w); E = MAX(E, e); height = MAX(height, s - n); } } if (vertical) height = MAX(height, S - N); else width = MAX(width, E - W); (*widthPtr) = width; (*heightPtr) = height; } /* *---------------------------------------------------------------------- * * Style_DoLayoutNeededV -- * * Calculate the vertical size and position of each element. * This is similar to Style_DoLayoutV but without expansion or * squeezing. Also, the size and position of -union elements * is not calculated. * * Results: * layouts[] is updated. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Style_DoLayoutNeededV( StyleDrawArgs *drawArgs, /* Various args. */ struct Layout layouts[] /* Array of layout records to be updated, * one per element. Should be initialized * by Style_DoLayoutH(). */ ) { IStyle *style = (IStyle *) drawArgs->style; MStyle *masterStyle = style->master; MElementLink *eLinks1, *eLink1; IElementLink *eLinks2, *eLink2; int *ePadY, *iPadY, *uPadY; int i; int y = 0; eLinks1 = masterStyle->elements; eLinks2 = style->elements; /* Layout elements left-to-right, or top-to-bottom */ for (i = 0; i < masterStyle->numElements; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; eLink2 = &eLinks2[i]; /* The size of a -union element is determined by the elements * it surrounds */ if (IS_UNION(eLink1)) { /* I don't need good values because I'm only calculating the * needed height */ layout->y = layout->iHeight = layout->eHeight = 0; continue; } /* -detach elements are positioned by themselves */ if (IS_DETACH(eLink1)) continue; ePadY = layout->ePadY; iPadY = layout->iPadY; uPadY = layout->uPadY; layout->y = y + abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; if (masterStyle->vertical) y = layout->y + layout->eHeight; } /* -detach elements */ for (i = 0; i < masterStyle->numElements; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; eLink2 = &eLinks2[i]; if (!IS_DETACH(eLink1) || IS_UNION(eLink1)) continue; ePadY = layout->ePadY; iPadY = layout->iPadY; uPadY = layout->uPadY; layout->y = abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; } } /* *---------------------------------------------------------------------- * * Style_DoLayout -- * * Calculate the size and position of each element. * * Results: * layouts[] is updated. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* Arrange all the Elements considering drawArgs.width and maybe drawArgs.height */ static void Style_DoLayout( StyleDrawArgs *drawArgs, /* Various args. */ struct Layout layouts[], /* Uninitialized records to be filled in. */ int neededV, /* TRUE if drawArgs.height should be ignored. */ char *file, /* debug */ int line /* debug */ ) { TreeCtrl *tree = drawArgs->tree; IStyle *style = (IStyle *) drawArgs->style; MStyle *masterStyle = style->master; int state = drawArgs->state; int i; if (style->neededWidth == -1) panic("Style_DoLayout(file %s line %d): style.neededWidth == -1", file, line); #ifdef CACHE_STYLE_STYLE if (style->minWidth + drawArgs->indent > drawArgs->width) panic("Style_DoLayout(file %s line %d): style.minWidth + drawArgs->indent %d > drawArgs.width %d", file, line, style->minWidth + drawArgs->indent, drawArgs->width); #endif Style_DoLayoutH(drawArgs, layouts); for (i = 0; i < masterStyle->numElements; i++) { struct Layout *layout = &layouts[i]; MElementLink *eLink1 = layout->master; IElementLink *eLink2 = layout->eLink; TreeElementArgs args; if (IS_HIDDEN(layout)) continue; /* The size of a -union element is determined by the elements * it surrounds */ if (IS_UNION(eLink1)) { layout->useHeight = 0; continue; } #ifdef CACHE_ELEM_SIZE layout->useHeight = eLink2->neededHeight; #else layout->useHeight = layout->neededHeight; #endif /* If a Text Element is given less width than it needs (due to * -squeeze x layout), then it may wrap lines. This means * the height can vary depending on the width. */ if (eLink2->elem->typePtr->heightProc == NULL) continue; if (eLink1->fixedHeight >= 0) continue; #ifdef CACHE_ELEM_SIZE /* Not squeezed */ if (layout->useWidth >= eLink2->neededWidth) continue; /* Already calculated the height at this width */ if (layout->useWidth == eLink2->layoutWidth) { layout->useHeight = eLink2->layoutHeight; continue; } #else /* Not squeezed */ if (layout->useWidth >= layout->neededWidth) continue; #endif args.tree = tree; args.state = state; args.elem = eLink2->elem; args.height.fixedWidth = layout->useWidth; (*args.elem->typePtr->heightProc)(&args); if (eLink1->fixedHeight >= 0) layout->useHeight = eLink1->fixedHeight; else if ((eLink1->minHeight >= 0) && (args.height.height < eLink1->minHeight)) layout->useHeight = eLink1->minHeight; else if ((eLink1->maxHeight >= 0) && (args.height.height > eLink1->maxHeight)) layout->useHeight = eLink1->maxHeight; else layout->useHeight = args.height.height; #ifdef CACHE_ELEM_SIZE eLink2->layoutWidth = layout->useWidth; eLink2->layoutHeight = layout->useHeight; #endif } if (neededV) { Style_DoLayoutNeededV(drawArgs, layouts); } else { Style_DoLayoutV(drawArgs, layouts); } } /* *---------------------------------------------------------------------- * * Style_NeededSize -- * * Calculate the width and height of a style based only on * the requested size of each element. * * Results: * The width and height. The minimum width and height is equal to * the requested width and height minus any squeezing. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Style_NeededSize( TreeCtrl *tree, /* Widget info. */ IStyle *style, /* Style to calculate size of. */ int state, /* STATE_xxx flags. */ int *widthPtr, /* Returned width. */ int *heightPtr, /* Returned height. */ int *minWidthPtr, /* Returned minimum width. */ int *minHeightPtr /* Returned minimum height. */ ) { MStyle *masterStyle = style->master; MElementLink *eLinks1, *eLink1; IElementLink *eLinks2, *eLink2; struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; int *ePadX, *iPadX, *uPadX, *ePadY, *iPadY, *uPadY; int i, j, eLinkCount = masterStyle->numElements; int x = 0, y = 0; int squeezeX = 0, squeezeY = 0; int headerHeight = 0; STATIC_ALLOC(layouts, struct Layout, eLinkCount); eLinks1 = masterStyle->elements; eLinks2 = style->elements; for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; layout->unionParent = 0; layout->temp = 0; /* see Layout_CalcVisibility */ } for (i = 0; i < eLinkCount; i++) { Layout_CalcVisibility(tree, state, masterStyle, layouts, i); } for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; eLink1 = &eLinks1[i]; eLink2 = &eLinks2[i]; if (IS_HIDDEN(layout)) continue; if (IS_UNION(eLink1)) { for (j = 0; j < eLink1->onionCount; j++) { struct Layout *layout2 = &layouts[eLink1->onion[j]]; if (!IS_HIDDEN(layout2)) layout2->unionParent = 1; } } layout->master = eLink1; layout->eLink = eLink2; if (!IS_UNION(eLink1)) { #ifdef CACHE_ELEM_SIZE if ((eLink2->neededWidth == -1) || (eLink2->neededHeight == -1)) { Element_NeededSize(tree, eLink1, eLink2->elem, state, &eLink2->neededWidth, &eLink2->neededHeight); eLink2->layoutWidth = -1; } layout->useWidth = eLink2->neededWidth; layout->useHeight = eLink2->neededHeight; #else Element_NeededSize(tree, eLink1, eLink2->elem, state, &layout->neededWidth, &layout->neededHeight); layout->useWidth = layout->neededWidth; #endif } for (j = 0; j < 2; j++) { layout->ePadX[j] = eLink1->ePadX[j]; layout->ePadY[j] = eLink1->ePadY[j]; layout->iPadX[j] = eLink1->iPadX[j]; layout->iPadY[j] = eLink1->iPadY[j]; /* No -union padding yet */ layout->uPadX[j] = 0; layout->uPadY[j] = 0; } TreeElement_GetContentMargins(tree, layout->eLink->elem, state, layout->eMargins, layout->uMargins, &layout->arrowHeight); if (IS_UNION(eLink1)) { headerHeight = MAX(headerHeight, layout->eMargins[1] + layout->arrowHeight + layout->eMargins[3]); } } /* Calculate the padding around elements surrounded by -union elements */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int padx[2], pady[2]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; /* Start at the top level of each -union heirarchy. */ if (!IS_UNION(eLink1) || layout->unionParent) continue; ePadX = layout->ePadX; ePadY = layout->ePadY; iPadX = layout->iPadX; iPadY = layout->iPadY; for (j = 0; j < 2; j++) { padx[j] = ePadX[j] + iPadX[j] + layout->uMargins[j*2]; pady[j] = ePadY[j] + iPadY[j] + layout->uMargins[j*2+1]; } for (j = 0; j < eLink1->onionCount; j++) { struct Layout *layout2 = &layouts[eLink1->onion[j]]; if (IS_HIDDEN(layout2)) continue; Layout_AddUnionPadding(tree, masterStyle, layouts, i, eLink1->onion[j], padx, pady ); } } /* Layout elements left-to-right, or top-to-bottom */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; eLink2 = &eLinks2[i]; /* The size of a -union element is determined by the elements * it surrounds */ if (IS_UNION(eLink1)) { layout->x = layout->y = layout->eWidth = layout->eHeight = 0; for (j = 0; j < 2; j++) { layout->ePadX[j] = 0; layout->ePadY[j] = 0; layout->iPadX[j] = 0; layout->iPadY[j] = 0; layout->uPadX[j] = 0; layout->uPadY[j] = 0; } continue; } if (eLink1->flags & ELF_SQUEEZE_X) squeezeX++; if (eLink1->flags & ELF_SQUEEZE_Y) squeezeY++; /* -detach elements are positioned by themselves */ if (IS_DETACH(eLink1)) continue; ePadX = layout->ePadX; ePadY = layout->ePadY; iPadX = layout->iPadX; iPadY = layout->iPadY; uPadX = layout->uPadX; uPadY = layout->uPadY; layout->x = x + abs(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT])); layout->y = y + abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT]; layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT]; layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; if (masterStyle->vertical) y = layout->y + layout->eHeight; else x = layout->x + layout->eWidth; } /* -detach elements */ for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; eLink2 = &eLinks2[i]; if (!IS_DETACH(eLink1) || IS_UNION(eLink1)) continue; ePadX = layout->ePadX; ePadY = layout->ePadY; iPadX = layout->iPadX; iPadY = layout->iPadY; uPadX = layout->uPadX; uPadY = layout->uPadY; layout->x = abs(ePadX[PAD_TOP_LEFT] - MAX(ePadX[PAD_TOP_LEFT], uPadX[PAD_TOP_LEFT])); layout->y = abs(ePadY[PAD_TOP_LEFT] - MAX(ePadY[PAD_TOP_LEFT], uPadY[PAD_TOP_LEFT])); layout->iWidth = iPadX[PAD_TOP_LEFT] + layout->useWidth + iPadX[PAD_BOTTOM_RIGHT]; layout->iHeight = iPadY[PAD_TOP_LEFT] + layout->useHeight + iPadY[PAD_BOTTOM_RIGHT]; layout->eWidth = ePadX[PAD_TOP_LEFT] + layout->iWidth + ePadX[PAD_BOTTOM_RIGHT]; layout->eHeight = ePadY[PAD_TOP_LEFT] + layout->iHeight + ePadY[PAD_BOTTOM_RIGHT]; } Layout_Size(masterStyle->vertical, eLinkCount, layouts, widthPtr, heightPtr); /* the height of a header was: content margin top + MAX(text pady top + height + pady bottom, image pady top + height + pady bottom, arrow pady top + height + pady bottom) + content margin bottom */ *heightPtr = MAX(*heightPtr, headerHeight); if (squeezeX || squeezeY) { for (i = 0; i < eLinkCount; i++) { struct Layout *layout = &layouts[i]; int subtract; if (IS_HIDDEN(layout)) continue; eLink1 = &eLinks1[i]; if (IS_UNION(eLink1)) continue; if (eLink1->flags & ELF_SQUEEZE_X) { if ((eLink1->minWidth >= 0) && (eLink1->minWidth <= layout->useWidth)) { subtract = layout->useWidth - eLink1->minWidth; } else { subtract = layout->useWidth; } layout->eWidth -= subtract; if (!masterStyle->vertical && !IS_DETACH(eLink1)) { for (j = i + 1; j < eLinkCount; j++) if (!IS_HIDDEN(&layouts[j]) && !DETACH_OR_UNION(&eLinks1[j])) layouts[j].x -= subtract; } } if (eLink1->flags & ELF_SQUEEZE_Y) { if ((eLink1->minHeight >= 0) && (eLink1->minHeight <= layout->useHeight)) { subtract = layout->useHeight - eLink1->minHeight; } else { subtract = layout->useHeight; } layout->eHeight -= subtract; if (masterStyle->vertical && !IS_DETACH(eLink1)) { for (j = i + 1; j < eLinkCount; j++) if (!IS_HIDDEN(&layouts[j]) && !DETACH_OR_UNION(&eLinks1[j])) layouts[j].y -= subtract; } } } Layout_Size(masterStyle->vertical, eLinkCount, layouts, minWidthPtr, minHeightPtr); } else { *minWidthPtr = *widthPtr; *minHeightPtr = *heightPtr; } STATIC_FREE(layouts, struct Layout, eLinkCount); } /* *---------------------------------------------------------------------- * * Style_CheckNeededSize -- * * If the style's requested size is out-of-date then recalculate * Style.neededWidth, Style.neededHeight, Style.minWidth, and * Style.minHeight. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void Style_CheckNeededSize( TreeCtrl *tree, /* Widget info. */ IStyle *style, /* Style info. */ int state /* STATE_xxx flags. */ ) { if (style->neededWidth == -1) { int minWidth, minHeight; Style_NeededSize(tree, style, state, &style->neededWidth, &style->neededHeight, &minWidth, &minHeight); #ifdef CACHE_STYLE_SIZE style->minWidth = minWidth; style->minHeight = minHeight; style->layoutWidth = -1; #endif /* CACHE_STYLE_SIZE */ #ifdef TREECTRL_DEBUG style->neededState = state; #endif } #ifdef TREECTRL_DEBUG if (style->neededState != state) panic("Style_CheckNeededSize: neededState %d != state %d\n", style->neededState, state); #endif } #ifndef CACHE_STYLE_SIZE static void Style_MinSize( TreeCtrl *tree, /* Widget info. */ IStyle *style, /* Style info. */ int state, /* STATE_xxx flags. */ int *minWidthPtr, int *minHeightPtr ) { int i, hasSqueeze = FALSE; for (i = 0; i < style->master->numElements; i++) { MElementLink *eLink1 = &style->master->elements[i]; if (!IS_UNION(eLink1) && (eLink1->flags & (ELF_SQUEEZE_X | ELF_SQUEEZE_Y))) { hasSqueeze = TRUE; break; } } if (hasSqueeze) { int width, height; Style_NeededSize(tree, style, state, &width, &height, minWidthPtr, minHeightPtr); } else { *minWidthPtr = style->neededWidth; *minHeightPtr = style->neededHeight; } } #endif /* !CACHE_STYLE_SIZE */ /* *---------------------------------------------------------------------- * * TreeStyle_NeededWidth -- * * Return the requested width of a style. * * Results: * The requested width. If the requested size is out-of-date * then it is recalculated. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_NeededWidth( TreeCtrl *tree, /* Widget info. */ TreeStyle style_, /* Style token. */ int state /* STATE_xxx flags. */ ) { IStyle *style = (IStyle *) style_; Style_CheckNeededSize(tree, style, state); return style->neededWidth; } /* *---------------------------------------------------------------------- * * TreeStyle_NeededHeight -- * * Return the requested height of a style. * * Results: * The requested height. If the requested size is out-of-date * then it is recalculated. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_NeededHeight( TreeCtrl *tree, /* Widget info. */ TreeStyle style_, /* Style token. */ int state /* STATE_xxx flags. */ ) { IStyle *style = (IStyle *) style_; Style_CheckNeededSize(tree, style, state); return style->neededHeight; } /* *---------------------------------------------------------------------- * * TreeStyle_UseHeight -- * * Return the height of a style for a given state and width. * * Results: * The height of the style. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_UseHeight( StyleDrawArgs *drawArgs /* Various args. */ ) { TreeCtrl *tree = drawArgs->tree; IStyle *style = (IStyle *) drawArgs->style; MStyle *masterStyle = style->master; int state = drawArgs->state; struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; int width, height, minWidth; #ifndef CACHE_STYLE_SIZE int minHeight; #endif Style_CheckNeededSize(tree, style, state); #ifdef CACHE_STYLE_SIZE minWidth = style->minWidth; #else if (drawArgs->width < style->neededWidth + drawArgs->indent) Style_MinSize(tree, style, state, &minWidth, &minHeight); else minWidth = style->neededWidth; #endif /* * If we have: * a) infinite space available, or * b) more width than the style needs, or * c) less width than the style needs, but it has no -squeeze x elements * then return the needed height of the style. This is safe since no * text elements will be growing vertically when lines wrap. */ if ((drawArgs->width == -1) || (drawArgs->width >= style->neededWidth + drawArgs->indent) || (style->neededWidth == minWidth)) { return style->neededHeight; } /* We never lay out the style at less than the minimum width */ if (drawArgs->width < minWidth + drawArgs->indent) drawArgs->width = minWidth + drawArgs->indent; #ifdef CACHE_STYLE_SIZE /* We have less space than the style needs, and have already calculated * the height of the style at this width. (The height may change because * of text elements wrapping lines). */ if (drawArgs->width == style->layoutWidth) return style->layoutHeight; #endif STATIC_ALLOC(layouts, struct Layout, masterStyle->numElements); Style_DoLayout(drawArgs, layouts, TRUE, __FILE__, __LINE__); Layout_Size(style->master->vertical, masterStyle->numElements, layouts, &width, &height); STATIC_FREE(layouts, struct Layout, masterStyle->numElements); #ifdef CACHE_STYLE_SIZE style->layoutWidth = drawArgs->width; style->layoutHeight = height; #endif return height; } /* *---------------------------------------------------------------------- * * TreeStyle_Draw -- * * Draw all the elements in a style. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void TreeStyle_Draw( StyleDrawArgs *drawArgs /* Various args. */ ) { IStyle *style = (IStyle *) drawArgs->style; MStyle *masterStyle = style->master; TreeCtrl *tree = drawArgs->tree; TreeRectangle bounds; TreeElementArgs args; int i, j, x, y, minWidth, minHeight; struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; #undef DEBUG_DRAW #ifdef DEBUG_DRAW int debugDraw = TRUE; #endif Style_CheckNeededSize(tree, style, drawArgs->state); #ifdef CACHE_STYLE_SIZE minWidth = style->minWidth; minHeight = style->minHeight; #else if ((drawArgs->width < style->neededWidth + drawArgs->indent) || (drawArgs->height < style->neededHeight)) { Style_MinSize(tree, style, drawArgs->state, &minWidth, &minHeight); } else { minWidth = style->neededWidth; minHeight = style->neededHeight; } #endif /* Get the bounds allowed for drawing (in window coordinates), inside * the item-column(s) and inside the header/borders. */ x = drawArgs->x + tree->drawableXOrigin - tree->xOrigin; y = drawArgs->y + tree->drawableYOrigin - tree->yOrigin; TreeRect_SetXYWH(bounds, x, y, drawArgs->width, drawArgs->height); TreeRect_Intersect(&args.display.bounds, &bounds, &drawArgs->bounds); TreeRect_SetXYWH(args.display.spanBbox, drawArgs->x, drawArgs->y, drawArgs->width, drawArgs->height); /* We never lay out the style at less than the minimum size */ if (drawArgs->width < minWidth + drawArgs->indent) drawArgs->width = minWidth + drawArgs->indent; if (drawArgs->height < minHeight) drawArgs->height = minHeight; STATIC_ALLOC(layouts, struct Layout, masterStyle->numElements); Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__); args.tree = tree; args.state = drawArgs->state; args.display.td = drawArgs->td; args.display.drawable = drawArgs->td.drawable; args.display.column = drawArgs->column; /* needed for gradients */ args.display.item = drawArgs->item; /* needed for gradients */ args.display.spanIndex = drawArgs->spanIndex; args.display.indent = drawArgs->indent; for (i = 0; i < masterStyle->numElements; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; /* Don't "draw" window elements. TreeStyle_UpdateWindowPositions() * does that for us. */ if (ELEMENT_TYPE_MATCHES(layout->eLink->elem->typePtr, &treeElemTypeWindow)) continue; if (PerStateBoolean_ForState(tree, &layout->master->draw, drawArgs->state, NULL) == 0) continue; #ifdef DEBUG_DRAW if (debugDraw && layout->master->onion != NULL) continue; #endif if ((layout->useWidth > 0) && (layout->useHeight > 0)) { args.elem = layout->eLink->elem; args.display.x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT]; args.display.y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT]; args.display.x += layout->iPadX[PAD_TOP_LEFT]; args.display.y += layout->iPadY[PAD_TOP_LEFT]; args.display.width = layout->useWidth; args.display.height = layout->useHeight; args.display.sticky = layout->master->flags & ELF_STICKY; /* This is used by the header element to adjust the arrow position * according to -arrowgravity. */ for (j = 0; j < 4; j++) { args.display.eUnionBbox[j] = layout->eUnionBbox[j]; args.display.iUnionBbox[j] = layout->iUnionBbox[j]; } #ifdef DEBUG_DRAW if (debugDraw) { XColor *color[3]; GC gc[3]; if (layout->master->onion != NULL) { color[0] = Tk_GetColor(tree->interp, tree->tkwin, "blue2"); gc[0] = Tk_GCForColor(color[0], Tk_WindowId(tree->tkwin)); color[1] = Tk_GetColor(tree->interp, tree->tkwin, "blue3"); gc[1] = Tk_GCForColor(color[1], Tk_WindowId(tree->tkwin)); } else { color[0] = Tk_GetColor(tree->interp, tree->tkwin, "gray50"); gc[0] = Tk_GCForColor(color[0], Tk_WindowId(tree->tkwin)); color[1] = Tk_GetColor(tree->interp, tree->tkwin, "gray60"); gc[1] = Tk_GCForColor(color[1], Tk_WindowId(tree->tkwin)); color[2] = Tk_GetColor(tree->interp, tree->tkwin, "gray70"); gc[2] = Tk_GCForColor(color[2], Tk_WindowId(args.tree->tkwin)); } /* external */ XFillRectangle(tree->display, args.display.drawable, gc[2], args.display.x - layout->ePadX[PAD_TOP_LEFT], args.display.y - layout->ePadY[PAD_TOP_LEFT], layout->eWidth, layout->eHeight); /* internal */ XFillRectangle(tree->display, args.display.drawable, gc[1], args.display.x, args.display.y, args.display.width, args.display.height); /* needed */ if (!layout->master->onion && !(layout->master->flags & ELF_DETACH)) XFillRectangle(tree->display, args.display.drawable, gc[0], args.display.x + layout->iPadX[PAD_TOP_LEFT], args.display.y + layout->iPadY[PAD_TOP_LEFT], layout->eLink->neededWidth, layout->eLink->neededHeight); } else #endif /* DEBUG_DRAW */ (*args.elem->typePtr->displayProc)(&args); } } #ifdef DEBUG_DRAW if (debugDraw) for (i = 0; i < masterStyle->numElements; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; if (layout->master->onion == NULL) continue; if (layout->useWidth > 0 && layout->useHeight > 0) { args.elem = layout->eLink->elem; args.display.x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT]; args.display.y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT]; args.display.width = layout->iWidth; args.display.height = layout->iHeight; { XColor *color[3]; GC gc[3]; color[0] = Tk_GetColor(tree->interp, tree->tkwin, "blue2"); gc[0] = Tk_GCForColor(color[0], Tk_WindowId(tree->tkwin)); color[1] = Tk_GetColor(tree->interp, tree->tkwin, "blue3"); gc[1] = Tk_GCForColor(color[1], Tk_WindowId(tree->tkwin)); /* external */ XDrawRectangle(tree->display, args.display.drawable, gc[0], args.display.x - layout->ePadX[PAD_TOP_LEFT], args.display.y - layout->ePadY[PAD_TOP_LEFT], layout->eWidth - 1, layout->eHeight - 1); /* internal */ XDrawRectangle(tree->display, args.display.drawable, gc[1], args.display.x, args.display.y, args.display.width - 1, args.display.height - 1); } } } #endif /* DEBUG_DRAW */ STATIC_FREE(layouts, struct Layout, masterStyle->numElements); } /* *---------------------------------------------------------------------- * * TreeStyle_UpdateWindowPositions -- * * Call the displayProc on each window element so it can update * its geometry. This is needed if an item was scrolled and its * displayProc wasn't otherwise called. * * Results: * None. * * Side effects: * Possible window geometry changes. * *---------------------------------------------------------------------- */ void TreeStyle_UpdateWindowPositions( StyleDrawArgs *drawArgs /* Various args. */ ) { IStyle *style = (IStyle *) drawArgs->style; MStyle *masterStyle = style->master; TreeCtrl *tree = drawArgs->tree; TreeRectangle bounds; TreeElementArgs args; int i, x, y, minWidth, minHeight; struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; int numElements = masterStyle->numElements; if (!masterStyle->hasWindowElem) return; Style_CheckNeededSize(tree, style, drawArgs->state); #ifdef CACHE_STYLE_SIZE minWidth = style->minWidth; minHeight = style->minHeight; #else if ((drawArgs->width < style->neededWidth + drawArgs->indent) || (drawArgs->height < style->neededHeight)) { Style_MinSize(tree, style, drawArgs->state, &minWidth, &minHeight); } else { minWidth = style->neededWidth; minHeight = style->neededHeight; } #endif /* Get the bounds allowed for drawing (in window coordinates), inside * the item-column(s) and inside the header/borders. */ x = drawArgs->x + tree->drawableXOrigin - tree->xOrigin; y = drawArgs->y + tree->drawableYOrigin - tree->yOrigin; TreeRect_SetXYWH(bounds, x, y, drawArgs->width, drawArgs->height); TreeRect_Intersect(&args.display.bounds, &bounds, &drawArgs->bounds); /* We never lay out the style at less than the minimum size */ if (drawArgs->width < minWidth + drawArgs->indent) drawArgs->width = minWidth + drawArgs->indent; if (drawArgs->height < minHeight) drawArgs->height = minHeight; STATIC_ALLOC(layouts, struct Layout, numElements); Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__); args.tree = tree; args.state = drawArgs->state; args.display.td = drawArgs->td; args.display.drawable = drawArgs->td.drawable; for (i = 0; i < numElements; i++) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; if (!ELEMENT_TYPE_MATCHES(layout->eLink->elem->typePtr, &treeElemTypeWindow)) continue; if (PerStateBoolean_ForState(tree, &layout->master->draw, drawArgs->state, NULL) == 0) continue; if ((layout->useWidth > 0) && (layout->useHeight > 0)) { int requests; TreeDisplay_GetReadyForTrouble(tree, &requests); args.elem = layout->eLink->elem; args.display.x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT]; args.display.y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT]; args.display.x += layout->iPadX[PAD_TOP_LEFT]; args.display.y += layout->iPadY[PAD_TOP_LEFT]; args.display.width = layout->useWidth; args.display.height = layout->useHeight; args.display.sticky = layout->master->flags & ELF_STICKY; (*args.elem->typePtr->displayProc)(&args); /* Updating the position of a window may generate a * or event on that window. Binding scripts on those * events could do anything, including deleting items and * thus the style we are drawing. In other cases (such as when * using Tile widgets I notice), the Tk_GeomMgr.requestProc * may get called which calls Tree_ElementChangedItself which * calls FreeDItemInfo which frees a DItem we are in the middle * of displaying. So if anything was done that caused a display * request, then abort abort abort. */ if (TreeDisplay_WasThereTrouble(tree, requests)) break; } } STATIC_FREE(layouts, struct Layout, numElements); } /* *---------------------------------------------------------------------- * * TreeStyle_OnScreen -- * * Call the onScreenProc (if non-NULL) on each element so it can * update its visibility when an item's visibility changes. * * Results: * None. * * Side effects: * Possible window visibility changes. * *---------------------------------------------------------------------- */ void TreeStyle_OnScreen( TreeCtrl *tree, /* Widget info. */ TreeStyle style_, /* Style token. */ int onScreen /* Boolean indicating whether the item * using the style is on screen anymore. */ ) { IStyle *style = (IStyle *) style_; TreeElementArgs args; int i; args.tree = tree; args.screen.visible = onScreen; for (i = 0; i < style->master->numElements; i++) { IElementLink *eLink = &style->elements[i]; if (eLink->elem->typePtr->onScreenProc == NULL) continue; args.elem = eLink->elem; (*args.elem->typePtr->onScreenProc)(&args); } } /* *---------------------------------------------------------------------- * * Element_FreeResources -- * * Free memory etc associated with an Element. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ static void Element_FreeResources( TreeCtrl *tree, /* Widget info. */ TreeElement elem /* Record to free. */ ) { TreeElementType *typePtr = elem->typePtr; TreeElementArgs args; Tcl_HashEntry *hPtr; if (elem->master == NULL) { hPtr = Tcl_FindHashEntry(&tree->elementHash, elem->name); Tcl_DeleteHashEntry(hPtr); } args.tree = tree; args.elem = elem; (*typePtr->deleteProc)(&args); Tk_FreeConfigOptions((char *) elem, typePtr->optionTable, tree->tkwin); DynamicOption_Free(tree, elem->options, typePtr->optionSpecs); #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, typePtr->name, (char *) elem, typePtr->size); #else WFREE(elem, TreeElement_); #endif } /* *---------------------------------------------------------------------- * * MElementLink_Init -- * * Initialize (don't allocate) a MElementLink. * * Results: * eLink is filled with default values. * * Side effects: * None. * *---------------------------------------------------------------------- */ static MElementLink * MElementLink_Init( MElementLink *eLink, /* Existing record to initialize. */ TreeElement elem /* Existing element to point to. */ ) { memset(eLink, '\0', sizeof(MElementLink)); eLink->elem = elem; eLink->flags |= ELF_INDENT; eLink->minWidth = eLink->fixedWidth = eLink->maxWidth = -1; eLink->minHeight = eLink->fixedHeight = eLink->maxHeight = -1; eLink->flags |= ELF_STICKY; return eLink; } /* *---------------------------------------------------------------------- * * MElementLink_FreeResources -- * * Free memory etc associated with an MElementLink. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ static void MElementLink_FreeResources( TreeCtrl *tree, /* Widget info. */ MElementLink *eLink /* Record to free. */ ) { if (eLink->onion != NULL) WCFREE(eLink->onion, int, eLink->onionCount); PerStateInfo_Free(tree, &pstBoolean, &eLink->draw); if (eLink->draw.obj != NULL) { Tcl_DecrRefCount(eLink->draw.obj); } PerStateInfo_Free(tree, &pstBoolean, &eLink->visible); if (eLink->visible.obj != NULL) { Tcl_DecrRefCount(eLink->visible.obj); } } /* *---------------------------------------------------------------------- * * IElementLink_FreeResources -- * * Free memory etc associated with an ElementLink. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ static void IElementLink_FreeResources( TreeCtrl *tree, /* Widget info. */ IElementLink *eLink /* Record to free. */ ) { if (eLink->elem->master != NULL) Element_FreeResources(tree, eLink->elem); } /* *---------------------------------------------------------------------- * * MStyle_FreeResources -- * * Free memory etc associated with a Style. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ static void MStyle_FreeResources( TreeCtrl *tree, /* Widget info. */ MStyle *style /* Style to free. */ ) { Tcl_HashEntry *hPtr; int i; hPtr = Tcl_FindHashEntry(&tree->styleHash, style->name); Tcl_DeleteHashEntry(hPtr); if (style->numElements > 0) { for (i = 0; i < style->numElements; i++) MElementLink_FreeResources(tree, &style->elements[i]); #ifdef ALLOC_HAX TreeAlloc_CFree(tree->allocData, MElementLinkUid, (char *) style->elements, sizeof(MElementLink), style->numElements, ELEMENT_LINK_ROUND); #else WCFREE(style->elements, MElementLink, style->numElements); #endif } #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, MStyleUid, (char *) style, sizeof(MStyle)); #else WFREE(style, MStyle); #endif } /* *---------------------------------------------------------------------- * * IStyle_FreeResources -- * * Free memory etc associated with a Style. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ static void IStyle_FreeResources( TreeCtrl *tree, /* Widget info. */ IStyle *style /* Style to free. */ ) { MStyle *masterStyle = style->master; int i; if (masterStyle->numElements > 0) { for (i = 0; i < masterStyle->numElements; i++) IElementLink_FreeResources(tree, &style->elements[i]); #ifdef ALLOC_HAX TreeAlloc_CFree(tree->allocData, IElementLinkUid, (char *) style->elements, sizeof(IElementLink), masterStyle->numElements, ELEMENT_LINK_ROUND); #else WCFREE(style->elements, IElementLink, masterStyle->numElements); #endif } #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, IStyleUid, (char *) style, sizeof(IStyle)); #else WFREE(style, IStyle); #endif } /* *---------------------------------------------------------------------- * * TreeStyle_FreeResources -- * * Free memory etc associated with a Style. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ void TreeStyle_FreeResources( TreeCtrl *tree, /* Widget info. */ TreeStyle style_ /* Token of style to free. */ ) { MStyle *masterStyle = (MStyle *) style_; IStyle *style = (IStyle *) style_; if (style->master == NULL) MStyle_FreeResources(tree, masterStyle); else IStyle_FreeResources(tree, style); } /* *---------------------------------------------------------------------- * * MStyle_FindElem -- * * Find an ElementLink in a style. * * Results: * If found, a pointer to the ElementLink and index in the * style's array of ElementLinks is returned; otherwise NULL * is returned. * * Side effects: * World peace. * *---------------------------------------------------------------------- */ static MElementLink * MStyle_FindElem( TreeCtrl *tree, /* Widget info. */ MStyle *style, /* Style to search. */ TreeElement master, /* Master element to find. */ int *index /* Returned index, may be NULL. */ ) { int i; for (i = 0; i < style->numElements; i++) { MElementLink *eLink = &style->elements[i]; if (eLink->elem->name == master->name) { if (index != NULL) (*index) = i; return eLink; } } return NULL; } /* *---------------------------------------------------------------------- * * IStyle_FindElem -- * * Find an ElementLink in a style. * * Results: * If found, a pointer to the ElementLink and index in the * style's array of ElementLinks is returned; otherwise NULL * is returned. * * Side effects: * World peace. * *---------------------------------------------------------------------- */ static IElementLink * IStyle_FindElem( TreeCtrl *tree, /* Widget info. */ IStyle *style, /* Style to search. */ TreeElement master, /* Master element to find. */ int *index /* Returned index, may be NULL. */ ) { MStyle *masterStyle = style->master; int i; for (i = 0; i < masterStyle->numElements; i++) { IElementLink *eLink = &style->elements[i]; if (eLink->elem->name == master->name) { if (index != NULL) (*index) = i; return eLink; } } return NULL; } /* *---------------------------------------------------------------------- * * TreeStyle_FindElement -- * * Find an ElementLink in a style. * * Results: * If found, the index in the style's array of ElementLinks is * returned with TCL_OK. Otherwise TCL_ERROR is returned and an * error message is placed in the interpreter result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_FindElement( TreeCtrl *tree, /* Widget info. */ TreeStyle style_, /* Token of style to search. */ TreeElement elem, /* Master element to find. */ int *index /* Returned index, may be NULL. */ ) { MStyle *masterStyle = (MStyle *) style_; IStyle *style = (IStyle *) style_; if (((style->master == NULL) && (MStyle_FindElem(tree, masterStyle, elem, index) == NULL)) || ((style->master != NULL) && (IStyle_FindElem(tree, style, elem, index) == NULL))) { FormatResult(tree->interp, "style %s does not use element %s", style->master ? style->master->name : masterStyle->name, elem->name); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Element_CreateAndConfig -- * * Allocate and initialize a new Element (master or instance). * * Results: * An Element is allocated, its createProc is called, default * configuration options are set, then the configProc and changeProc * are called to handle any given configurations options. If an * error occurs NULL is returned. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ static TreeElement Element_CreateAndConfig( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the element. Should * be NULL for a master element. */ TreeItemColumn column, /* Item-column containing the element. * Should be NULL for a master element. */ TreeElement masterElem, /* Master element if creating an instance. */ TreeElementType *type, /* Element type. Should be NULL when * creating an instance. */ CONST char *name, /* Name of master element, NULL for an * instance. */ int objc, /* Array of intialial configuration. */ Tcl_Obj *CONST objv[] /* options. */ ) { TreeElement elem; TreeElementArgs args; Tcl_Obj *staticObjV[STATIC_SIZE], **objV = staticObjV; int i, objC = 0, domain = STATE_DOMAIN_ITEM; STATIC_ALLOC(objV, Tcl_Obj *, objc); /* Filter out -statedomain and its value. */ /* FIXME: there is no way to query this. */ for (i = 0; i < objc; i += 2) { int length; CONST char *s = Tcl_GetStringFromObj(objv[i], &length); if (strncmp(s, "-statedomain", length) == 0) { if (i + 1 == objc) { FormatResult(tree->interp, "value for \"%s\" missing", s); STATIC_FREE(objV, Tcl_Obj *, objc); return NULL; } s = Tcl_GetStringFromObj(objv[i + 1], &length); if (strncmp(s, "header", length) == 0) domain = STATE_DOMAIN_HEADER; else if (strncmp(s, "item", length) != 0) { FormatResult(tree->interp, "unknown state domain \"%s\"", s); STATIC_FREE(objV, Tcl_Obj *, objc); return NULL; } } else { objV[objC++] = objv[i]; if (i + 1 < objc) objV[objC++] = objv[i + 1]; } } if (masterElem != NULL) { type = masterElem->typePtr; name = masterElem->name; domain = masterElem->stateDomain; } #ifdef ALLOC_HAX elem = (TreeElement) TreeAlloc_Alloc(tree->allocData, type->name, type->size); #else elem = (TreeElement) ckalloc(type->size); #endif memset(elem, '\0', type->size); elem->name = Tk_GetUid(name); elem->typePtr = type; elem->master = masterElem; elem->stateDomain = domain; args.tree = tree; args.elem = elem; args.create.item = item; args.create.column = column; if ((*type->createProc)(&args) != TCL_OK) { STATIC_FREE(objV, Tcl_Obj *, objc); #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, type->name, (char *) elem, type->size); #else WFREE(elem, TreeElement_); #endif return NULL; } if (Tk_InitOptions(tree->interp, (char *) elem, type->optionTable, tree->tkwin) != TCL_OK) { STATIC_FREE(objV, Tcl_Obj *, objc); #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, type->name, (char *) elem, type->size); #else WFREE(elem, TreeElement_); #endif return NULL; } args.config.objc = objC; args.config.objv = objV; args.config.flagSelf = 0; args.config.item = item; args.config.column = column; if ((*type->configProc)(&args) != TCL_OK) { (*type->deleteProc)(&args); STATIC_FREE(objV, Tcl_Obj *, objc); Tk_FreeConfigOptions((char *) elem, type->optionTable, tree->tkwin); DynamicOption_Free(tree, elem->options, type->optionSpecs); #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, type->name, (char *) elem, type->size); #else WFREE(elem, TreeElement_); #endif return NULL; } args.change.flagSelf = args.config.flagSelf; args.change.flagTree = 0; args.change.flagMaster = 0; (*type->changeProc)(&args); STATIC_FREE(objV, Tcl_Obj *, objc); return elem; } /* *---------------------------------------------------------------------- * * Style_CreateElem -- * * Allocate and initialize a new instance Element in a IStyle * (if it doesn't already exist) and return its associated * IElementLink. * * Results: * If the style already has a matching instance element, then a * pointer to an existing IElementLink is returned. * If the style does not already have a matching instance element, * then a new one is created and a pointer to an existing * IElementLink is returned. * If an error occurs creating the new element the result is * NULL. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ static IElementLink * Style_CreateElem( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the element. */ TreeItemColumn column, /* Item-column containing the element. */ IStyle *style, /* Style to search/add the element to. */ TreeElement masterElem, /* Element to find or create and instance of. */ int *isNew) /* If non-NULL, set to TRUE if a new instance * element was created. */ { MStyle *masterStyle = style->master; IElementLink *eLink = NULL; TreeElement elem; int i; if (masterElem->master != NULL) panic("Style_CreateElem called with instance Element"); if (isNew != NULL) (*isNew) = FALSE; for (i = 0; i < masterStyle->numElements; i++) { eLink = &style->elements[i]; if (eLink->elem == masterElem) { /* Allocate instance Element here */ break; } /* Instance Style already has instance Element */ if (eLink->elem->name == masterElem->name) return eLink; } /* Error: Element isn't in the master Style */ if (i == masterStyle->numElements) return NULL; elem = Element_CreateAndConfig(tree, item, column, masterElem, NULL, NULL, 0, NULL); if (elem == NULL) return NULL; eLink->elem = elem; if (isNew != NULL) (*isNew) = TRUE; return eLink; } /* *---------------------------------------------------------------------- * * TreeStyle_NewInstance -- * * Create and initialize a new instance of a master style. * * Results: * A new instance Style. The new array of ElementLinks is * initialized to contain pointers to master elements; instance * elements are created the first time they are configured. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ TreeStyle TreeStyle_NewInstance( TreeCtrl *tree, /* Widget info. */ TreeStyle style_ /* Master style to create instance of. */ ) { MStyle *style = (MStyle *) style_; IStyle *copy; IElementLink *eLink; int i; #ifdef ALLOC_HAX copy = (IStyle *) TreeAlloc_Alloc(tree->allocData, IStyleUid, sizeof(IStyle)); #else copy = (IStyle *) ckalloc(sizeof(IStyle)); #endif memset(copy, '\0', sizeof(IStyle)); copy->master = style; copy->neededWidth = -1; copy->neededHeight = -1; if (style->numElements > 0) { #ifdef ALLOC_HAX copy->elements = (IElementLink *) TreeAlloc_CAlloc(tree->allocData, IElementLinkUid, sizeof(IElementLink), style->numElements, ELEMENT_LINK_ROUND); #else copy->elements = (IElementLink *) ckalloc(sizeof(IElementLink) * style->numElements); #endif memset(copy->elements, '\0', sizeof(IElementLink) * style->numElements); for (i = 0; i < style->numElements; i++) { eLink = ©->elements[i]; eLink->elem = style->elements[i].elem; #ifdef CACHE_ELEM_SIZE eLink->neededWidth = -1; eLink->neededHeight = -1; #endif } } return (TreeStyle) copy; } /* *---------------------------------------------------------------------- * * TreeElement_FromObj -- * * Convert a Tcl_Obj to a master element. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeElement_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *obj, /* Object to convert from. */ TreeElement *elemPtr /* Returned master element token. */ ) { char *name; Tcl_HashEntry *hPtr; name = Tcl_GetString(obj); hPtr = Tcl_FindHashEntry(&tree->elementHash, name); if ((hPtr == NULL) || ((TreeElement) Tcl_GetHashValue(hPtr))->hidden) { Tcl_AppendResult(tree->interp, "element \"", name, "\" doesn't exist", NULL); return TCL_ERROR; } (*elemPtr) = (TreeElement) Tcl_GetHashValue(hPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeElement_IsType -- * * Determine if an element is of a certain type. * * Results: * TRUE if the type matches, otherwise FALSE. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeElement_IsType( TreeCtrl *tree, /* Widget info. */ TreeElement elem, /* Element to check. */ CONST char *type /* NULL-terminated element type name. */ ) { return strcmp(elem->typePtr->name, type) == 0; } /* *---------------------------------------------------------------------- * * TreeStyle_FromObj -- * * Convert a Tcl_Obj to a master style. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *obj, /* Object to convert from. */ TreeStyle *stylePtr) /* Returned master style token. */ { char *name; Tcl_HashEntry *hPtr; name = Tcl_GetString(obj); hPtr = Tcl_FindHashEntry(&tree->styleHash, name); if (hPtr == NULL || ((MStyle *) Tcl_GetHashValue(hPtr))->hidden) { Tcl_AppendResult(tree->interp, "style \"", name, "\" doesn't exist", NULL); return TCL_ERROR; } (*stylePtr) = (TreeStyle) Tcl_GetHashValue(hPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeElement_ToObj -- * * Create a new Tcl_Obj representing an element. * * Results: * A Tcl_Obj. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeElement_ToObj( TreeElement elem /* Element to create Tcl_Obj from. */ ) { return Tcl_NewStringObj(elem->name, -1); } /* *---------------------------------------------------------------------- * * TreeStyle_ToObj -- * * Create a new Tcl_Obj representing a style. * * Results: * A Tcl_Obj. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeStyle_ToObj( TreeStyle style_ /* Style token to create Tcl_Obj from. */ ) { MStyle *masterStyle = (MStyle *) style_; IStyle *style = (IStyle *) style_; if (style->master != NULL) masterStyle = style->master; return Tcl_NewStringObj(masterStyle->name, -1); } /* *---------------------------------------------------------------------- * * Style_Changed -- * * Called when a master style is configured or the layout of one * of its elements changes. * * Results: * For each item-column using an instance of the given master * style, size and display info is marked out-of-date. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ static void Style_Changed( TreeCtrl *tree, /* Widget info. */ MStyle *masterStyle /* Style that changed. */ ) { TreeItem item; TreeItemColumn column; TreeColumn treeColumn; Tcl_HashTable *tablePtr = &tree->itemHash; Tcl_HashEntry *hPtr; Tcl_HashSearch search; int columnIndex, layout; int updateDInfo = FALSE; IStyle *style; int tailOK; hPtr = Tcl_FirstHashEntry(tablePtr, &search); if (hPtr == NULL) { tablePtr = &tree->headerHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); tailOK = TreeItem_GetHeader(tree, item) != NULL; treeColumn = Tree_FirstColumn(tree, -1, TreeItem_GetHeader(tree, item) != NULL); column = TreeItem_GetFirstColumn(tree, item); columnIndex = 0; layout = FALSE; while (column != NULL) { style = (IStyle *) TreeItemColumn_GetStyle(tree, column); if ((style != NULL) && (style->master == masterStyle)) { #ifdef CACHE_ELEM_SIZE int i; for (i = 0; i < masterStyle->numElements; i++) { IElementLink *eLink = &style->elements[i]; /* This is needed if the -width/-height layout options change */ eLink->neededWidth = eLink->neededHeight = -1; } #endif style->neededWidth = style->neededHeight = -1; TreeColumns_InvalidateWidthOfItems(tree, treeColumn); TreeItemColumn_InvalidateSize(tree, column); layout = TRUE; } columnIndex++; column = TreeItemColumn_GetNext(tree, column); treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK); } if (layout) { TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); updateDInfo = TRUE; } hPtr = Tcl_NextHashEntry(&search); if (hPtr == NULL && tablePtr == &tree->itemHash) { tablePtr = &tree->headerHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } } if (updateDInfo) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); } /* *---------------------------------------------------------------------- * * MStyle_ChangeElementsAux -- * * Update the list of elements used by a master style. Elements * may be inserted or deleted. * * Results: * The list of elements in the style is updated. * * Side effects: * Memory may be allocated/deallocated. * *---------------------------------------------------------------------- */ static void MStyle_ChangeElementsAux( TreeCtrl *tree, /* Widget info. */ MStyle *style, /* Master style to be updated. */ int count, /* The number of elements in the style after * this routine finishes. */ TreeElement *elemList, /* List of master elements the style uses. */ int *map /* Array of indexes into the list of elements * currently used by the style. */ ) { MElementLink *eLink, *eLinks = NULL; int i, staticKeep[STATIC_SIZE], *keep = staticKeep; STATIC_ALLOC(keep, int, style->numElements); if (count > 0) { #ifdef ALLOC_HAX eLinks = (MElementLink *) TreeAlloc_CAlloc(tree->allocData, MElementLinkUid, sizeof(MElementLink), count, ELEMENT_LINK_ROUND); #else eLinks = (MElementLink *) ckalloc(sizeof(MElementLink) * count); #endif } /* Assume we are discarding all the old ElementLinks */ for (i = 0; i < style->numElements; i++) keep[i] = 0; for (i = 0; i < count; i++) { if (map[i] != -1) { eLinks[i] = style->elements[map[i]]; keep[map[i]] = 1; } else { eLink = MElementLink_Init(&eLinks[i], elemList[i]); } } if (style->numElements > 0) { /* Free unused ElementLinks */ for (i = 0; i < style->numElements; i++) { if (!keep[i]) { MElementLink_FreeResources(tree, &style->elements[i]); } } #ifdef ALLOC_HAX TreeAlloc_CFree(tree->allocData, MElementLinkUid, (char *) style->elements, sizeof(MElementLink), style->numElements, ELEMENT_LINK_ROUND); #else WCFREE(style->elements, MElementLink, style->numElements); #endif } STATIC_FREE(keep, int, style->numElements); style->elements = eLinks; style->numElements = count; /* Hack - Remember if any of the elements are of type 'header' or * 'window'. */ style->hasHeaderElem = FALSE; style->hasWindowElem = FALSE; for (i = 0; i < count; i++) { if (ELEMENT_TYPE_MATCHES(eLinks[i].elem->typePtr, &treeElemTypeHeader)) style->hasHeaderElem = TRUE; if (ELEMENT_TYPE_MATCHES(eLinks[i].elem->typePtr, &treeElemTypeWindow)) style->hasWindowElem = TRUE; } } /* *---------------------------------------------------------------------- * * IStyle_ChangeElementsAux -- * * Update the list of elements used by an instance style. Elements * may be inserted or deleted. * * Results: * The list of elements in the style is updated. * * Side effects: * Memory may be allocated/deallocated. * *---------------------------------------------------------------------- */ static void IStyle_ChangeElementsAux( TreeCtrl *tree, /* Widget info. */ IStyle *style, /* Instance style to be updated. */ int oldCount, /* The previous number of elements. */ int count, /* The number of elements in the style after * this routine finishes. */ TreeElement *elemList, /* List of master elements the style uses. */ int *map /* Array of indexes into the list of elements * currently used by the style. */ ) { IElementLink *eLink, *eLinks = NULL; int i, staticKeep[STATIC_SIZE], *keep = staticKeep; STATIC_ALLOC(keep, int, oldCount); if (count > 0) { #ifdef ALLOC_HAX eLinks = (IElementLink *) TreeAlloc_CAlloc(tree->allocData, IElementLinkUid, sizeof(IElementLink), count, ELEMENT_LINK_ROUND); #else eLinks = (IElementLink *) ckalloc(sizeof(IElementLink) * count); #endif } /* Assume we are discarding all the old ElementLinks */ for (i = 0; i < oldCount; i++) keep[i] = 0; for (i = 0; i < count; i++) { if (map[i] != -1) { eLinks[i] = style->elements[map[i]]; keep[map[i]] = 1; } else { eLink = &eLinks[i]; eLink->elem = elemList[i]; #ifdef CACHE_ELEM_SIZE eLink->neededWidth = eLink->neededHeight = -1; #endif } } if (oldCount > 0) { /* Free unused ElementLinks */ for (i = 0; i < oldCount; i++) { if (!keep[i]) { IElementLink_FreeResources(tree, &style->elements[i]); } } #ifdef ALLOC_HAX TreeAlloc_CFree(tree->allocData, IElementLinkUid, (char *) style->elements, sizeof(IElementLink), oldCount, ELEMENT_LINK_ROUND); #else WCFREE(style->elements, IElementLink, oldCount); #endif } STATIC_FREE(keep, int, oldCount); style->elements = eLinks; } /* *---------------------------------------------------------------------- * * Style_ChangeElements -- * * Update the list of elements used by a style. Elements * may be inserted or deleted. * * Results: * The list of elements in the master style is updated. For * each item-column using an instance of the master style, * the list of elements is updated. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ static void Style_ChangeElements( TreeCtrl *tree, /* Widget info. */ MStyle *masterStyle, /* Master style to be updated. */ int count, /* The number of elements in the style after * this routine finishes. */ TreeElement *elemList, /* List of master elements the style uses. */ int *map /* Array of indexes into the list of elements * currently used by the style. */ ) { TreeItem item; TreeItemColumn column; TreeColumn treeColumn; Tcl_HashTable *tablePtr = &tree->itemHash; Tcl_HashEntry *hPtr; Tcl_HashSearch search; int columnIndex, layout; int updateDInfo = FALSE; IStyle *style; int i, j, k, oldCount; int tailOK; /* Update -union lists */ for (i = 0; i < masterStyle->numElements; i++) { MElementLink *eLink = &masterStyle->elements[i]; int staticKeep[STATIC_SIZE], *keep = staticKeep; int onionCnt = 0, *onion = NULL; if (eLink->onion == NULL) continue; STATIC_ALLOC(keep, int, eLink->onionCount); /* Check every Element in this -union */ for (j = 0; j < eLink->onionCount; j++) { MElementLink *eLink2 = &masterStyle->elements[eLink->onion[j]]; /* Check the new list of Elements */ keep[j] = -1; for (k = 0; k < count; k++) { /* This new Element is in the -union */ if (elemList[k] == eLink2->elem) { keep[j] = k; onionCnt++; break; } } } if (onionCnt > 0) { if (onionCnt != eLink->onionCount) onion = (int *) ckalloc(sizeof(int) * onionCnt); else onion = eLink->onion; k = 0; for (j = 0; j < eLink->onionCount; j++) { if (keep[j] != -1) onion[k++] = keep[j]; } } STATIC_FREE(keep, int, eLink->onionCount); if (onionCnt != eLink->onionCount) { WCFREE(eLink->onion, int, eLink->onionCount); eLink->onion = onion; eLink->onionCount = onionCnt; } } oldCount = masterStyle->numElements; MStyle_ChangeElementsAux(tree, masterStyle, count, elemList, map); hPtr = Tcl_FirstHashEntry(tablePtr, &search); if (hPtr == NULL) { tablePtr = &tree->headerHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); tailOK = TreeItem_GetHeader(tree, item) != NULL; treeColumn = Tree_FirstColumn(tree, -1, TreeItem_GetHeader(tree, item) != NULL); column = TreeItem_GetFirstColumn(tree, item); columnIndex = 0; layout = FALSE; while (column != NULL) { style = (IStyle *) TreeItemColumn_GetStyle(tree, column); if ((style != NULL) && (style->master == masterStyle)) { IStyle_ChangeElementsAux(tree, style, oldCount, count, elemList, map); style->neededWidth = style->neededHeight = -1; TreeColumns_InvalidateWidthOfItems(tree, treeColumn); TreeItemColumn_InvalidateSize(tree, column); layout = TRUE; } columnIndex++; column = TreeItemColumn_GetNext(tree, column); treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK); } if (layout) { TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); updateDInfo = TRUE; } hPtr = Tcl_NextHashEntry(&search); if (hPtr == NULL && tablePtr == &tree->itemHash) { tablePtr = &tree->headerHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } } if (updateDInfo) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); } /* *---------------------------------------------------------------------- * * Style_ElemChanged -- * * Called when a master element or TreeCtrl is configured. * * Results: * A check is made on each item-column to see if it is using * the element. The size of any element/column/item affected * is marked out-of-date. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ static void Style_ElemChanged( TreeCtrl *tree, /* Widget info. */ MStyle *masterStyle, /* Master style that uses the element. */ TreeElement masterElem, /* Master element affected by the change. */ int masterElemIndex, /* Index of masterElem in masterStyle. */ int flagM, /* Flags returned by TreeElementType.configProc() * if the master element was configured, * zero if the TreeCtrl was configured. */ int flagT, /* TREE_CONF_xxx flags if the TreeCtrl was * configured, zero if the master element * was configured. */ int csM /* CS_xxx flags returned by * TreeElementType.changeProc(). */ ) { TreeItem item; TreeItemColumn column; TreeColumn treeColumn; Tcl_HashTable *tablePtr = &tree->itemHash; Tcl_HashEntry *hPtr; Tcl_HashSearch search; IElementLink *eLink; int columnIndex; TreeElementArgs args; IStyle *style; int eMask, cMask, iMask; int updateDInfo = FALSE, tailOK; args.tree = tree; args.change.flagTree = flagT; args.change.flagMaster = flagM; args.change.flagSelf = 0; hPtr = Tcl_FirstHashEntry(tablePtr, &search); if (hPtr == NULL) { tablePtr = &tree->headerHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); tailOK = TreeItem_GetHeader(tree, item) != NULL; treeColumn = Tree_FirstColumn(tree, -1, tailOK); column = TreeItem_GetFirstColumn(tree, item); columnIndex = 0; iMask = 0; while (column != NULL) { cMask = 0; style = (IStyle *) TreeItemColumn_GetStyle(tree, column); if ((style != NULL) && (style->master == masterStyle)) { eLink = &style->elements[masterElemIndex]; if (eLink->elem == masterElem) { #ifdef CACHE_ELEM_SIZE if (csM & CS_LAYOUT) eLink->neededWidth = eLink->neededHeight = -1; #endif cMask |= csM; } /* Instance element */ else { args.elem = eLink->elem; eMask = (*masterElem->typePtr->changeProc)(&args); #ifdef CACHE_ELEM_SIZE if (eMask & CS_LAYOUT) eLink->neededWidth = eLink->neededHeight = -1; #endif cMask |= eMask; } iMask |= cMask; if (cMask & CS_LAYOUT) { style->neededWidth = style->neededHeight = -1; TreeColumns_InvalidateWidthOfItems(tree, treeColumn); TreeItemColumn_InvalidateSize(tree, column); } else if (cMask & CS_DISPLAY) { Tree_InvalidateItemDInfo(tree, treeColumn, item, NULL); } } columnIndex++; column = TreeItemColumn_GetNext(tree, column); treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK); } if (iMask & CS_LAYOUT) { TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); updateDInfo = TRUE; } else if (iMask & CS_DISPLAY) { } hPtr = Tcl_NextHashEntry(&search); if (hPtr == NULL && tablePtr == &tree->itemHash) { tablePtr = &tree->headerHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } } if (updateDInfo) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); } /* *---------------------------------------------------------------------- * * TreeStyle_GetButtonY -- * * Return the value of the -buttony style option. * * Results: * Pixel value or -1 if unspecified. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_GetButtonY( TreeCtrl *tree, /* Widget info. */ TreeStyle style_ /* Master or instance style token. */ ) { MStyle *style = (MStyle *) style_; MStyle *master = (style->master != NULL) ? style->master : style; return (master->buttonYObj == NULL) ? -1 : master->buttonY; } /* *---------------------------------------------------------------------- * * TreeStyle_GetMaster -- * * Return the master style for an instance style. * * Results: * Token for the master style. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeStyle TreeStyle_GetMaster( TreeCtrl *tree, /* Widget info. */ TreeStyle style_ /* Instance style token. */ ) { return (TreeStyle) ((IStyle *) style_)->master; } /* *---------------------------------------------------------------------- * * TreeStyle_GetName -- * * Return the name of a style. * * Results: * String name. * * Side effects: * None. * *---------------------------------------------------------------------- */ CONST char * TreeStyle_GetName( TreeCtrl *tree, /* Widget info. */ TreeStyle style_ /* Master or instance style token. */ ) { MStyle *style = (MStyle *) style_; MStyle *master = (style->master != NULL) ? style->master : style; return master->name; } /* *---------------------------------------------------------------------- * * TreeStyle_GetStateDomain -- * * Return the state domain for a style. * * Results: * STATE_DOMAIN_XXX index. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_GetStateDomain( TreeCtrl *tree, /* Widget info. */ TreeStyle style_ /* Master or instance style token. */ ) { MStyle *style = (MStyle *) style_; MStyle *master = (style->master != NULL) ? style->master : style; return master->stateDomain; } /* *---------------------------------------------------------------------- * * Style_GetImageOrText -- * * Return the value of a configuration option for an element. * * Results: * The result of Tk_GetOptionValue for an option of the first * element of the proper type (if any), otherwise NULL. * * Side effects: * A Tcl_Obj may be allocated. * *---------------------------------------------------------------------- */ static Tcl_Obj * Style_GetImageOrText( TreeCtrl *tree, /* Widget info. */ IStyle *style, /* Style. */ TreeElementType *typePtr, /* Type of element to look for. */ Tcl_Obj *optionNameObj, /* Pointer to a Tcl_Obj holding the * option name. */ TreeElement *elemPtr /* Returned element or NULL. */ ) { IElementLink *eLink; int i; for (i = 0; i < style->master->numElements; i++) { eLink = &style->elements[i]; if (ELEMENT_TYPE_MATCHES(eLink->elem->typePtr, typePtr)) { Tcl_Obj *resultObjPtr; resultObjPtr = Tk_GetOptionValue(tree->interp, (char *) eLink->elem, eLink->elem->typePtr->optionTable, optionNameObj, tree->tkwin); (*elemPtr) = style->master->elements[i].elem; return resultObjPtr; } } (*elemPtr) = NULL; return NULL; } /* *---------------------------------------------------------------------- * * TreeStyle_GetImage -- * * Return the value of the -image option for the first * image element in a style (if any). * * Results: * The result of Tk_GetOptionValue if the element was found, * otherwise NULL. * * Side effects: * A Tcl_Obj may be allocated. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeStyle_GetImage( TreeCtrl *tree, /* Widget info. */ TreeStyle style_, /* Token for style to examine. */ TreeElement *elemPtr /* Returned element or NULL. */ ) { return Style_GetImageOrText(tree, (IStyle *) style_, &treeElemTypeImage, tree->imageOptionNameObj, elemPtr); } /* *---------------------------------------------------------------------- * * TreeStyle_GetText -- * * Return the value of the -text option for the first * text element in a style (if any). * * Results: * The result of Tk_GetOptionValue if the element was found, * otherwise NULL. * * Side effects: * A Tcl_Obj may be allocated. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeStyle_GetText( TreeCtrl *tree, /* Widget info. */ TreeStyle style_, /* Token for style to examine. */ TreeElement *elemPtr /* Returned element or NULL. */ ) { return Style_GetImageOrText(tree, (IStyle *) style_, &treeElemTypeText, tree->textOptionNameObj, elemPtr); } /* *---------------------------------------------------------------------- * * Style_SetImageOrText -- * * Set the value of a configuration option for the first * element of the proper type in a style (if any). * * Results: * A standard Tcl result. * * Side effects: * Size of the element and style will be marked out-of-date. * A Tcl_Obj may be allocated. * *---------------------------------------------------------------------- */ static int Style_SetImageOrText( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the style. Needed if * a new instance Element is created. */ TreeItemColumn column, /* Item-column containing the style */ IStyle *style, /* The style */ TreeElementType *typePtr, /* Element type to look for. */ Tcl_Obj *optionNameObj, /* Pointer to a Tcl_Obj holding the option * name. */ Tcl_Obj *valueObj, /* New value for the config option. */ TreeElement *elemPtr /* Returned element or NULL. */ ) { MStyle *masterStyle = style->master; IElementLink *eLink; int i; (*elemPtr) = NULL; for (i = 0; i < masterStyle->numElements; i++) { TreeElement masterElem = masterStyle->elements[i].elem; if (ELEMENT_TYPE_MATCHES(masterElem->typePtr, typePtr)) { Tcl_Obj *objv[2]; TreeElementArgs args; eLink = Style_CreateElem(tree, item, column, style, masterElem, NULL); objv[0] = optionNameObj; objv[1] = valueObj; args.tree = tree; args.elem = eLink->elem; args.config.objc = 2; args.config.objv = objv; args.config.flagSelf = 0; args.config.item = item; args.config.column = column; if ((*eLink->elem->typePtr->configProc)(&args) != TCL_OK) return TCL_ERROR; args.change.flagSelf = args.config.flagSelf; args.change.flagTree = 0; args.change.flagMaster = 0; (void) (*eLink->elem->typePtr->changeProc)(&args); #ifdef CACHE_ELEM_SIZE eLink->neededWidth = eLink->neededHeight = -1; #endif style->neededWidth = style->neededHeight = -1; (*elemPtr) = masterElem; break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeStyle_SetImage -- * * Set the value of the -image option for the first image * element in a style (if any). * * Results: * A standard Tcl result. * * Side effects: * Size of the element and style will be marked out-of-date. * A Tcl_Obj may be allocated. * *---------------------------------------------------------------------- */ int TreeStyle_SetImage( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the style. */ TreeItemColumn column, /* Item-column containing the style. */ TreeStyle style_, /* The instance style. */ Tcl_Obj *valueObj, /* New value for -image option. */ TreeElement *elemPtr /* Returned element or NULL. */ ) { return Style_SetImageOrText(tree, item, column, (IStyle *) style_, &treeElemTypeImage, tree->imageOptionNameObj, valueObj, elemPtr); } /* *---------------------------------------------------------------------- * * TreeStyle_SetText -- * * Set the value of the -text option for the first text * element in a style (if any). * * Results: * A standard Tcl result. * * Side effects: * Size of the element and style will be marked out-of-date. * A Tcl_Obj may be allocated. * *---------------------------------------------------------------------- */ int TreeStyle_SetText( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the style. */ TreeItemColumn column, /* Item-column containing the style. */ TreeStyle style_, /* The instance style. */ Tcl_Obj *valueObj, /* New value for -text option. */ TreeElement *elemPtr /* Returned element or NULL. */ ) { return Style_SetImageOrText(tree, item, column, (IStyle *) style_, &treeElemTypeText, tree->textOptionNameObj, valueObj, elemPtr); } /* *---------------------------------------------------------------------- * * Style_Deleted -- * * Called when a master style is about to be deleted. Any * item-columns using an instance of the style have their style * freed. * * Results: * The TreeCtrl -defaultstyle option is updated if the deleted * style was specified in the value of the option. * * Side effects: * Display changes. Memory is deallocated. * *---------------------------------------------------------------------- */ static void Style_Deleted( TreeCtrl *tree, /* Widget info. */ MStyle *masterStyle /* The master style being deleted. */ ) { TreeItem item; TreeItemColumn column; TreeColumn treeColumn; Tcl_HashTable *tablePtr = &tree->itemHash; Tcl_HashEntry *hPtr; Tcl_HashSearch search; IStyle *style; int columnIndex; int tailOK; hPtr = Tcl_FirstHashEntry(tablePtr, &search); if (hPtr == NULL) { tablePtr = &tree->headerHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); tailOK = TreeItem_GetHeader(tree, item) != NULL; treeColumn = Tree_FirstColumn(tree, -1, tailOK); column = TreeItem_GetFirstColumn(tree, item); columnIndex = 0; while (column != NULL) { style = (IStyle *) TreeItemColumn_GetStyle(tree, column); if ((style != NULL) && (style->master == masterStyle)) { TreeColumns_InvalidateWidthOfItems(tree, treeColumn); TreeItemColumn_ForgetStyle(tree, column); TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); } columnIndex++; column = TreeItemColumn_GetNext(tree, column); treeColumn = Tree_ColumnToTheRight(treeColumn, FALSE, tailOK); } hPtr = Tcl_NextHashEntry(&search); if (hPtr == NULL && tablePtr == &tree->itemHash) { tablePtr = &tree->headerHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } } /* Update each column's -itemstyle option */ treeColumn = tree->columns; while (treeColumn != NULL) { TreeColumn_StyleDeleted(treeColumn, (TreeStyle) masterStyle); treeColumn = TreeColumn_Next(treeColumn); } #ifdef DEPRECATED /* Update -defaultstyle option */ if (tree->defaultStyle.stylesObj != NULL) { Tcl_Obj *stylesObj = tree->defaultStyle.stylesObj; if (Tcl_IsShared(stylesObj)) { stylesObj = Tcl_DuplicateObj(stylesObj); Tcl_DecrRefCount(tree->defaultStyle.stylesObj); Tcl_IncrRefCount(stylesObj); tree->defaultStyle.stylesObj = stylesObj; } for (columnIndex = 0; columnIndex < tree->defaultStyle.numStyles; columnIndex++) { Tcl_Obj *emptyObj; if (tree->defaultStyle.styles[columnIndex] != (TreeStyle) masterStyle) continue; tree->defaultStyle.styles[columnIndex] = NULL; emptyObj = Tcl_NewObj(); Tcl_ListObjReplace(tree->interp, stylesObj, columnIndex, 1, 1, &emptyObj); } } #endif /* DEPRECATED */ #ifdef DRAGIMAGE_STYLE TreeDragImage_StyleDeleted(tree->dragImage, (TreeStyle) masterStyle); #endif } /* *---------------------------------------------------------------------- * * Element_Changed -- * * Called when a master element or TreeCtrl has been configured. * * Results: * Every master and instance style using the element is updated. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ static void Element_Changed( TreeCtrl *tree, /* Widget info. */ TreeElement masterElem, /* Master element that may have changed. */ int flagM, /* Flags returned by TreeElementType.configProc() * if the master element was configured, * zero if the TreeCtrl was configured. */ int flagT, /* TREE_CONF_xxx flags if the TreeCtrl was * configured, zero if the master element * was configured. */ int csM /* CS_xxx flags returned by * TreeElementType.changeProc(). */ ) { Tcl_HashEntry *hPtr; Tcl_HashSearch search; MStyle *masterStyle; MElementLink *eLink; int i; hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search); while (hPtr != NULL) { masterStyle = (MStyle *) Tcl_GetHashValue(hPtr); for (i = 0; i < masterStyle->numElements; i++) { eLink = &masterStyle->elements[i]; if (eLink->elem == masterElem) { Style_ElemChanged(tree, masterStyle, masterElem, i, flagM, flagT, csM); break; } } hPtr = Tcl_NextHashEntry(&search); } } /* *---------------------------------------------------------------------- * * Element_Deleted -- * * Called when a master element is about to be deleted. * * Results: * The list of elements in any master styles using the element is * updated. Ditto for instance styles. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ static void Element_Deleted( TreeCtrl *tree, /* Widget info. */ TreeElement masterElem /* Master element being deleted. */ ) { Tcl_HashEntry *hPtr; Tcl_HashSearch search; MStyle *masterStyle; MElementLink *eLink; int i, j; hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search); while (hPtr != NULL) { masterStyle = (MStyle *) Tcl_GetHashValue(hPtr); for (i = 0; i < masterStyle->numElements; i++) { eLink = &masterStyle->elements[i]; if (eLink->elem == masterElem) { TreeElement staticElemList[STATIC_SIZE], *elemList = staticElemList; int staticElemMap[STATIC_SIZE], *elemMap = staticElemMap; STATIC_ALLOC(elemList, TreeElement, masterStyle->numElements); STATIC_ALLOC(elemMap, int, masterStyle->numElements); for (j = 0; j < masterStyle->numElements; j++) { if (j == i) continue; elemList[(j < i) ? j : (j - 1)] = masterStyle->elements[j].elem; elemMap[(j < i) ? j : (j - 1)] = j; } Style_ChangeElements(tree, masterStyle, masterStyle->numElements - 1, elemList, elemMap); STATIC_FREE(elemList, TreeElement, masterStyle->numElements + 1); STATIC_FREE(elemMap, int, masterStyle->numElements + 1); break; } } hPtr = Tcl_NextHashEntry(&search); } } /* *---------------------------------------------------------------------- * * Tree_RedrawElement -- * * A STUB export. Schedules a redraw of the given item. * * Results: * None. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ void Tree_RedrawElement( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the element. */ TreeElement elem /* The element that changed. */ ) { /* Master element */ if (elem->master == NULL) { } /* Instance element */ else { Tree_InvalidateItemDInfo(tree, NULL, item, NULL); } } typedef struct Iterate { TreeCtrl *tree; TreeItem item; TreeItemColumn column; int columnIndex; IStyle *style; TreeElementType *elemTypePtr; IElementLink *eLink; Tcl_HashSearch search; Tcl_HashEntry *hPtr; } Iterate; static int IterateItem(Iterate *iter) { int i; while (iter->column != NULL) { iter->style = (IStyle *) TreeItemColumn_GetStyle(iter->tree, iter->column); if (iter->style != NULL) { for (i = 0; i < iter->style->master->numElements; i++) { iter->eLink = &iter->style->elements[i]; if (ELEMENT_TYPE_MATCHES(iter->eLink->elem->typePtr, iter->elemTypePtr)) return 1; } } iter->column = TreeItemColumn_GetNext(iter->tree, iter->column); iter->columnIndex++; } return 0; } TreeIterate Tree_ElementIterateBegin( TreeCtrl *tree, TreeElementType *elemTypePtr) { Iterate *iter; iter = (Iterate *) ckalloc(sizeof(Iterate)); iter->tree = tree; iter->elemTypePtr = elemTypePtr; iter->hPtr = Tcl_FirstHashEntry(&tree->itemHash, &iter->search); while (iter->hPtr != NULL) { iter->item = (TreeItem) Tcl_GetHashValue(iter->hPtr); iter->column = TreeItem_GetFirstColumn(tree, iter->item); iter->columnIndex = 0; if (IterateItem(iter)) return (TreeIterate) iter; iter->hPtr = Tcl_NextHashEntry(&iter->search); } ckfree((char *) iter); return NULL; } TreeIterate Tree_ElementIterateNext( TreeIterate iter_) { Iterate *iter = (Iterate *) iter_; iter->column = TreeItemColumn_GetNext(iter->tree, iter->column); iter->columnIndex++; if (IterateItem(iter)) return iter_; iter->hPtr = Tcl_NextHashEntry(&iter->search); while (iter->hPtr != NULL) { iter->item = (TreeItem) Tcl_GetHashValue(iter->hPtr); iter->column = TreeItem_GetFirstColumn(iter->tree, iter->item); iter->columnIndex = 0; if (IterateItem(iter)) return iter_; iter->hPtr = Tcl_NextHashEntry(&iter->search); } ckfree((char *) iter); return NULL; } /* *---------------------------------------------------------------------- * * Tree_ElementChangedItself -- * * Called when an element has reconfigured itself outside of * any API calls. For example, when a window associated with a * window element is resized, or a text element's -textvariable * is set. * * Results: * None. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ void Tree_ElementChangedItself( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the element. */ TreeItemColumn column, /* Item-column containing the element. */ TreeElement elem, /* The element that changed. */ int flags, /* Element-specific configuration flags. */ int csM /* CS_xxx flags detailing the effects of * the change. */ ) { /* Master element. */ if (item == NULL) { Element_Changed(tree, elem, flags, 0, csM); return; } if (csM & CS_LAYOUT) { IStyle *style = (IStyle *) TreeItemColumn_GetStyle(tree, column); int i; IElementLink *eLink = NULL; int columnIndex; if (style == NULL) panic("Tree_ElementChangedItself but style is NULL\n"); for (i = 0; i < style->master->numElements; i++) { eLink = &style->elements[i]; if (eLink->elem == elem) break; } if (eLink == NULL) panic("Tree_ElementChangedItself but eLink is NULL\n"); columnIndex = TreeItemColumn_Index(tree, item, column); #ifdef CACHE_ELEM_SIZE eLink->neededWidth = eLink->neededHeight = -1; #endif style->neededWidth = style->neededHeight = -1; if (TreeItem_GetHeader(tree, item) == NULL) TreeColumns_InvalidateWidthOfItems(tree, Tree_FindColumn(tree, columnIndex)); TreeItemColumn_InvalidateSize(tree, column); TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); if (TreeItem_GetHeader(tree, item) == NULL) Tree_DInfoChanged(tree, DINFO_REDO_RANGES); } else if (csM & CS_DISPLAY) { int columnIndex; columnIndex = TreeItemColumn_Index(tree, item, column); Tree_InvalidateItemDInfo(tree, Tree_FindColumn(tree, columnIndex), item, NULL); } } void Tree_ElementIterateChanged(TreeIterate iter_, int mask) { Iterate *iter = (Iterate *) iter_; if (mask & CS_LAYOUT) { #ifdef CACHE_ELEM_SIZE iter->eLink->neededWidth = iter->eLink->neededHeight = -1; #endif iter->style->neededWidth = iter->style->neededHeight = -1; TreeColumns_InvalidateWidthOfItems(iter->tree, Tree_FindColumn(iter->tree, iter->columnIndex)); TreeItemColumn_InvalidateSize(iter->tree, iter->column); TreeItem_InvalidateHeight(iter->tree, iter->item); Tree_FreeItemDInfo(iter->tree, iter->item, NULL); Tree_DInfoChanged(iter->tree, DINFO_REDO_RANGES); } if (mask & CS_DISPLAY) Tree_InvalidateItemDInfo(iter->tree, NULL, iter->item, NULL); } TreeElement Tree_ElementIterateGet(TreeIterate iter_) { Iterate *iter = (Iterate *) iter_; return iter->eLink->elem; } /* *---------------------------------------------------------------------- * * TreeStyle_TreeChanged -- * * Called when a TreeCtrl is configured. This handles changes to * the -font option affecting text elements for example. * * Results: * Calls the changeProc on every master element. Any elements * affected by the change are eventually redisplayed. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ void TreeStyle_TreeChanged( TreeCtrl *tree, /* Widget info. */ int flagT /* TREE_CONF_xxx flags. */ ) { Tcl_HashEntry *hPtr; Tcl_HashSearch search; TreeElement masterElem; TreeElementArgs args; int eMask; if (flagT == 0) return; args.tree = tree; args.change.flagTree = flagT; args.change.flagMaster = 0; args.change.flagSelf = 0; hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search); while (hPtr != NULL) { masterElem = (TreeElement) Tcl_GetHashValue(hPtr); args.elem = masterElem; eMask = (*masterElem->typePtr->changeProc)(&args); Element_Changed(tree, masterElem, 0, flagT, eMask); hPtr = Tcl_NextHashEntry(&search); } } /* *---------------------------------------------------------------------- * * TreeStyle_ElementCget -- * * This procedure is invoked to process the [item element cget] * widget command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeStyle_ElementCget( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the element. */ TreeItemColumn column, /* Item-column containing the element. */ TreeStyle style_, /* Style containing the element. */ Tcl_Obj *elemObj, /* Name of the element. */ Tcl_Obj *optionNameObj /* Name of the config option. */ ) { IStyle *style = (IStyle *) style_; Tcl_Obj *resultObjPtr = NULL; TreeElement elem; IElementLink *eLink; int inHeader = TreeItem_GetHeader(tree, item) != NULL; if (TreeElement_FromObj(tree, elemObj, &elem) != TCL_OK) return TCL_ERROR; eLink = IStyle_FindElem(tree, style, elem, NULL); if ((eLink != NULL) && (eLink->elem == elem)) { int index = TreeItemColumn_Index(tree, item, column); TreeColumn treeColumn = Tree_FindColumn(tree, index); FormatResult(tree->interp, "element %s is not configured in %s %s%d column %s%d", elem->name, inHeader ? "header" : "item", inHeader ? "" : tree->itemPrefix, TreeItem_GetID(tree, item), tree->columnPrefix, TreeColumn_GetID(treeColumn)); return TCL_ERROR; } if (eLink == NULL) { FormatResult(tree->interp, "style %s does not use element %s", style->master->name, elem->name); return TCL_ERROR; } resultObjPtr = Tk_GetOptionValue(tree->interp, (char *) eLink->elem, eLink->elem->typePtr->optionTable, optionNameObj, tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(tree->interp, resultObjPtr); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeStyle_ElementConfigure -- * * This procedure is invoked to process the [item element configure] * widget command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeStyle_ElementConfigure( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the element. */ TreeItemColumn column, /* Item-column containing the element. */ TreeStyle style_, /* Style containing the element. */ TreeElement elem, /* Name of the element. */ int objc, /* Number of arguments. */ Tcl_Obj **objv, /* Argument values. */ int *eMask /* Returned CS_xxx flags. */ ) { IStyle *style = (IStyle *) style_; IElementLink *eLink; TreeElementArgs args; int inHeader = TreeItem_GetHeader(tree, item) != NULL; (*eMask) = 0; if (objc <= 1) { Tcl_Obj *resultObjPtr; eLink = IStyle_FindElem(tree, style, elem, NULL); if ((eLink != NULL) && (eLink->elem == elem)) { int index = TreeItemColumn_Index(tree, item, column); TreeColumn treeColumn = Tree_FindColumn(tree, index); FormatResult(tree->interp, "element %s is not configured in %s %s%d column %s%d", elem->name, inHeader ? "header" : "item", inHeader ? "" : tree->itemPrefix, TreeItem_GetID(tree, item), tree->columnPrefix, TreeColumn_GetID(treeColumn)); return TCL_ERROR; } if (eLink == NULL) { FormatResult(tree->interp, "style %s does not use element %s", style->master->name, elem->name); return TCL_ERROR; } resultObjPtr = Tk_GetOptionInfo(tree->interp, (char *) eLink->elem, eLink->elem->typePtr->optionTable, (objc == 0) ? (Tcl_Obj *) NULL : objv[0], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(tree->interp, resultObjPtr); } else { int isNew; eLink = Style_CreateElem(tree, item, column, style, elem, &isNew); if (eLink == NULL) { FormatResult(tree->interp, "style %s does not use element %s", style->master->name, elem->name); return TCL_ERROR; } /* Do this before configProc(). If eLink was just allocated and an * error occurs in configProc() it won't be done */ (*eMask) = 0; if (isNew) { #ifdef CACHE_ELEM_SIZE eLink->neededWidth = eLink->neededHeight = -1; #endif style->neededWidth = style->neededHeight = -1; (*eMask) = CS_DISPLAY | CS_LAYOUT; } args.tree = tree; args.elem = eLink->elem; args.config.objc = objc; args.config.objv = objv; args.config.flagSelf = 0; args.config.item = item; args.config.column = column; if ((*args.elem->typePtr->configProc)(&args) != TCL_OK) return TCL_ERROR; args.change.flagSelf = args.config.flagSelf; args.change.flagTree = 0; args.change.flagMaster = 0; (*eMask) |= (*elem->typePtr->changeProc)(&args); if (!isNew && ((*eMask) & CS_LAYOUT)) { #ifdef CACHE_ELEM_SIZE eLink->neededWidth = eLink->neededHeight = -1; #endif style->neededWidth = style->neededHeight = -1; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeStyle_ElementConfigureFromObj -- * * This procedure is invoked to process the [item element configure] * widget command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeStyle_ElementConfigureFromObj( TreeCtrl *tree, /* Widget info. */ TreeItem item, /* Item containing the element. */ TreeItemColumn column, /* Item-column containing the element. */ TreeStyle style, /* Style containing the element. */ Tcl_Obj *elemObj, /* Name of the element. */ int objc, /* Number of arguments. */ Tcl_Obj **objv, /* Argument values. */ int *eMask /* Returned CS_xxx flags. */ ) { TreeElement elem; (*eMask) = 0; if (TreeElement_FromObj(tree, elemObj, &elem) != TCL_OK) return TCL_ERROR; return TreeStyle_ElementConfigure(tree, item, column, style, elem, objc, objv, eMask); } /* *---------------------------------------------------------------------- * * TreeStyle_ElementActual -- * * This procedure is invoked to process the [item element perstate] * widget command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeStyle_ElementActual( TreeCtrl *tree, /* Widget info. */ TreeStyle style_, /* The style. */ int state, /* STATE_xxx flags. */ Tcl_Obj *elemObj, /* Name of the element. */ Tcl_Obj *optionNameObj /* Name of the config option. */ ) { IStyle *style = (IStyle *) style_; TreeElement masterElem; IElementLink *eLink; TreeElementArgs args; if (TreeElement_FromObj(tree, elemObj, &masterElem) != TCL_OK) return TCL_ERROR; eLink = IStyle_FindElem(tree, style, masterElem, NULL); if (eLink == NULL) { FormatResult(tree->interp, "style %s does not use element %s", style->master->name, masterElem->name); return TCL_ERROR; } args.tree = tree; args.elem = eLink->elem; args.state = state; args.actual.obj = optionNameObj; return (*masterElem->typePtr->actualProc)(&args); } /* *---------------------------------------------------------------------- * * TreeElementCmd -- * * This procedure is invoked to process the [element] * widget command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeElementCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; static CONST char *commandNames[] = { "cget", "configure", "create", "delete", "names", "perstate", "type", (char *) NULL }; enum { COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_CREATE, COMMAND_DELETE, COMMAND_NAMES, COMMAND_PERSTATE, COMMAND_TYPE }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case COMMAND_CGET: { Tcl_Obj *resultObjPtr = NULL; TreeElement elem; if (objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "name option"); return TCL_ERROR; } if (TreeElement_FromObj(tree, objv[3], &elem) != TCL_OK) return TCL_ERROR; /* Hack -- allow [cget -statedomain] but not [configure] */ { int length; CONST char *s = Tcl_GetStringFromObj(objv[4], &length); /* FIXME: Check for minimum # unique chars. */ if (strncmp(s, "-statedomain", length) == 0 && length >= 6) { Tcl_SetObjResult(interp, Tcl_NewStringObj( tree->stateDomain[elem->stateDomain].name, -1)); break; } } resultObjPtr = Tk_GetOptionValue(interp, (char *) elem, elem->typePtr->optionTable, objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } case COMMAND_CONFIGURE: { Tcl_Obj *resultObjPtr = NULL; TreeElement elem; int eMask; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "name ?option? ?value option value ...?"); return TCL_ERROR; } if (TreeElement_FromObj(tree, objv[3], &elem) != TCL_OK) return TCL_ERROR; if (objc <= 5) { resultObjPtr = Tk_GetOptionInfo(interp, (char *) elem, elem->typePtr->optionTable, (objc == 4) ? (Tcl_Obj *) NULL : objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); } else { TreeElementArgs args; args.tree = tree; args.elem = elem; args.config.objc = objc - 4; args.config.objv = objv + 4; args.config.flagSelf = 0; args.config.item = NULL; args.config.column = NULL; if ((*elem->typePtr->configProc)(&args) != TCL_OK) return TCL_ERROR; args.change.flagSelf = args.config.flagSelf; args.change.flagTree = 0; args.change.flagMaster = 0; eMask = (*elem->typePtr->changeProc)(&args); Element_Changed(tree, elem, args.change.flagSelf, 0, eMask); } break; } case COMMAND_CREATE: { char *name; int length; int isNew; TreeElement elem; TreeElementType *typePtr; Tcl_HashEntry *hPtr; if (objc < 5) { Tcl_WrongNumArgs(interp, 3, objv, "name type ?option value ...?"); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[3], &length); if (!length) return TCL_ERROR; hPtr = Tcl_FindHashEntry(&tree->elementHash, name); if (hPtr != NULL) { FormatResult(interp, "element \"%s\" already exists", name); return TCL_ERROR; } if (TreeElement_TypeFromObj(tree, objv[4], &typePtr) != TCL_OK) return TCL_ERROR; elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name, objc - 5, objv + 5); if (elem == NULL) return TCL_ERROR; hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew); Tcl_SetHashValue(hPtr, elem); Tcl_SetObjResult(interp, TreeElement_ToObj(elem)); break; } case COMMAND_DELETE: { TreeElement elem; int i; for (i = 3; i < objc; i++) { if (TreeElement_FromObj(tree, objv[i], &elem) != TCL_OK) return TCL_ERROR; Element_Deleted(tree, elem); Element_FreeResources(tree, elem); } break; } case COMMAND_NAMES: { Tcl_Obj *listObj; Tcl_HashSearch search; Tcl_HashEntry *hPtr; TreeElement elem; if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, NULL); return TCL_ERROR; } listObj = Tcl_NewListObj(0, NULL); hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search); while (hPtr != NULL) { elem = (TreeElement) Tcl_GetHashValue(hPtr); if (!elem->hidden) Tcl_ListObjAppendElement(interp, listObj, TreeElement_ToObj(elem)); hPtr = Tcl_NextHashEntry(&search); } Tcl_SetObjResult(interp, listObj); break; } /* T element perstate E option stateList */ case COMMAND_PERSTATE: { TreeElement elem; int states[3]; TreeElementArgs args; if (objc != 6) { Tcl_WrongNumArgs(tree->interp, 3, objv, "element option stateList"); return TCL_ERROR; } if (TreeElement_FromObj(tree, objv[3], &elem) != TCL_OK) return TCL_ERROR; if (Tree_StateFromListObj(tree, elem->stateDomain, objv[5], states, SFO_NOT_OFF | SFO_NOT_TOGGLE) != TCL_OK) return TCL_ERROR; args.tree = tree; args.elem = elem; args.state = states[STATE_OP_ON]; args.actual.obj = objv[4]; return (*elem->typePtr->actualProc)(&args); } case COMMAND_TYPE: { TreeElement elem; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "name"); return TCL_ERROR; } if (TreeElement_FromObj(tree, objv[3], &elem) != TCL_OK) return TCL_ERROR; Tcl_SetResult(interp, elem->typePtr->name, TCL_STATIC); /* Tk_Uid */ break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Style_CreateAndConfig -- * * Allocate and initialize a master style. * * Results: * Pointer to the new Style, or NULL if an error occurs. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ static MStyle * Style_CreateAndConfig( TreeCtrl *tree, /* Widget info. */ char *name, /* Name of new style. */ int objc, /* Number of config-option arg-value pairs. */ Tcl_Obj *CONST objv[] /* Config-option arg-value pairs. */ ) { MStyle *style; int i, objC = 0; Tcl_Obj *staticObjV[STATIC_SIZE], **objV = staticObjV; int domain = STATE_DOMAIN_ITEM; STATIC_ALLOC(objV, Tcl_Obj *, objc); /* Filter out -statedomain and its value. */ /* FIXME: there is no way to query this. */ for (i = 0; i < objc; i += 2) { int length; CONST char *s = Tcl_GetStringFromObj(objv[i], &length); if (strncmp(s, "-statedomain", length) == 0) { if (i + 1 == objc) { FormatResult(tree->interp, "value for \"%s\" missing", s); STATIC_FREE(objV, Tcl_Obj *, objc); return NULL; } s = Tcl_GetStringFromObj(objv[i + 1], &length); if (strncmp(s, "header", length) == 0) domain = STATE_DOMAIN_HEADER; else if (strncmp(s, "item", length) != 0) { FormatResult(tree->interp, "unknown state domain \"%s\"", s); STATIC_FREE(objV, Tcl_Obj *, objc); return NULL; } } else { objV[objC++] = objv[i]; if (i + 1 < objc) objV[objC++] = objv[i + 1]; } } #ifdef ALLOC_HAX style = (MStyle *) TreeAlloc_Alloc(tree->allocData, MStyleUid, sizeof(MStyle)); #else style = (MStyle *) ckalloc(sizeof(MStyle)); #endif memset(style, '\0', sizeof(MStyle)); style->name = Tk_GetUid(name); style->stateDomain = domain; if (Tk_InitOptions(tree->interp, (char *) style, tree->styleOptionTable, tree->tkwin) != TCL_OK) { STATIC_FREE(objV, Tcl_Obj *, objc); #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, MStyleUid, (char *) style, sizeof(MStyle)); #else WFREE(style, MStyle); #endif return NULL; } if (Tk_SetOptions(tree->interp, (char *) style, tree->styleOptionTable, objC, objV, tree->tkwin, NULL, NULL) != TCL_OK) { STATIC_FREE(objV, Tcl_Obj *, objc); Tk_FreeConfigOptions((char *) style, tree->styleOptionTable, tree->tkwin); #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, MStyleUid, (char *) style, sizeof(MStyle)); #else WFREE(style, MStyle); #endif return NULL; } STATIC_FREE(objV, Tcl_Obj *, objc); return style; } /* *---------------------------------------------------------------------- * * TreeStyle_ListElements -- * * Creates a Tcl list with the names of elements in a style. * * Results: * If the style is a master style, the interpreter result holds * a list of each element in the style. If the style is an * instance style, the interpreter result holds a list of those * elements configured for the style (i.e., instance elements). * * Side effects: * Memory is allocated, interpreter result changed. * *---------------------------------------------------------------------- */ void TreeStyle_ListElements( TreeCtrl *tree, /* Widget info. */ TreeStyle style_ /* The style. */ ) { MStyle *masterStyle = (MStyle *) style_; IStyle *style = (IStyle *) style_; Tcl_Obj *listObj; TreeElement elem; int i, numElements = TreeStyle_NumElements(tree, style_); if (numElements <= 0) return; listObj = Tcl_NewListObj(0, NULL); for (i = 0; i < numElements; i++) { if (style->master != NULL) { elem = style->elements[i].elem; if (elem->master == NULL) continue; } else { elem = masterStyle->elements[i].elem; } Tcl_ListObjAppendElement(tree->interp, listObj, TreeElement_ToObj(elem)); } Tcl_SetObjResult(tree->interp, listObj); } enum { OPTION_CENTER, OPTION_DETACH, OPTION_DRAW, OPTION_EXPAND, OPTION_HEIGHT, OPTION_iEXPAND, OPTION_INDENT, OPTION_iPADX, OPTION_iPADY, OPTION_MAXHEIGHT, OPTION_MAXWIDTH, OPTION_MINHEIGHT, OPTION_MINWIDTH, OPTION_PADX, OPTION_PADY, OPTION_SQUEEZE, OPTION_STICKY, OPTION_UNION, OPTION_WIDTH, OPTION_VISIBLE }; /* *---------------------------------------------------------------------- * * LayoutOptionToObj -- * * Return a Tcl_Obj holding the value of a style layout option * for an element. * * Results: * Pointer to a new Tcl_Obj or NULL if the option has no value. * * Side effects: * A Tcl_Obj may be allocated. * *---------------------------------------------------------------------- */ static Tcl_Obj * LayoutOptionToObj( TreeCtrl *tree, /* Widget info. */ MStyle *style, /* Master style using the element. */ MElementLink *eLink, /* Layout info for the element. */ int option /* OPTION_xxx constant. */ ) { Tcl_Interp *interp = tree->interp; switch (option) { case OPTION_PADX: return TreeCtrl_NewPadAmountObj(eLink->ePadX); case OPTION_PADY: return TreeCtrl_NewPadAmountObj(eLink->ePadY); case OPTION_iPADX: return TreeCtrl_NewPadAmountObj(eLink->iPadX); case OPTION_iPADY: return TreeCtrl_NewPadAmountObj(eLink->iPadY); case OPTION_CENTER: { char flags[2]; int n = 0; if (eLink->flags & ELF_CENTER_X) flags[n++] = 'x'; if (eLink->flags & ELF_CENTER_Y) flags[n++] = 'y'; if (n) return Tcl_NewStringObj(flags, n); break; } case OPTION_DETACH: return Tcl_NewStringObj(IS_DETACH(eLink) ? "yes" : "no", -1); case OPTION_EXPAND: { char flags[4]; int n = 0; if (eLink->flags & ELF_eEXPAND_W) flags[n++] = 'w'; if (eLink->flags & ELF_eEXPAND_N) flags[n++] = 'n'; if (eLink->flags & ELF_eEXPAND_E) flags[n++] = 'e'; if (eLink->flags & ELF_eEXPAND_S) flags[n++] = 's'; if (n) return Tcl_NewStringObj(flags, n); break; } case OPTION_iEXPAND: { char flags[6]; int n = 0; if (eLink->flags & ELF_iEXPAND_X) flags[n++] = 'x'; if (eLink->flags & ELF_iEXPAND_Y) flags[n++] = 'y'; if (eLink->flags & ELF_iEXPAND_W) flags[n++] = 'w'; if (eLink->flags & ELF_iEXPAND_N) flags[n++] = 'n'; if (eLink->flags & ELF_iEXPAND_E) flags[n++] = 'e'; if (eLink->flags & ELF_iEXPAND_S) flags[n++] = 's'; if (n) return Tcl_NewStringObj(flags, n); break; } case OPTION_INDENT: return Tcl_NewStringObj((eLink->flags & ELF_INDENT) ? "yes" : "no", -1); case OPTION_SQUEEZE: { char flags[2]; int n = 0; if (eLink->flags & ELF_SQUEEZE_X) flags[n++] = 'x'; if (eLink->flags & ELF_SQUEEZE_Y) flags[n++] = 'y'; if (n) return Tcl_NewStringObj(flags, n); break; } case OPTION_UNION: { int i; Tcl_Obj *objPtr; if (eLink->onionCount == 0) break; objPtr = Tcl_NewListObj(0, NULL); for (i = 0; i < eLink->onionCount; i++) Tcl_ListObjAppendElement(interp, objPtr, TreeElement_ToObj(style->elements[eLink->onion[i]].elem)); return objPtr; } case OPTION_MAXHEIGHT: { if (eLink->maxHeight >= 0) return Tcl_NewIntObj(eLink->maxHeight); break; } case OPTION_MINHEIGHT: { if (eLink->minHeight >= 0) return Tcl_NewIntObj(eLink->minHeight); break; } case OPTION_HEIGHT: { if (eLink->fixedHeight >= 0) return Tcl_NewIntObj(eLink->fixedHeight); break; } case OPTION_MAXWIDTH: { if (eLink->maxWidth >= 0) return Tcl_NewIntObj(eLink->maxWidth); break; } case OPTION_MINWIDTH: { if (eLink->minWidth >= 0) return Tcl_NewIntObj(eLink->minWidth); break; } case OPTION_WIDTH: { if (eLink->fixedWidth >= 0) return Tcl_NewIntObj(eLink->fixedWidth); break; } case OPTION_STICKY: { char flags[4]; int n = 0; if (eLink->flags & ELF_STICKY_W) flags[n++] = 'w'; if (eLink->flags & ELF_STICKY_N) flags[n++] = 'n'; if (eLink->flags & ELF_STICKY_E) flags[n++] = 'e'; if (eLink->flags & ELF_STICKY_S) flags[n++] = 's'; if (n) return Tcl_NewStringObj(flags, n); break; } case OPTION_DRAW: { return eLink->draw.obj; } case OPTION_VISIBLE: { return eLink->visible.obj; } } return NULL; } static int UnionRecursiveCheck( MStyle *mstyle, int iElemUnion, int iElemFind ) { int i; for (i = 0; i < mstyle->elements[iElemUnion].onionCount; i++) { if (mstyle->elements[iElemUnion].onion[i] == iElemFind) return 1; if (UnionRecursiveCheck(mstyle, mstyle->elements[iElemUnion].onion[i], iElemFind)) return 1; } return 0; } /* *---------------------------------------------------------------------- * * StyleLayoutCmd -- * * This procedure is invoked to process the [style layout] * widget command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int StyleLayoutCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* The current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; TreeStyle _style; MStyle *style; TreeElement elem; MElementLink saved, *eLink; int i, index, eIndex; static CONST char *optionNames[] = { "-center", "-detach", "-draw", "-expand", "-height", "-iexpand", "-indent", "-ipadx", "-ipady", "-maxheight", "-maxwidth", "-minheight", "-minwidth", "-padx", "-pady", "-squeeze", "-sticky", "-union", "-width", "-visible", (char *) NULL }; if (objc < 5) { Tcl_WrongNumArgs(interp, 3, objv, "name element ?option? ?value? ?option value ...?"); return TCL_ERROR; } if (TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK) return TCL_ERROR; style = (MStyle *) _style; if (TreeElement_FromObj(tree, objv[4], &elem) != TCL_OK) return TCL_ERROR; eLink = MStyle_FindElem(tree, style, elem, &eIndex); if (eLink == NULL) { FormatResult(interp, "style %s does not use element %s", style->name, elem->name); return TCL_ERROR; } /* T style layout S E */ if (objc == 5) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); Tcl_Obj *objPtr; for (i = 0; optionNames[i] != NULL; i++) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(optionNames[i], -1)); objPtr = LayoutOptionToObj(tree, style, eLink, i); Tcl_ListObjAppendElement(interp, listObj, objPtr ? objPtr : Tcl_NewObj()); } Tcl_SetObjResult(interp, listObj); return TCL_OK; } /* T style layout S E option */ if (objc == 6) { Tcl_Obj *objPtr; if (Tcl_GetIndexFromObj(interp, objv[5], optionNames, "option", 0, &index) != TCL_OK) return TCL_ERROR; objPtr = LayoutOptionToObj(tree, style, eLink, index); if (objPtr != NULL) Tcl_SetObjResult(interp, objPtr); return TCL_OK; } saved = *eLink; for (i = 5; i < objc; i += 2) { if (i + 2 > objc) { FormatResult(interp, "value for \"%s\" missing", Tcl_GetString(objv[i])); goto badConfig; } if (Tcl_GetIndexFromObj(interp, objv[i], optionNames, "option", 0, &index) != TCL_OK) { goto badConfig; } switch (index) { case OPTION_PADX: { if (TreeCtrl_GetPadAmountFromObj(interp, tree->tkwin, objv[i + 1], &eLink->ePadX[PAD_TOP_LEFT], &eLink->ePadX[PAD_BOTTOM_RIGHT]) != TCL_OK) goto badConfig; break; } case OPTION_PADY: { if (TreeCtrl_GetPadAmountFromObj(interp, tree->tkwin, objv[i + 1], &eLink->ePadY[PAD_TOP_LEFT], &eLink->ePadY[PAD_BOTTOM_RIGHT]) != TCL_OK) goto badConfig; break; } case OPTION_iPADX: { if (TreeCtrl_GetPadAmountFromObj(interp, tree->tkwin, objv[i + 1], &eLink->iPadX[PAD_TOP_LEFT], &eLink->iPadX[PAD_BOTTOM_RIGHT]) != TCL_OK) goto badConfig; break; } case OPTION_iPADY: { if (TreeCtrl_GetPadAmountFromObj(interp, tree->tkwin, objv[i + 1], &eLink->iPadY[PAD_TOP_LEFT], &eLink->iPadY[PAD_BOTTOM_RIGHT]) != TCL_OK) goto badConfig; break; } case OPTION_CENTER: { static const CharFlag charFlags[] = { { 'x', ELF_CENTER_X }, { 'y', ELF_CENTER_Y }, { 0, 0 } }; if (Tree_GetFlagsFromObj(tree, objv[i + 1], "center value", charFlags, &eLink->flags) != TCL_OK) { goto badConfig; } break; } case OPTION_DETACH: { int detach; if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &detach) != TCL_OK) goto badConfig; if (detach) eLink->flags |= ELF_DETACH; else eLink->flags &= ~ELF_DETACH; break; } case OPTION_EXPAND: { static const CharFlag charFlags[] = { { 'n', ELF_eEXPAND_N }, { 'e', ELF_eEXPAND_E }, { 's', ELF_eEXPAND_S }, { 'w', ELF_eEXPAND_W }, { 0, 0 } }; if (Tree_GetFlagsFromObj(tree, objv[i + 1], "expand value", charFlags, &eLink->flags) != TCL_OK) { goto badConfig; } break; } case OPTION_iEXPAND: { static const CharFlag charFlags[] = { { 'x', ELF_iEXPAND_X }, { 'y', ELF_iEXPAND_Y }, { 'n', ELF_iEXPAND_N }, { 'e', ELF_iEXPAND_E }, { 's', ELF_iEXPAND_S }, { 'w', ELF_iEXPAND_W }, { 0, 0 } }; if (Tree_GetFlagsFromObj(tree, objv[i + 1], "iexpand value", charFlags, &eLink->flags) != TCL_OK) { goto badConfig; } break; } case OPTION_INDENT: { int indent; if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &indent) != TCL_OK) goto badConfig; if (indent) eLink->flags |= ELF_INDENT; else eLink->flags &= ~ELF_INDENT; break; } case OPTION_SQUEEZE: { static const CharFlag charFlags[] = { { 'x', ELF_SQUEEZE_X }, { 'y', ELF_SQUEEZE_Y }, { 0, 0 } }; if (Tree_GetFlagsFromObj(tree, objv[i + 1], "squeeze value", charFlags, &eLink->flags) != TCL_OK) { goto badConfig; } break; } case OPTION_UNION: { int objc1; Tcl_Obj **objv1; int j, k, eIndex2, *onion, count = 0; if (Tcl_ListObjGetElements(interp, objv[i + 1], &objc1, &objv1) != TCL_OK) goto badConfig; if (objc1 == 0) { if (eLink->onion != NULL) { if (eLink->onion != saved.onion) WCFREE(eLink->onion, int, eLink->onionCount); eLink->onionCount = 0; eLink->onion = NULL; } break; } onion = (int *) ckalloc(sizeof(int) * objc1); for (j = 0; j < objc1; j++) { TreeElement elem2; MElementLink *eLink2; if (TreeElement_FromObj(tree, objv1[j], &elem2) != TCL_OK) { ckfree((char *) onion); goto badConfig; } eLink2 = MStyle_FindElem(tree, style, elem2, &eIndex2); if (eLink2 == NULL) { ckfree((char *) onion); FormatResult(interp, "style %s does not use element %s", style->name, elem2->name); goto badConfig; } if (eLink == eLink2) { ckfree((char *) onion); FormatResult(interp, "element %s can't form union with itself", elem2->name); goto badConfig; } if (UnionRecursiveCheck(style, eIndex2, eIndex)) { ckfree((char *) onion); FormatResult(interp, "can't form a recursive union with element %s", elem2->name); goto badConfig; } /* Silently ignore duplicates */ for (k = 0; k < count; k++) { if (onion[k] == eIndex2) break; } if (k < count) continue; onion[count++] = eIndex2; } if ((eLink->onion != NULL) && (eLink->onion != saved.onion)) WCFREE(eLink->onion, int, eLink->onionCount); if (count == objc1) eLink->onion = onion; else { eLink->onion = (int *) ckalloc(sizeof(int) * count); for (k = 0; k < count; k++) eLink->onion[k] = onion[k]; ckfree((char *) onion); } eLink->onionCount = count; break; } case OPTION_MAXHEIGHT: { int height; if (ObjectIsEmpty(objv[i + 1])) { eLink->maxHeight = -1; break; } if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], &height) != TCL_OK) || (height < 0)) { FormatResult(interp, "bad screen distance \"%s\"", Tcl_GetString(objv[i + 1])); goto badConfig; } eLink->maxHeight = height; break; } case OPTION_MINHEIGHT: { int height; if (ObjectIsEmpty(objv[i + 1])) { eLink->minHeight = -1; break; } if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], &height) != TCL_OK) || (height < 0)) { FormatResult(interp, "bad screen distance \"%s\"", Tcl_GetString(objv[i + 1])); goto badConfig; } eLink->minHeight = height; break; } case OPTION_HEIGHT: { int height; if (ObjectIsEmpty(objv[i + 1])) { eLink->fixedHeight = -1; break; } if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], &height) != TCL_OK) || (height < 0)) { FormatResult(interp, "bad screen distance \"%s\"", Tcl_GetString(objv[i + 1])); goto badConfig; } eLink->fixedHeight = height; break; } case OPTION_MAXWIDTH: { int width; if (ObjectIsEmpty(objv[i + 1])) { eLink->maxWidth = -1; break; } if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], &width) != TCL_OK) || (width < 0)) { FormatResult(interp, "bad screen distance \"%s\"", Tcl_GetString(objv[i + 1])); goto badConfig; } eLink->maxWidth = width; break; } case OPTION_MINWIDTH: { int width; if (ObjectIsEmpty(objv[i + 1])) { eLink->minWidth = -1; break; } if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], &width) != TCL_OK) || (width < 0)) { FormatResult(interp, "bad screen distance \"%s\"", Tcl_GetString(objv[i + 1])); goto badConfig; } eLink->minWidth = width; break; } case OPTION_WIDTH: { int width; if (ObjectIsEmpty(objv[i + 1])) { eLink->fixedWidth = -1; break; } if ((Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], &width) != TCL_OK) || (width < 0)) { FormatResult(interp, "bad screen distance \"%s\"", Tcl_GetString(objv[i + 1])); goto badConfig; } eLink->fixedWidth = width; break; } case OPTION_STICKY: { static const CharFlag charFlags[] = { { 'n', ELF_STICKY_N }, { 'e', ELF_STICKY_E }, { 's', ELF_STICKY_S }, { 'w', ELF_STICKY_W }, { 0, 0 } }; if (Tree_GetFlagsFromObj(tree, objv[i + 1], "sticky value", charFlags, &eLink->flags) != TCL_OK) { goto badConfig; } break; } case OPTION_DRAW: case OPTION_VISIBLE: { PerStateInfo *psi, *psiSaved; if (index == OPTION_DRAW) { psi = &eLink->draw; psiSaved = &saved.draw; } else { psi = &eLink->visible; psiSaved = &saved.visible; } /* Already configured this once. */ if (psi->obj != NULL && psi->obj != psiSaved->obj) { PerStateInfo_Free(tree, &pstBoolean, psi); Tcl_DecrRefCount(psi->obj); /* First configure. Don't free the saved data. */ } else { psi->data = NULL; psi->count = 0; } psi->obj = objv[i + 1]; Tcl_IncrRefCount(psi->obj); if (PerStateInfo_FromObj(tree, style->stateDomain, TreeStateFromObj, &pstBoolean, psi) != TCL_OK) { goto badConfig; } break; } } } if (saved.onion && (eLink->onion != saved.onion)) WCFREE(saved.onion, int, saved.onionCount); if (saved.draw.obj != NULL && saved.draw.obj != eLink->draw.obj) { PerStateInfo_Free(tree, &pstBoolean, &saved.draw); Tcl_DecrRefCount(saved.draw.obj); } if (saved.visible.obj != NULL && saved.visible.obj != eLink->visible.obj) { PerStateInfo_Free(tree, &pstBoolean, &saved.visible); Tcl_DecrRefCount(saved.visible.obj); } Style_Changed(tree, style); return TCL_OK; badConfig: if (eLink->onion && (eLink->onion != saved.onion)) WCFREE(eLink->onion, int, eLink->onionCount); if (eLink->draw.obj != NULL && eLink->draw.obj != saved.draw.obj) { PerStateInfo_Free(tree, &pstBoolean, &eLink->draw); Tcl_DecrRefCount(eLink->draw.obj); } if (eLink->visible.obj != NULL && eLink->visible.obj != saved.visible.obj) { PerStateInfo_Free(tree, &pstBoolean, &eLink->visible); Tcl_DecrRefCount(eLink->visible.obj); } *eLink = saved; return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeStyleCmd -- * * This procedure is invoked to process the [style] widget * command. See the user documentation for details on what it * does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeStyleCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; static CONST char *commandNames[] = { "cget", "configure", "create", "delete", "elements", "layout", "names", (char *) NULL }; enum { COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_CREATE, COMMAND_DELETE, COMMAND_ELEMENTS, COMMAND_LAYOUT, COMMAND_NAMES }; int index; TreeStyle _style; MStyle *style; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case COMMAND_CGET: { Tcl_Obj *resultObjPtr; if (objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "name option"); return TCL_ERROR; } if (TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK) return TCL_ERROR; style = (MStyle *) _style; /* Hack -- allow [cget -statedomain] but not [configure] */ { int length; CONST char *s = Tcl_GetStringFromObj(objv[4], &length); /* FIXME: Check for minimum # unique chars. */ if (strncmp(s, "-statedomain", length) == 0 && length >= 7) { Tcl_SetObjResult(interp, Tcl_NewStringObj( tree->stateDomain[style->stateDomain].name, -1)); break; } } resultObjPtr = Tk_GetOptionValue(interp, (char *) style, tree->styleOptionTable, objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } case COMMAND_CONFIGURE: { Tcl_Obj *resultObjPtr = NULL; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "name ?option? ?value option value ...?"); return TCL_ERROR; } if (TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK) return TCL_ERROR; style = (MStyle *) _style; if (objc <= 5) { resultObjPtr = Tk_GetOptionInfo(interp, (char *) style, tree->styleOptionTable, (objc == 4) ? (Tcl_Obj *) NULL : objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); } else { if (Tk_SetOptions(tree->interp, (char *) style, tree->styleOptionTable, objc - 4, objv + 4, tree->tkwin, NULL, NULL) != TCL_OK) return TCL_ERROR; Style_Changed(tree, style); } break; } case COMMAND_CREATE: { char *name; int len; Tcl_HashEntry *hPtr; int isNew; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "name ?option value ...?"); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[3], &len); if (!len) { FormatResult(interp, "invalid style name \"\""); return TCL_ERROR; } hPtr = Tcl_FindHashEntry(&tree->styleHash, name); if (hPtr != NULL) { FormatResult(interp, "style \"%s\" already exists", name); return TCL_ERROR; } style = Style_CreateAndConfig(tree, name, objc - 4, objv + 4); if (style == NULL) return TCL_ERROR; hPtr = Tcl_CreateHashEntry(&tree->styleHash, name, &isNew); Tcl_SetHashValue(hPtr, style); Tcl_SetObjResult(interp, TreeStyle_ToObj((TreeStyle) style)); break; } case COMMAND_DELETE: { int i; if (objc < 3) { Tcl_WrongNumArgs(interp, 3, objv, "?name ...?"); return TCL_ERROR; } for (i = 3; i < objc; i++) { if (TreeStyle_FromObj(tree, objv[i], &_style) != TCL_OK) return TCL_ERROR; Style_Deleted(tree, (MStyle *) _style); TreeStyle_FreeResources(tree, _style); } break; } /* T style elements S ?{E ...}? */ case COMMAND_ELEMENTS: { TreeElement elem, *elemList = NULL; int i, j, count = 0; int staticMap[STATIC_SIZE], *map = staticMap; int listObjc; Tcl_Obj **listObjv; if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 3, objv, "name ?elementList?"); return TCL_ERROR; } if (TreeStyle_FromObj(tree, objv[3], &_style) != TCL_OK) return TCL_ERROR; style = (MStyle *) _style; if (objc == 5) { if (Tcl_ListObjGetElements(interp, objv[4], &listObjc, &listObjv) != TCL_OK) return TCL_ERROR; if (listObjc > 0) elemList = (TreeElement *) ckalloc(sizeof(TreeElement_) * listObjc); for (i = 0; i < listObjc; i++) { if (TreeElement_FromObj(tree, listObjv[i], &elem) != TCL_OK) { ckfree((char *) elemList); return TCL_ERROR; } if (elem->stateDomain != style->stateDomain) { FormatResult(interp, "state domain conflict between style \"%s\" and element \"%s\"", style->name, elem->name); ckfree((char *) elemList); return TCL_ERROR; } /* Ignore duplicate elements */ for (j = 0; j < count; j++) { if (elemList[j] == elem) break; } if (j < count) continue; elemList[count++] = elem; } STATIC_ALLOC(map, int, count); for (i = 0; i < count; i++) map[i] = -1; /* Reassigning Elements to a Style */ if (style->numElements > 0) { /* Check each Element */ for (i = 0; i < count; i++) { /* See if this Element is already used by the Style */ for (j = 0; j < style->numElements; j++) { if (elemList[i] == style->elements[j].elem) { /* Preserve it */ map[i] = j; break; } } } } Style_ChangeElements(tree, style, count, elemList, map); if (elemList != NULL) ckfree((char *) elemList); STATIC_FREE(map, int, count); break; } TreeStyle_ListElements(tree, (TreeStyle) style); break; } /* T style layout S E ?option? ?value? ?option value ...? */ case COMMAND_LAYOUT: { return StyleLayoutCmd(clientData, interp, objc, objv); } case COMMAND_NAMES: { Tcl_Obj *listObj; Tcl_HashSearch search; Tcl_HashEntry *hPtr; listObj = Tcl_NewListObj(0, NULL); hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search); while (hPtr != NULL) { _style = (TreeStyle) Tcl_GetHashValue(hPtr); if (!((MStyle *)_style)->hidden) Tcl_ListObjAppendElement(interp, listObj, TreeStyle_ToObj(_style)); hPtr = Tcl_NextHashEntry(&search); } Tcl_SetObjResult(interp, listObj); break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tree_ButtonMaxSize -- * * Return the maximum possible size of a button in any state. This * includes the size of the -buttonimage and -buttonbitmap options, * as well as the theme button and default +/- button. * * Results: * Pixel size >= 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_ButtonMaxSize( TreeCtrl *tree, /* Widget info. */ int *maxWidth, /* Returned maximum width. */ int *maxHeight /* Returned maximum height. */ ) { int w, h, width = 0, height = 0; PerStateImage_MaxSize(tree, &tree->buttonImage, &w, &h); width = MAX(width, w); height = MAX(height, h); PerStateBitmap_MaxSize(tree, &tree->buttonBitmap, &w, &h); width = MAX(width, w); height = MAX(height, h); if (tree->useTheme) { if (TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin), TRUE, &w, &h) == TCL_OK) { width = MAX(width, w); height = MAX(height, h); } if (TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin), FALSE, &w, &h) == TCL_OK) { width = MAX(width, w); height = MAX(height, h); } } (*maxWidth) = MAX(width, tree->buttonSize); (*maxHeight) = MAX(height, tree->buttonSize); } /* *---------------------------------------------------------------------- * * Tree_ButtonHeight -- * * Return the size of a button for a certain state. * * Results: * Pixel size >= 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tree_ButtonHeight( TreeCtrl *tree, /* Widget info. */ int state /* STATE_xxx flags. */ ) { Tk_Image image; Pixmap bitmap; int w, h; image = PerStateImage_ForState(tree, &tree->buttonImage, state, NULL); if (image != NULL) { Tk_SizeOfImage(image, &w, &h); return h; } bitmap = PerStateBitmap_ForState(tree, &tree->buttonBitmap, state, NULL); if (bitmap != None) { Tk_SizeOfBitmap(tree->display, bitmap, &w, &h); return h; } if (tree->useTheme && TreeTheme_GetButtonSize(tree, Tk_WindowId(tree->tkwin), (state & STATE_ITEM_OPEN) != 0, &w, &h) == TCL_OK) return h; return tree->buttonSize; } /* *---------------------------------------------------------------------- * * TreeStyle_Identify -- * * Perform hit-testing on a style. * * Results: * The element containing the given point, or NULL. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeElement TreeStyle_Identify( StyleDrawArgs *drawArgs, /* Various args. */ int x, /* Window x-coord to hit-test against. */ int y /* Window y-coord to hit-test against. */ ) { TreeCtrl *tree = drawArgs->tree; IStyle *style = (IStyle *) drawArgs->style; MStyle *masterStyle = style->master; int state = drawArgs->state; IElementLink *eLink = NULL; int i, minWidth, minHeight; struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; Style_CheckNeededSize(tree, style, state); #ifdef CACHE_STYLE_SIZE minWidth = style->minWidth; minHeight = style->minHeight; #else Style_MinSize(tree, style, state, &minWidth, &minHeight); #endif if (drawArgs->width < minWidth + drawArgs->indent) drawArgs->width = minWidth + drawArgs->indent; if (drawArgs->height < minHeight) drawArgs->height = minHeight; x -= drawArgs->x; STATIC_ALLOC(layouts, struct Layout, masterStyle->numElements); Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__); for (i = style->master->numElements - 1; i >= 0; i--) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink = layout->eLink; if ((x >= layout->x + layout->ePadX[PAD_TOP_LEFT]) && (x < layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth) && (y >= layout->y + layout->ePadY[PAD_TOP_LEFT]) && (y < layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight)) { goto done; } } eLink = NULL; done: STATIC_FREE(layouts, struct Layout, masterStyle->numElements); if (eLink != NULL) return eLink->elem; return NULL; } /* *---------------------------------------------------------------------- * * TreeStyle_Identify2 -- * * Return a list of elements overlapping the given area. * * Results: * The names of any elements overlapping the given area are * appended to the supplied list. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ void TreeStyle_Identify2( StyleDrawArgs *drawArgs, /* Various args. */ int x1, int y1, /* Top-left of area to hit-test. */ int x2, int y2, /* Bottom-right of area to hit-test. */ Tcl_Obj *listObj /* Initialized list object to hold * the result. */ ) { TreeCtrl *tree = drawArgs->tree; IStyle *style = (IStyle *) drawArgs->style; MStyle *masterStyle = style->master; int state = drawArgs->state; IElementLink *eLink; int i, minWidth, minHeight; struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; Style_CheckNeededSize(tree, style, state); #ifdef CACHE_STYLE_SIZE minWidth = style->minWidth; minHeight = style->minHeight; #else Style_MinSize(tree, style, state, &minWidth, &minHeight); #endif if (drawArgs->width < minWidth + drawArgs->indent) drawArgs->width = minWidth + drawArgs->indent; if (drawArgs->height < minHeight) drawArgs->height = minHeight; STATIC_ALLOC(layouts, struct Layout, masterStyle->numElements); Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__); for (i = style->master->numElements - 1; i >= 0; i--) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; eLink = layout->eLink; if ((drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT] < x2) && (drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT] + layout->iWidth > x1) && (drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT] < y2) && (drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT] + layout->iHeight > y1)) { Tcl_ListObjAppendElement(drawArgs->tree->interp, listObj, Tcl_NewStringObj(eLink->elem->name, -1)); } } STATIC_FREE(layouts, struct Layout, masterStyle->numElements); } /* *---------------------------------------------------------------------- * * TreeStyle_Remap -- * * The guts of the [item style map] command. See the user * documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeStyle_Remap( TreeCtrl *tree, /* Widget info. */ TreeStyle styleFrom_, /* Current instance style. */ TreeStyle styleTo_, /* Master style to "convert" the current * style to. */ int objc, /* Must be even number. */ Tcl_Obj *CONST objv[] /* Array of old-new element names. */ ) { IStyle *styleFrom = (IStyle *) styleFrom_; MStyle *styleTo = (MStyle *) styleTo_; int i, indexFrom, indexTo; int staticMap[STATIC_SIZE], *map = staticMap; IElementLink *eLink; TreeElement elemFrom, elemTo; TreeElement staticElemMap[STATIC_SIZE], *elemMap = staticElemMap; int styleFromNumElements = styleFrom->master->numElements; int result = TCL_OK; /* Must be instance */ if ((styleFrom == NULL) || (styleFrom->master == NULL)) return TCL_ERROR; /* Must be master */ if ((styleTo == NULL) || (styleTo->master != NULL)) return TCL_ERROR; /* Nothing to do */ if (styleFrom->master == styleTo) return TCL_OK; if (objc & 1) return TCL_ERROR; STATIC_ALLOC(map, int, styleFromNumElements); STATIC_ALLOC(elemMap, TreeElement, styleFromNumElements); for (i = 0; i < styleFromNumElements; i++) map[i] = -1; for (i = 0; i < objc; i += 2) { /* Get the old-style element */ if (TreeElement_FromObj(tree, objv[i], &elemFrom) != TCL_OK) { result = TCL_ERROR; goto done; } /* Verify the old style uses the element */ if (MStyle_FindElem(tree, styleFrom->master, elemFrom, &indexFrom) == NULL) { FormatResult(tree->interp, "style %s does not use element %s", styleFrom->master->name, elemFrom->name); result = TCL_ERROR; goto done; } /* Get the new-style element */ if (TreeElement_FromObj(tree, objv[i + 1], &elemTo) != TCL_OK) { result = TCL_ERROR; goto done; } /* Verify the new style uses the element */ if (MStyle_FindElem(tree, styleTo, elemTo, &indexTo) == NULL) { FormatResult(tree->interp, "style %s does not use element %s", styleTo->name, elemTo->name); result = TCL_ERROR; goto done; } /* Must be the same type */ if (elemFrom->typePtr != elemTo->typePtr) { FormatResult(tree->interp, "can't map element type %s to %s", elemFrom->typePtr->name, elemTo->typePtr->name); result = TCL_ERROR; goto done; } /* See if the instance style has any info for this element */ eLink = &styleFrom->elements[indexFrom]; if (eLink->elem->master != NULL) { map[indexFrom] = indexTo; elemMap[indexFrom] = eLink->elem; } } for (i = 0; i < styleFromNumElements; i++) { eLink = &styleFrom->elements[i]; indexTo = map[i]; /* Free info for any Elements not being remapped */ if ((indexTo == -1) && (eLink->elem->master != NULL)) { elemFrom = eLink->elem->master; Element_FreeResources(tree, eLink->elem); eLink->elem = elemFrom; } /* Remap this Element */ if (indexTo != -1) { elemMap[i]->master = styleTo->elements[indexTo].elem; elemMap[i]->name = styleTo->elements[indexTo].elem->name; } } if (styleFromNumElements != styleTo->numElements) { #ifdef ALLOC_HAX if (styleFromNumElements > 0) TreeAlloc_CFree(tree->allocData, IElementLinkUid, (char *) styleFrom->elements, sizeof(IElementLink), styleFromNumElements, ELEMENT_LINK_ROUND); styleFrom->elements = (IElementLink *) TreeAlloc_CAlloc(tree->allocData, IElementLinkUid, sizeof(IElementLink), styleTo->numElements, ELEMENT_LINK_ROUND); #else if (styleFromNumElements > 0) WCFREE(styleFrom->elements, IElementLink, styleFromNumElements); styleFrom->elements = (IElementLink *) ckalloc(sizeof(IElementLink) * styleTo->numElements); #endif memset(styleFrom->elements, '\0', sizeof(IElementLink) * styleTo->numElements); } for (i = 0; i < styleTo->numElements; i++) { styleFrom->elements[i].elem = styleTo->elements[i].elem; #ifdef CACHE_ELEM_SIZE styleFrom->elements[i].neededWidth = -1; styleFrom->elements[i].neededHeight = -1; #endif } for (i = 0; i < styleFromNumElements; i++) { indexTo = map[i]; if (indexTo != -1) styleFrom->elements[indexTo].elem = elemMap[i]; } styleFrom->master = styleTo; styleFrom->neededWidth = styleFrom->neededHeight = -1; done: STATIC_FREE(map, int, styleFromNumElements); STATIC_FREE(elemMap, TreeElement, styleFromNumElements); return result; } /* *---------------------------------------------------------------------- * * TreeStyle_GetSortData -- * * Called by the [item sort] code. Returns a long, double or * string value from a text element. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_GetSortData( TreeCtrl *tree, /* Widget info. */ TreeStyle style_, /* The style. */ int elemIndex, /* Index of a text element, or -1 to use * the first text element. */ int type, /* SORT_xxx constant. */ long *lv, /* Returned for SORT_LONG. */ double *dv, /* Returned for SORT_DOUBLE. */ char **sv /* Returned for SORT_ASCII or SORT_DICT. */ ) { IStyle *style = (IStyle *) style_; IElementLink *eLink = style->elements; int i; if (elemIndex == -1) { for (i = 0; i < style->master->numElements; i++) { if (ELEMENT_TYPE_MATCHES(eLink->elem->typePtr, &treeElemTypeText)) return TreeElement_GetSortData(tree, eLink->elem, type, lv, dv, sv); eLink++; } } else { if ((elemIndex < 0) || (elemIndex >= style->master->numElements)) panic("bad elemIndex %d to TreeStyle_GetSortData", elemIndex); eLink = &style->elements[elemIndex]; if (ELEMENT_TYPE_MATCHES(eLink->elem->typePtr, &treeElemTypeText)) return TreeElement_GetSortData(tree, eLink->elem, type, lv, dv, sv); } FormatResult(tree->interp, "can't find text element in style %s", style->master->name); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeStyle_GetElemRects -- * * Return a list of rectangles for specified elements in a style. * * Results: * The number of rects[] written. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_GetElemRects( StyleDrawArgs *drawArgs, /* Various args. */ int objc, /* Number of element names. */ Tcl_Obj *CONST objv[], /* Array of element names. */ TreeRectangle rects[] /* Returned rectangles. */ ) { IStyle *style = (IStyle *) drawArgs->style; MStyle *master = style->master; int i, j, count = 0, minWidth, minHeight; struct Layout staticLayouts[STATIC_SIZE], *layouts = staticLayouts; TreeElement staticElems[STATIC_SIZE], *elems = staticElems; MElementLink *eLink; STATIC_ALLOC(elems, TreeElement, objc); for (j = 0; j < objc; j++) { if (TreeElement_FromObj(drawArgs->tree, objv[j], &elems[j]) != TCL_OK) { count = -1; goto done; } eLink = MStyle_FindElem(drawArgs->tree, master, elems[j], NULL); if (eLink == NULL) { FormatResult(drawArgs->tree->interp, "style %s does not use element %s", master->name, elems[j]->name); count = -1; goto done; } } Style_CheckNeededSize(drawArgs->tree, style, drawArgs->state); #ifdef CACHE_STYLE_SIZE minWidth = style->minWidth; minHeight = style->minHeight; #else Style_MinSize(drawArgs->tree, style, drawArgs->state, &minWidth, &minHeight); #endif if (drawArgs->width < minWidth + drawArgs->indent) drawArgs->width = minWidth + drawArgs->indent; if (drawArgs->height < minHeight) drawArgs->height = minHeight; STATIC_ALLOC(layouts, struct Layout, master->numElements); Style_DoLayout(drawArgs, layouts, FALSE, __FILE__, __LINE__); for (i = master->numElements - 1; i >= 0; i--) { struct Layout *layout = &layouts[i]; if (IS_HIDDEN(layout)) continue; if (objc > 0) { for (j = 0; j < objc; j++) if (elems[j] == layout->eLink->elem || elems[j] == layout->master->elem) break; if (j == objc) continue; } rects[count].x = drawArgs->x + layout->x + layout->ePadX[PAD_TOP_LEFT]; rects[count].y = drawArgs->y + layout->y + layout->ePadY[PAD_TOP_LEFT]; if (layout->master->onion == NULL) { rects[count].x += layout->iPadX[PAD_TOP_LEFT]; rects[count].y += layout->iPadY[PAD_TOP_LEFT]; rects[count].width = layout->useWidth; rects[count].height = layout->useHeight; } else { rects[count].width = layout->iWidth; rects[count].height = layout->iHeight; } count++; } STATIC_FREE(layouts, struct Layout, master->numElements); done: STATIC_FREE(elems, TreeElement, objc); return count; } /* *---------------------------------------------------------------------- * * TreeStyle_ChangeState -- * * Called when the state of an item or item-column changes. * * Results: * A bitmask of CS_DISPLAY and CS_LAYOUT values. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_ChangeState( TreeCtrl *tree, /* Widget info. */ TreeStyle style_, /* The instance style. */ int state1, /* The previous state. */ int state2 /* The current state. */ ) { IStyle *style = (IStyle *) style_; MStyle *masterStyle = style->master; MElementLink *eLink1; IElementLink *eLink2; TreeElementArgs args; int i, eMask, mask = 0; int undisplay; if (state1 == state2) return 0; args.tree = tree; for (i = 0; i < masterStyle->numElements; i++) { eLink2 = &style->elements[i]; args.elem = eLink2->elem; args.states.state1 = state1; args.states.state2 = state2; args.states.draw1 = args.states.draw2 = TRUE; args.states.visible1 = args.states.visible2 = TRUE; eLink1 = &masterStyle->elements[i]; undisplay = FALSE; eMask = 0; /* Check for the style layout option -draw changing. */ if (eLink1->draw.count > 0) { args.states.draw1 = PerStateBoolean_ForState(tree, &eLink1->draw, state1, NULL) != 0; args.states.draw2 = PerStateBoolean_ForState(tree, &eLink1->draw, state2, NULL) != 0; if (args.states.draw1 != args.states.draw2) { eMask |= CS_DISPLAY; if (!args.states.draw2) undisplay = TRUE; } } /* Check for the style layout option -visible changing. */ if (eLink1->visible.count > 0) { args.states.visible1 = PerStateBoolean_ForState(tree, &eLink1->visible, state1, NULL) != 0; args.states.visible2 = PerStateBoolean_ForState(tree, &eLink1->visible, state2, NULL) != 0; /* FIXME: Changing visibility might not change the layout. */ if (args.states.visible1 != args.states.visible2) { eMask |= CS_DISPLAY | CS_LAYOUT; if (!args.states.visible2) undisplay = TRUE; } } /* Tell the element about the state change. */ eMask |= (*args.elem->typePtr->stateProc)(&args); /* Hack: If a window element becomes hidden, then tell it it is * not onscreen, otherwise it will never be "drawn" in the * hidden state. */ if (undisplay && ELEMENT_TYPE_MATCHES(args.elem->typePtr, &treeElemTypeWindow)) { args.screen.visible = FALSE; (*args.elem->typePtr->onScreenProc)(&args); } if (eMask) { #ifdef CACHE_ELEM_SIZE if (eMask & CS_LAYOUT) eLink2->neededWidth = eLink2->neededHeight = -1; #endif mask |= eMask; } } if (mask & CS_LAYOUT) style->neededWidth = style->neededHeight = -1; #ifdef TREECTRL_DEBUG if (style->neededWidth != -1) style->neededState = state2; #endif return mask; } /* *---------------------------------------------------------------------- * * Tree_UndefineState -- * * The guts of the [state undefine] widget command. * * Results: * The undefProc of every element is called to respond to the * undefined state flag. The size of every element/column/item is * marked out-of-date regardless of whether the state change * affected the element. * * Side effects: * Display changes. * *---------------------------------------------------------------------- */ void Tree_UndefineState( TreeCtrl *tree, /* Widget info. */ int domain, /* STATE_DOMAIN_XXX index. */ int state /* STATE_xxx flag. */ ) { TreeItem item; TreeItemColumn column; Tcl_HashTable *tablePtr = &tree->itemHash; Tcl_HashEntry *hPtr; Tcl_HashSearch search; IElementLink *eLink; int i, columnIndex; TreeElementArgs args; /* Undefine the state for the -draw and -visible style layout * options for each element of this style. */ hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search); while (hPtr != NULL) { MStyle *masterStyle = (MStyle *) Tcl_GetHashValue(hPtr); for (i = 0; i < masterStyle->numElements; i++) { MElementLink *eLink1 = &masterStyle->elements[i]; PerStateInfo_Undefine(tree, &pstBoolean, &eLink1->draw, masterStyle->stateDomain, state); PerStateInfo_Undefine(tree, &pstBoolean, &eLink1->visible, masterStyle->stateDomain, state); } hPtr = Tcl_NextHashEntry(&search); } args.tree = tree; args.state = state; hPtr = Tcl_FirstHashEntry(tablePtr, &search); if (hPtr == NULL) { tablePtr = &tree->headerHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } while (hPtr != NULL) { item = (TreeItem) Tcl_GetHashValue(hPtr); column = TreeItem_GetFirstColumn(tree, item); columnIndex = 0; while (column != NULL) { IStyle *style = (IStyle *) TreeItemColumn_GetStyle(tree, column); if (style != NULL) { for (i = 0; i < style->master->numElements; i++) { eLink = &style->elements[i]; /* Instance element */ if (eLink->elem->master != NULL) { args.elem = eLink->elem; (*args.elem->typePtr->undefProc)(&args); } #ifdef CACHE_ELEM_SIZE eLink->neededWidth = eLink->neededHeight = -1; #endif } style->neededWidth = style->neededHeight = -1; TreeItemColumn_InvalidateSize(tree, column); } columnIndex++; column = TreeItemColumn_GetNext(tree, column); } TreeItem_InvalidateHeight(tree, item); Tree_FreeItemDInfo(tree, item, NULL); TreeItem_UndefineState(tree, item, state); hPtr = Tcl_NextHashEntry(&search); if (hPtr == NULL && tablePtr == &tree->itemHash) { tablePtr = &tree->headerHash; hPtr = Tcl_FirstHashEntry(tablePtr, &search); } } TreeColumns_InvalidateWidthOfItems(tree, NULL); Tree_DInfoChanged(tree, DINFO_REDO_RANGES); hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search); while (hPtr != NULL) { args.elem = (TreeElement) Tcl_GetHashValue(hPtr); (*args.elem->typePtr->undefProc)(&args); hPtr = Tcl_NextHashEntry(&search); } } /* *---------------------------------------------------------------------- * * TreeStyle_NumElements -- * * Return the number of elements in a style. * * Results: * The number of... oh nevermind. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_NumElements( TreeCtrl *tree, /* Widget info. */ TreeStyle style_ /* The style. */ ) { MStyle *masterStyle = ((MStyle *) style_); IStyle *style = ((IStyle *) style_); return (style->master == NULL) ? masterStyle->numElements : style->master->numElements; } /* *---------------------------------------------------------------------- * * TreeStyle_IsHeaderStyle -- * * Determine if a style was created by Tree_MakeHeaderStyle for use * in column headers. * * Results: * TRUE if the style was created by the widget itself, FALSE if * it was created by [style create]. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_IsHeaderStyle( TreeCtrl *tree, /* Widget info. */ TreeStyle style /* The style. */ ) { #if 1 if (((IStyle *)style)->master != NULL) style = TreeStyle_GetMaster(tree, style); /* Faster check. */ return ((MStyle *) style)->hidden; #else HeaderStyle *hs; if (((IStyle *)style)->master != NULL) style = TreeStyle_GetMaster(tree, style); for (hs = tree->headerStyle.first; hs != NULL; hs = hs->next) { if (hs->style == style) return TRUE; } #endif return FALSE; } /* *---------------------------------------------------------------------- * * TreeStyle_HasHeaderElement -- * * Determine if a style has a 'header' type element. * * Results: * TRUE if the style has a 'header' type element, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_HasHeaderElement( TreeCtrl *tree, /* Widget info. */ TreeStyle style /* The style. */ ) { MStyle *mstyle = (MStyle *) style; if (mstyle->master != NULL) mstyle = (MStyle *) mstyle->master; return mstyle->hasHeaderElem; } /* *---------------------------------------------------------------------- * * Tree_MakeHeaderStyle -- * * Returns a master style suitable for use in a column header. * If a style meeting the requirements exists, it is returned. * Otherwise, a new style is created with a 'header' element * and possibly a bitmap, image, and/or text element. * * Note that the any styles and elements created by this function * are hidden from the user. * * Results: * A master style token. * * Side effects: * None. * *---------------------------------------------------------------------- */ TreeStyle Tree_MakeHeaderStyle( TreeCtrl *tree, /* Widget info. */ HeaderStyleParams *params /* Acts as a unique signature for the * style. */ ) { HeaderStyle *hs; int i, count = 0, map[4], isNew; char name[64]; MStyle *style; TreeElement elem, elements[4]; MElementLink *eLink; Tcl_HashEntry *hPtr; if (params->image) params->bitmap = 0; if (!params->image && !params->bitmap) { params->imagePadX[0] = params->imagePadX[1] = 0; params->imagePadY[0] = params->imagePadY[1] = 0; } if (!params->text) { params->textPadX[0] = params->textPadX[1] = 0; params->textPadY[0] = params->textPadY[1] = 0; } for (hs = tree->headerStyle.first; hs != NULL; hs = hs->next) { if (hs->params.justify != params->justify) continue; if (hs->params.bitmap != params->bitmap) continue; if (hs->params.image != params->image) continue; if (hs->params.text != params->text) continue; for (i = 0; i < 2; i++) { if (hs->params.imagePadX[i] != params->imagePadX[i]) break; if (hs->params.imagePadY[i] != params->imagePadY[i]) break; if (hs->params.textPadX[i] != params->textPadX[i]) break; if (hs->params.textPadY[i] != params->textPadY[i]) break; } if (i < 2) continue; break; } if (hs != NULL) { return hs->style; } /* Create the master elements shared by all header styles if they don't * exist. */ if (tree->headerStyle.headerElem == NULL) { Tcl_Obj *obj = Tcl_NewStringObj("header", -1); TreeElementType *typePtr; Tcl_IncrRefCount(obj); TreeElement_TypeFromObj(tree, obj, &typePtr); Tcl_DecrRefCount(obj); sprintf(name, "treectrl_header_elem.header"); elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name, 0, NULL); elem->hidden = TRUE; elem->stateDomain = STATE_DOMAIN_HEADER; hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew); Tcl_SetHashValue(hPtr, elem); tree->headerStyle.headerElem = elem; } if (tree->headerStyle.bitmapElem == NULL) { Tcl_Obj *obj = Tcl_NewStringObj("bitmap", -1); TreeElementType *typePtr; Tcl_IncrRefCount(obj); TreeElement_TypeFromObj(tree, obj, &typePtr); Tcl_DecrRefCount(obj); sprintf(name, "treectrl_header_elem.bitmap"); elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name, 0, NULL); elem->hidden = TRUE; elem->stateDomain = STATE_DOMAIN_HEADER; hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew); Tcl_SetHashValue(hPtr, elem); tree->headerStyle.bitmapElem = elem; } if (tree->headerStyle.imageElem == NULL) { Tcl_Obj *obj = Tcl_NewStringObj("image", -1); TreeElementType *typePtr; Tcl_IncrRefCount(obj); TreeElement_TypeFromObj(tree, obj, &typePtr); Tcl_DecrRefCount(obj); sprintf(name, "treectrl_header_elem.image"); elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name, 0, NULL); elem->hidden = TRUE; elem->stateDomain = STATE_DOMAIN_HEADER; hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew); Tcl_SetHashValue(hPtr, elem); tree->headerStyle.imageElem = elem; } if (tree->headerStyle.textElem == NULL) { Tcl_Obj *obj = Tcl_NewStringObj("text", -1); TreeElementType *typePtr; Tcl_IncrRefCount(obj); TreeElement_TypeFromObj(tree, obj, &typePtr); Tcl_DecrRefCount(obj); sprintf(name, "treectrl_header_elem.text"); elem = Element_CreateAndConfig(tree, NULL, NULL, NULL, typePtr, name, 0, NULL); elem->hidden = TRUE; elem->stateDomain = STATE_DOMAIN_HEADER; hPtr = Tcl_CreateHashEntry(&tree->elementHash, name, &isNew); Tcl_SetHashValue(hPtr, elem); tree->headerStyle.textElem = elem; } sprintf(name, "treectrl_header_style_%d", tree->headerStyle.nextId); style = Style_CreateAndConfig(tree, name, 0, NULL); style->hidden = TRUE; style->stateDomain = STATE_DOMAIN_HEADER; hPtr = Tcl_CreateHashEntry(&tree->styleHash, name, &isNew); Tcl_SetHashValue(hPtr, style); /* Alloc element list. */ elements[count++] = tree->headerStyle.headerElem; if (params->bitmap) elements[count++] = tree->headerStyle.bitmapElem; if (params->image) elements[count++] = tree->headerStyle.imageElem; if (params->text) elements[count++] = tree->headerStyle.textElem; map[0] = map[1] = map[2] = map[3] = -1; MStyle_ChangeElementsAux(tree, style, count, elements, map); /* Layout. */ eLink = &style->elements[0]; /* header */ if (count > 1) { eLink->onionCount = count - 1; eLink->onion = (int *) ckalloc(sizeof(int) * eLink->onionCount); for (i = 1; i < count; i++) eLink->onion[i - 1] = i; eLink->flags |= ELF_iEXPAND; /* wens */ eLink->flags &= ~ELF_INDENT; } else { eLink->flags |= ELF_DETACH | ELF_iEXPAND_X | ELF_iEXPAND_Y; eLink->flags &= ~ELF_INDENT; } if (params->bitmap || params->image) { eLink = &style->elements[1]; for (i = 0; i < 2; i++) { eLink->ePadX[i] = params->imagePadX[i]; eLink->ePadY[i] = params->imagePadY[i]; } eLink->flags |= ELF_eEXPAND_NS; if (params->justify == TK_JUSTIFY_CENTER) eLink->flags |= ELF_CENTER_X; else if (params->justify == TK_JUSTIFY_RIGHT) eLink->flags |= ELF_eEXPAND_W; } if (params->text) { eLink = &style->elements[1 + (params->bitmap || params->image)]; for (i = 0; i < 2; i++) { eLink->ePadX[i] = params->textPadX[i]; eLink->ePadY[i] = params->textPadY[i]; } eLink->ePadX[0] = MAX(params->textPadX[0] - params->imagePadX[1], 0); eLink->flags |= ELF_SQUEEZE_X | ELF_eEXPAND_NS; if (params->justify == TK_JUSTIFY_CENTER) eLink->flags |= ELF_CENTER_X; else if (!(params->bitmap || params->image) && (params->justify == TK_JUSTIFY_RIGHT)) eLink->flags |= ELF_eEXPAND_W; } hs = (HeaderStyle *) ckalloc(sizeof(HeaderStyle)); hs->style = (TreeStyle) style; hs->params = *params; hs->next = tree->headerStyle.first; tree->headerStyle.first = hs; tree->headerStyle.nextId++; return hs->style; } /* *---------------------------------------------------------------------- * * TreeStyle_InitWidget -- * * Style-related package initialization. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeStyle_InitWidget( TreeCtrl *tree /* Widget info. */ ) { #ifdef TREECTRL_DEBUG if (STICKY_W != ELF_STICKY_W || STICKY_E != ELF_STICKY_E || STICKY_N != ELF_STICKY_N || STICKY_S != ELF_STICKY_S) panic("STICKY_XYZ != ELF_STICKY_XYZ"); #endif tree->styleOptionTable = Tk_CreateOptionTable(tree->interp, styleOptionSpecs); tree->imageOptionNameObj = Tcl_NewStringObj("-image", -1); Tcl_IncrRefCount(tree->imageOptionNameObj); tree->textOptionNameObj = Tcl_NewStringObj("-text", -1); Tcl_IncrRefCount(tree->textOptionNameObj); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeStyle_FreeWidget -- * * Free style-related resources for a deleted TreeCtrl. * * Results: * None. * * Side effects: * Memory is freed. * *---------------------------------------------------------------------- */ void TreeStyle_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { Tcl_HashEntry *hPtr; Tcl_HashSearch search; TreeElement elem; TreeStyle style; while (1) { hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search); if (hPtr == NULL) break; style = (TreeStyle) Tcl_GetHashValue(hPtr); TreeStyle_FreeResources(tree, style); } while (1) { hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search); if (hPtr == NULL) break; elem = (TreeElement) Tcl_GetHashValue(hPtr); Element_FreeResources(tree, elem); } Tcl_DeleteHashTable(&tree->elementHash); Tcl_DeleteHashTable(&tree->styleHash); Tcl_DecrRefCount(tree->imageOptionNameObj); Tcl_DecrRefCount(tree->textOptionNameObj); while (tree->headerStyle.first != NULL) { HeaderStyle *next = tree->headerStyle.first->next; ckfree((char *) tree->headerStyle.first); tree->headerStyle.first = next; } } tktreectrl-2.4.1/generic/tkTreeTheme.c0000644000076400010400000003700311562310762020222 0ustar TimAdministrators/* * tkTreeTheme.c -- * * This module implements visual themes. * * Copyright (c) 2005-2011 Tim Baker */ #ifdef USE_TTK #include "tkTreeCtrl.h" #include "ttk/ttkTheme.h" #include "ttk/ttk-extra.h" typedef struct TreeThemeData_ { Ttk_Layout layout; Ttk_Layout buttonLayout; Ttk_Layout headingLayout; Tk_OptionTable buttonOptionTable; Tk_OptionTable headingOptionTable; Ttk_Box clientBox; int buttonWidth[2], buttonHeight[2]; Ttk_Padding buttonPadding[2]; } TreeThemeData_; int TreeTheme_DrawHeaderItem(TreeCtrl *tree, Drawable drawable, int state, int arrow, int visIndex, int x, int y, int width, int height) { TreeThemeData themeData = tree->themeData; Ttk_Layout layout = themeData->headingLayout; Ttk_State ttk_state = 0; Ttk_Box box; if (layout == NULL) return TCL_ERROR; box = Ttk_MakeBox(x, y, width, height); switch (state) { case COLUMN_STATE_ACTIVE: ttk_state = TTK_STATE_ACTIVE; break; case COLUMN_STATE_PRESSED: ttk_state = TTK_STATE_PRESSED; break; } eTtk_RebindSublayout(layout, NULL); /* !!! rebind to column */ eTtk_PlaceLayout(layout, ttk_state, box); eTtk_DrawLayout(layout, ttk_state, drawable); return TCL_OK; } int TreeTheme_GetHeaderContentMargins(TreeCtrl *tree, int state, int arrow, int bounds[4]) { return TCL_ERROR; } int TreeTheme_DrawHeaderArrow(TreeCtrl *tree, Drawable drawable, int state, int up, int x, int y, int width, int height) { return TCL_ERROR; } /* From ttkTreeview.c */ #define TTK_STATE_OPEN TTK_STATE_USER1 int TreeTheme_DrawButton(TreeCtrl *tree, Drawable drawable, int open, int x, int y, int width, int height) { TreeThemeData themeData = tree->themeData; Ttk_Layout layout = themeData->buttonLayout; Ttk_State ttk_state = 0; Ttk_Box box; Ttk_Padding padding; if (layout == NULL) return TCL_ERROR; open = open ? 1 : 0; padding = themeData->buttonPadding[open]; x -= padding.left; y -= padding.top; width = themeData->buttonWidth[open]; height = themeData->buttonHeight[open]; box = Ttk_MakeBox(x, y, width, height); ttk_state = open ? TTK_STATE_OPEN : 0; eTtk_RebindSublayout(layout, NULL); /* !!! rebind to item */ eTtk_PlaceLayout(layout, ttk_state, box); eTtk_DrawLayout(layout, ttk_state, drawable); return TCL_OK; } int TreeTheme_GetButtonSize(TreeCtrl *tree, Drawable drawable, int open, int *widthPtr, int *heightPtr) { TreeThemeData themeData = tree->themeData; Ttk_Padding padding; if (themeData->buttonLayout == NULL) return TCL_ERROR; open = open ? 1 : 0; padding = themeData->buttonPadding[open]; *widthPtr = themeData->buttonWidth[open] - padding.left - padding.right; *heightPtr = themeData->buttonHeight[open] - padding.top - padding.bottom; return TCL_OK; } int TreeTheme_GetArrowSize(TreeCtrl *tree, Drawable drawable, int up, int *widthPtr, int *heightPtr) { return TCL_ERROR; } int TreeTheme_SetBorders(TreeCtrl *tree) { TreeThemeData themeData = tree->themeData; Tk_Window tkwin = tree->tkwin; Ttk_Box clientBox = themeData->clientBox; tree->inset.left = clientBox.x; tree->inset.top = clientBox.y; tree->inset.right = Tk_Width(tkwin) - (clientBox.x + clientBox.width); tree->inset.bottom = Tk_Height(tkwin) - (clientBox.y + clientBox.height); return TCL_OK; } /* * This routine is a big hack so that the "field" element (of the TreeCtrl * layout) doesn't erase the entire background of the window. This routine * draws each edge of the layout into a pixmap and copies the pixmap to the * window. */ int TreeTheme_DrawBorders( TreeCtrl *tree, Drawable drawable ) { TreeThemeData themeData = tree->themeData; Tk_Window tkwin = tree->tkwin; Ttk_Box winBox = Ttk_WinBox(tree->tkwin); Ttk_State state = 0; /* ??? */ int left, top, right, bottom; Drawable pixmapLR = None, pixmapTB = None; left = tree->inset.left; top = tree->inset.top; right = tree->inset.right; bottom = tree->inset.bottom; /* If the Ttk layout doesn't specify any borders or padding, then * draw nothing. */ if (left < 1 && top < 1 && right < 1 && bottom < 1) return TCL_OK; if (left > 0 || top > 0) eTtk_PlaceLayout(themeData->layout, state, winBox); if (left > 0 || right > 0) { pixmapLR = Tk_GetPixmap(tree->display, Tk_WindowId(tkwin), MAX(left, right), Tk_Height(tkwin), Tk_Depth(tkwin)); } if (top > 0 || bottom > 0) { pixmapTB = Tk_GetPixmap(tree->display, Tk_WindowId(tkwin), Tk_Width(tkwin), MAX(top, bottom), Tk_Depth(tkwin)); } /* DebugDrawBorder(tree, 0, left, top, right, bottom);*/ if (left > 0) { eTtk_DrawLayout(themeData->layout, state, pixmapLR); XCopyArea(tree->display, pixmapLR, drawable, tree->copyGC, 0, 0, left, Tk_Height(tkwin), 0, 0); } if (top > 0) { eTtk_DrawLayout(themeData->layout, state, pixmapTB); XCopyArea(tree->display, pixmapTB, drawable, tree->copyGC, 0, 0, Tk_Width(tkwin), top, 0, 0); } if (right > 0) { winBox.x -= winBox.width - right; eTtk_PlaceLayout(themeData->layout, state, winBox); eTtk_DrawLayout(themeData->layout, state, pixmapLR); XCopyArea(tree->display, pixmapLR, drawable, tree->copyGC, 0, 0, right, Tk_Height(tkwin), Tree_BorderRight(tree), 0); } if (bottom > 0) { winBox.x = 0; winBox.y -= winBox.height - bottom; eTtk_PlaceLayout(themeData->layout, state, winBox); eTtk_DrawLayout(themeData->layout, state, pixmapTB); XCopyArea(tree->display, pixmapTB, drawable, tree->copyGC, 0, 0, Tk_Width(tkwin), bottom, 0, Tree_BorderBottom(tree)); } if (pixmapLR != None) Tk_FreePixmap(tree->display, pixmapLR); if (pixmapTB != None) Tk_FreePixmap(tree->display, pixmapTB); return TCL_OK; } static Tk_OptionSpec NullOptionSpecs[] = { {TK_OPTION_END, 0,0,0, NULL, -1,-1, 0,0,0} }; /* from ttkTreeview.c */ static Ttk_Layout GetSublayout( Tcl_Interp *interp, Ttk_Theme themePtr, Ttk_Layout parentLayout, const char *layoutName, Tk_OptionTable optionTable, Ttk_Layout *layoutPtr) { Ttk_Layout newLayout = eTtk_CreateSublayout( interp, themePtr, parentLayout, layoutName, optionTable); if (newLayout) { if (*layoutPtr) eTtk_FreeLayout(*layoutPtr); *layoutPtr = newLayout; } return newLayout; } Ttk_Layout TreeCtrlGetLayout( Tcl_Interp *interp, Ttk_Theme themePtr, void *recordPtr ) { TreeCtrl *tree = recordPtr; TreeThemeData themeData = tree->themeData; Ttk_Layout treeLayout, newLayout; if (themeData->headingOptionTable == NULL) themeData->headingOptionTable = Tk_CreateOptionTable(interp, NullOptionSpecs); if (themeData->buttonOptionTable == NULL) themeData->buttonOptionTable = Tk_CreateOptionTable(interp, NullOptionSpecs); /* Create a new layout record based on widget -style or class */ treeLayout = eTtk_CreateLayout(interp, themePtr, "TreeCtrl", tree, tree->optionTable, tree->tkwin); /* Create a sublayout for drawing the column headers. The sublayout is * called "TreeCtrl.TreeCtrlHeading" by default. The actual layout specification * was defined by Ttk_RegisterLayout("TreeCtrlHeading") below. */ newLayout = GetSublayout(interp, themePtr, treeLayout, ".TreeCtrlHeading", themeData->headingOptionTable, &themeData->headingLayout); if (newLayout == NULL) return NULL; newLayout = GetSublayout(interp, themePtr, treeLayout, ".TreeCtrlButton", themeData->buttonOptionTable, &themeData->buttonLayout); if (newLayout == NULL) return NULL; return treeLayout; } void TreeCtrlDoLayout( void *recordPtr ) { TreeCtrl *tree = recordPtr; TreeThemeData themeData = tree->themeData; Ttk_LayoutNode *node; Ttk_Box winBox = Ttk_WinBox(tree->tkwin); Ttk_State state = 0; /* ??? */ eTtk_PlaceLayout(themeData->layout, state, winBox); node = eTtk_LayoutFindNode(themeData->layout, "client"); if (node != NULL) themeData->clientBox = eTtk_LayoutNodeInternalParcel(themeData->layout, node); else themeData->clientBox = winBox; /* Size of opened and closed buttons. */ eTtk_LayoutSize(themeData->buttonLayout, TTK_STATE_OPEN, &themeData->buttonWidth[1], &themeData->buttonHeight[1]); eTtk_LayoutSize(themeData->buttonLayout, 0, &themeData->buttonWidth[0], &themeData->buttonHeight[0]); node = eTtk_LayoutFindNode(themeData->buttonLayout, "indicator"); if (node != NULL) { Ttk_Box box1, box2; box1 = Ttk_MakeBox(0, 0, themeData->buttonWidth[1], themeData->buttonHeight[1]); eTtk_PlaceLayout(themeData->buttonLayout, TTK_STATE_OPEN, box1); box2 = eTtk_LayoutNodeInternalParcel(themeData->buttonLayout, node); themeData->buttonPadding[1] = Ttk_MakePadding(box2.x, box2.y, (box1.x + box1.width) - (box2.x + box2.width), (box1.y + box1.height) - (box2.y + box2.height)); box1 = Ttk_MakeBox(0, 0, themeData->buttonWidth[0], themeData->buttonHeight[0]); eTtk_PlaceLayout(themeData->buttonLayout, 0, box1); box2 = eTtk_LayoutNodeInternalParcel(themeData->buttonLayout, node); themeData->buttonPadding[0] = Ttk_MakePadding(box2.x, box2.y, (box1.x + box1.width) - (box2.x + box2.width), (box1.y + box1.height) - (box2.y + box2.height)); } else { themeData->buttonPadding[1] = Ttk_MakePadding(0,0,0,0); themeData->buttonPadding[0] = Ttk_MakePadding(0,0,0,0); } } void TreeTheme_Relayout( TreeCtrl *tree ) { TreeThemeData themeData = tree->themeData; Ttk_Theme themePtr = Ttk_GetCurrentTheme(tree->interp); Ttk_Layout newLayout = TreeCtrlGetLayout(tree->interp, themePtr, tree); if (newLayout) { if (themeData->layout) { eTtk_FreeLayout(themeData->layout); } themeData->layout = newLayout; TreeCtrlDoLayout(tree); } } /* HeaderElement is used for Treeheading.cell. The platform-specific code * will draw the native heading. */ typedef struct { Tcl_Obj *backgroundObj; } HeaderElement; static Ttk_ElementOptionSpec HeaderElementOptions[] = { { "-background", TK_OPTION_COLOR, Tk_Offset(HeaderElement, backgroundObj), DEFAULT_BACKGROUND }, {NULL} }; static void HeaderElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { HeaderElement *e = elementRecord; XColor *color = Tk_GetColorFromObj(tkwin, e->backgroundObj); GC gc = Tk_GCForColor(color, d); XFillRectangle(Tk_Display(tkwin), d, gc, b.x, b.y, b.width, b.height); } static Ttk_ElementSpec HeaderElementSpec = { TK_STYLE_VERSION_2, sizeof(HeaderElement), HeaderElementOptions, Ttk_NullElementGeometry, HeaderElementDraw }; /* Default button element (aka Treeitem.indicator). */ typedef struct { Tcl_Obj *backgroundObj; Tcl_Obj *colorObj; Tcl_Obj *sizeObj; Tcl_Obj *thicknessObj; } TreeitemIndicator; static Ttk_ElementOptionSpec TreeitemIndicatorOptions[] = { { "-buttonbackground", TK_OPTION_COLOR, Tk_Offset(TreeitemIndicator, backgroundObj), "white" }, { "-buttoncolor", TK_OPTION_COLOR, Tk_Offset(TreeitemIndicator, colorObj), "#808080" }, { "-buttonsize", TK_OPTION_PIXELS, Tk_Offset(TreeitemIndicator, sizeObj), "9" }, { "-buttonthickness", TK_OPTION_PIXELS, Tk_Offset(TreeitemIndicator, thicknessObj), "1" }, {NULL} }; static void TreeitemIndicatorSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { TreeitemIndicator *indicator = elementRecord; int size = 0; Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size); *widthPtr = *heightPtr = size; *paddingPtr = Ttk_MakePadding(0,0,0,0); } static void TreeitemIndicatorDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { TreeitemIndicator *indicator = elementRecord; int w1, lineLeft, lineTop, buttonLeft, buttonTop, buttonThickness, buttonSize; XColor *bgColor = Tk_GetColorFromObj(tkwin, indicator->backgroundObj); XColor *buttonColor = Tk_GetColorFromObj(tkwin, indicator->colorObj); XGCValues gcValues; unsigned long gcMask; GC buttonGC; Ttk_Padding padding = Ttk_MakePadding(0,0,0,0); b = Ttk_PadBox(b, padding); Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &buttonSize); Tk_GetPixelsFromObj(NULL, tkwin, indicator->thicknessObj, &buttonThickness); w1 = buttonThickness / 2; /* Left edge of vertical line */ /* Make sure this matches TreeItem_DrawLines() */ lineLeft = b.x + (b.width - buttonThickness) / 2; /* Top edge of horizontal line */ /* Make sure this matches TreeItem_DrawLines() */ lineTop = b.y + (b.height - buttonThickness) / 2; buttonLeft = b.x; buttonTop = b.y; /* Erase button background */ XFillRectangle(Tk_Display(tkwin), d, Tk_GCForColor(bgColor, d), buttonLeft + buttonThickness, buttonTop + buttonThickness, buttonSize - buttonThickness, buttonSize - buttonThickness); gcValues.foreground = buttonColor->pixel; gcValues.line_width = buttonThickness; gcMask = GCForeground | GCLineWidth; buttonGC = Tk_GetGC(tkwin, gcMask, &gcValues); /* Draw button outline */ XDrawRectangle(Tk_Display(tkwin), d, buttonGC, buttonLeft + w1, buttonTop + w1, buttonSize - buttonThickness, buttonSize - buttonThickness); /* Horizontal '-' */ XFillRectangle(Tk_Display(tkwin), d, buttonGC, buttonLeft + buttonThickness * 2, lineTop, buttonSize - buttonThickness * 4, buttonThickness); if (!(state & TTK_STATE_OPEN)) { /* Finish '+' */ XFillRectangle(Tk_Display(tkwin), d, buttonGC, lineLeft, buttonTop + buttonThickness * 2, buttonThickness, buttonSize - buttonThickness * 4); } Tk_FreeGC(Tk_Display(tkwin), buttonGC); } static Ttk_ElementSpec TreeitemIndicatorElementSpec = { TK_STYLE_VERSION_2, sizeof(TreeitemIndicator), TreeitemIndicatorOptions, TreeitemIndicatorSize, TreeitemIndicatorDraw }; TTK_BEGIN_LAYOUT(HeadingLayout) TTK_NODE("Treeheading.cell", TTK_FILL_BOTH) TTK_NODE("Treeheading.border", TTK_FILL_BOTH) TTK_END_LAYOUT TTK_BEGIN_LAYOUT(ButtonLayout) TTK_NODE("Treeitem.indicator", TTK_PACK_LEFT) TTK_END_LAYOUT TTK_BEGIN_LAYOUT(TreeCtrlLayout) TTK_GROUP("TreeCtrl.field", TTK_FILL_BOTH|TTK_BORDER, TTK_GROUP("TreeCtrl.padding", TTK_FILL_BOTH, TTK_NODE("TreeCtrl.client", TTK_FILL_BOTH))) TTK_END_LAYOUT void TreeTheme_ThemeChanged(TreeCtrl *tree) { } int TreeTheme_InitWidget(TreeCtrl *tree) { tree->themeData = (TreeThemeData) ckalloc(sizeof(TreeThemeData_)); memset(tree->themeData, '\0', sizeof(TreeThemeData_)); return TCL_OK; } int TreeTheme_FreeWidget(TreeCtrl *tree) { TreeThemeData themeData = tree->themeData; if (themeData != NULL) { if (themeData->layout != NULL) eTtk_FreeLayout(themeData->layout); if (themeData->buttonLayout != NULL) eTtk_FreeLayout(themeData->buttonLayout); if (themeData->headingLayout != NULL) eTtk_FreeLayout(themeData->headingLayout); ckfree((char *) themeData); } return TCL_OK; } int TreeTheme_InitInterp(Tcl_Interp *interp) { Ttk_Theme theme = Ttk_GetDefaultTheme(interp); Ttk_RegisterLayout(theme, "TreeCtrl", TreeCtrlLayout); /* Problem: what if Treeview also defines this? */ Ttk_RegisterElement(interp, theme, "Treeheading.cell", &HeaderElementSpec, 0); /* Problem: what if Treeview also defines this? */ Ttk_RegisterElement(interp, theme, "Treeitem.indicator", &TreeitemIndicatorElementSpec, 0); Ttk_RegisterLayout(theme, "TreeCtrlHeading", HeadingLayout); Ttk_RegisterLayout(theme, "TreeCtrlButton", ButtonLayout); return TCL_OK; } #endif /* USE_TTK */ tktreectrl-2.4.1/generic/tkTreeUtils.c0000644000076400010400000063040611645121643020266 0ustar TimAdministrators/* * tkTreeUtils.c -- * * This module implements misc routines for treectrl widgets. * * Copyright (c) 2002-2011 Tim Baker */ #include "tkTreeCtrl.h" struct dbwinterps { int count; #define DBWIN_MAX_INTERPS 16 Tcl_Interp *interps[DBWIN_MAX_INTERPS]; }; static Tcl_ThreadDataKey dbwinTDK; static CONST char *DBWIN_VAR_NAME = "dbwin"; static void dbwin_forget_interp(ClientData clientData, Tcl_Interp *interp) { struct dbwinterps *dbwinterps = Tcl_GetThreadData(&dbwinTDK, sizeof(struct dbwinterps)); int i; for (i = 0; i < dbwinterps->count; i++) { if (dbwinterps->interps[i] == interp) { for (; i < dbwinterps->count - 1; i++) { dbwinterps->interps[i] = dbwinterps->interps[i + 1]; } dbwinterps->count--; break; } } } void dbwin_add_interp(Tcl_Interp *interp) { struct dbwinterps *dbwinterps = Tcl_GetThreadData(&dbwinTDK, sizeof(struct dbwinterps)); if (dbwinterps->count < DBWIN_MAX_INTERPS) { dbwinterps->interps[dbwinterps->count++] = interp; Tcl_SetAssocData(interp, DBWIN_VAR_NAME, dbwin_forget_interp, NULL); } } void dbwin(char *fmt, ...) { struct dbwinterps *dbwinterps = Tcl_GetThreadData(&dbwinTDK, sizeof(struct dbwinterps)); char buf[512]; va_list args; int i; if (dbwinterps->count <= 0) return; va_start(args, fmt); vsnprintf(buf, 512, fmt, args); va_end(args); buf[511] = '\0'; for (i = 0; i < dbwinterps->count; i++) { /* All sorts of nasty stuff could happen here. */ Tcl_SetVar2(dbwinterps->interps[i], DBWIN_VAR_NAME, NULL, buf, TCL_GLOBAL_ONLY); } } #if defined(TREECTRL_DEBUG) #ifdef WIN32 #include #endif /* *---------------------------------------------------------------------- * * TreeCtrl_BreakIntoDebugger -- * * If running in a debugger, call DebugBreak(), otherwise * panic(). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeCtrl_BreakIntoDebugger( const char *file, int line ) { #if defined(WIN32) if (IsDebuggerPresent()) DebugBreak(); else #endif panic("Debugger call at %s:%d", file, line); } #endif /* TREECTRL_DEBUG */ /* * Forward declarations for procedures defined later in this file: */ static int PadAmountOptionSet _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags)); static Tcl_Obj *PadAmountOptionGet _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset)); static void PadAmountOptionRestore _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr)); static void PadAmountOptionFree _ANSI_ARGS_((ClientData clientData, Tk_Window tkwin, char *internalPtr)); /* * The following Tk_ObjCustomOption structure can be used as clientData entry * of a Tk_OptionSpec record with a TK_OPTION_CUSTOM type in the form * "(ClientData) &TreeCtrlCO_pad"; the option will then parse list with * one or two screen distances. */ Tk_ObjCustomOption TreeCtrlCO_pad = { "pad amount", PadAmountOptionSet, PadAmountOptionGet, PadAmountOptionRestore, PadAmountOptionFree }; /* *---------------------------------------------------------------------- * * FormatResult -- * * Set the interpreter's result to a formatted string. * * Results: * None. * * Side effects: * Interpreter's result is modified. * *---------------------------------------------------------------------- */ void FormatResult( Tcl_Interp *interp, /* Current interpreter. */ char *fmt, ... /* Format string and varargs. */ ) { va_list ap; char buf[256]; va_start(ap, fmt); vsprintf(buf, fmt, ap); va_end(ap); Tcl_SetResult(interp, buf, TCL_VOLATILE); } /* *---------------------------------------------------------------------- * * DStringAppendf -- * * Format a string and append it to a Tcl_DString. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void DStringAppendf( Tcl_DString *dString, /* Initialized dynamic string. */ char *fmt, ... /* Format string and varargs. */ ) { va_list ap; char buf[256]; va_start(ap, fmt); vsprintf(buf, fmt, ap); va_end(ap); Tcl_DStringAppend(dString, buf, -1); } /* *---------------------------------------------------------------------- * * Tree_Ellipsis -- * * Determine the number of bytes from the string that will fit * in the given horizontal span. If the entire string does not * fit then determine the largest number of bytes of a substring * with an ellipsis "..." appended that will fit. * * Results: * When the return value is equal to numBytes the caller should * not add the ellipsis to the string (unless force is TRUE). In * this case maxPixels contains the number of pixels for the entire * string (plus ellipsis if force is TRUE). * * When the return value is less than numBytes the caller should add * the ellipsis because only a substring fits. In this case * maxPixels contains the number of pixels for the substring * plus ellipsis. The substring has a minimum of one character. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tree_Ellipsis( Tk_Font tkfont, /* The font used to display the string. */ char *string, /* UTF-8 string, need not be NULL-terminated. */ int numBytes, /* Number of bytes to consider. */ int *maxPixels, /* In: maximum line length allowed. * Out: length of string that fits (with * ellipsis added if needed). */ char *ellipsis, /* NULL-terminated "..." */ int force /* TRUE if ellipsis should always be added * even if the whole string fits in * maxPixels. */ ) { char staticStr[256], *tmpStr = staticStr; int pixels, pixelsTest, bytesThatFit, bytesTest; int ellipsisNumBytes = (int) strlen(ellipsis); int bytesInFirstCh; Tcl_UniChar uniCh; bytesThatFit = Tk_MeasureChars(tkfont, string, numBytes, *maxPixels, 0, &pixels); /* The whole string fits. No ellipsis needed (unless forced) */ if ((bytesThatFit == numBytes) && !force) { (*maxPixels) = pixels; return numBytes; } bytesInFirstCh = Tcl_UtfToUniChar(string, &uniCh); if (bytesThatFit <= bytesInFirstCh) { goto singleChar; } /* Strip off one character at a time, adding ellipsis, until it fits */ if (force) bytesTest = bytesThatFit; else bytesTest = (int) (Tcl_UtfPrev(string + bytesThatFit, string) - string); if (bytesTest + ellipsisNumBytes > sizeof(staticStr)) tmpStr = ckalloc(bytesTest + ellipsisNumBytes); memcpy(tmpStr, string, bytesTest); while (bytesTest > 0) { memcpy(tmpStr + bytesTest, ellipsis, ellipsisNumBytes); numBytes = Tk_MeasureChars(tkfont, tmpStr, bytesTest + ellipsisNumBytes, *maxPixels, 0, &pixelsTest); if (numBytes == bytesTest + ellipsisNumBytes) { (*maxPixels) = pixelsTest; if (tmpStr != staticStr) ckfree(tmpStr); return bytesTest; } bytesTest = (int) (Tcl_UtfPrev(string + bytesTest, string) - string); } singleChar: /* No single char + ellipsis fits. Return the number of bytes for * the first character. The returned pixel width is the width of the * first character plus ellipsis. */ bytesThatFit = bytesInFirstCh; memcpy(tmpStr, string, bytesThatFit); memcpy(tmpStr + bytesThatFit, ellipsis, ellipsisNumBytes); (void) Tk_MeasureChars(tkfont, tmpStr, bytesThatFit + ellipsisNumBytes, -1, 0, &pixels); (*maxPixels) = pixels; if (tmpStr != staticStr) ckfree(tmpStr); return bytesThatFit; } /* *---------------------------------------------------------------------- * * Tree_GetRegion -- * * Return a pre-allocated TkRegion or create a new one. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ TkRegion Tree_GetRegion( TreeCtrl *tree /* Widget info. */ ) { TkRegion region; if (tree->regionStackLen == 0) { return TkCreateRegion(); } region = tree->regionStack[--tree->regionStackLen]; Tree_SetEmptyRegion(region); return region; } /* *---------------------------------------------------------------------- * * Tree_FreeRegion -- * * Push a region onto the free stack. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_FreeRegion( TreeCtrl *tree, /* Widget info. */ TkRegion region /* Region being released. */ ) { if (tree->regionStackLen == sizeof(tree->regionStack) / sizeof(TkRegion)) panic("Tree_FreeRegion: the stack is full"); tree->regionStack[tree->regionStackLen++] = region; } /* *---------------------------------------------------------------------- * * Tree_SetEmptyRegion -- * * Set a region to empty. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_SetEmptyRegion( TkRegion region /* Region to modify. */ ) { TkSubtractRegion(region, region, region); } /* *---------------------------------------------------------------------- * * Tree_GetRectRegion -- * * Allocate a region and set it to a single rectangle. * * Results: * Changes a region. * * Side effects: * None. * *---------------------------------------------------------------------- */ TkRegion Tree_GetRectRegion( TreeCtrl *tree, /* Widget info. */ const TreeRectangle *rect /* Rectangle */ ) { XRectangle xr; TkRegion region; region = Tree_GetRegion(tree); TreeRect_ToXRect(*rect, &xr); TkUnionRectWithRegion(&xr, region, region); return region; } /* *---------------------------------------------------------------------- * * Tree_SetRectRegion -- * * Set a region to a single rectangle. * * Results: * Changes a region. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_SetRectRegion( TkRegion region, /* Region to modify. */ const TreeRectangle *rect /* Rectangle */ ) { XRectangle xr; Tree_SetEmptyRegion(region); TreeRect_ToXRect(*rect, &xr); TkUnionRectWithRegion(&xr, region, region); } /* *---------------------------------------------------------------------- * * Tree_GetRegionBounds -- * * Return the bounding rectangle of a region. * * Results: * Result rect is filled in with the bounds of the given region. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_GetRegionBounds( TkRegion region, /* Region to modify. */ TreeRectangle *rect /* Rectangle */ ) { XRectangle xr; TkClipBox(region, &xr); TreeRect_FromXRect(xr, rect); } /* *---------------------------------------------------------------------- * * Tree_RedrawImage -- * * Wrapper around Tk_RedrawImage to clip the drawing to the actual * area of the drawable. If you try to draw a transparent photo * image outside the bounds of a drawable, X11 will silently fail * and nothing will be drawn. See tkImgPhoto.c:ImgPhotoDisplay. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_RedrawImage( Tk_Image image, int imageX, int imageY, int width, int height, TreeDrawable td, int drawableX, int drawableY ) { #if 0 int ix = imageX, iy = imageY, iw = width, ih = height; #endif if (drawableX < 0) { imageX = 0 - drawableX; width -= imageX; drawableX = 0; } if (drawableX + width > td.width) { width -= (drawableX + width) - td.width; } if (drawableY < 0) { imageY = 0 - drawableY; height -= imageY; drawableY = 0; } if (drawableY + height > td.height) { height -= (drawableY + height) - td.height; } #if 0 if (ix != imageX || iy != imageY || iw != width || ih != height) dbwin("Tree_RedrawImage clipped %d,%d,%d,%d -> %d,%d,%d,%d\n", ix,iy,iw,ih, imageX, imageY, width, height); #endif if (width > 0 && height > 0) { Tk_RedrawImage(image, imageX, imageY, width, height, td.drawable, drawableX, drawableY); } } /* *---------------------------------------------------------------------- * * Tree_DrawBitmap -- * * Draw part of a bitmap. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_DrawBitmap( TreeCtrl *tree, /* Widget info. */ Pixmap bitmap, /* Bitmap to draw. */ Drawable drawable, /* Where to draw. */ XColor *fg, XColor *bg, /* Foreground and background colors. * May be NULL. */ int src_x, int src_y, /* Left and top of part of bitmap to copy. */ int width, int height, /* Width and height of part of bitmap to * copy. */ int dest_x, int dest_y /* Left and top coordinates to copy part of * the bitmap to. */ ) { XGCValues gcValues; GC gc; unsigned long mask = 0; if (fg != NULL) { gcValues.foreground = fg->pixel; mask |= GCForeground; } if (bg != NULL) { gcValues.background = bg->pixel; mask |= GCBackground; } else { gcValues.clip_mask = bitmap; mask |= GCClipMask; } gcValues.graphics_exposures = False; mask |= GCGraphicsExposures; gc = Tk_GetGC(tree->tkwin, mask, &gcValues); Tree_DrawBitmapWithGC(tree, bitmap, drawable, gc, src_x, src_y, width, height, dest_x, dest_y); Tk_FreeGC(tree->display, gc); } /* * Replacement for Tk_TextLayout stuff. Allows the caller to break lines * on character boundaries (as well as word boundaries). Allows the caller * to specify the maximum number of lines to display. Will add ellipsis "..." * to the end of text that is too long to fit (when max lines specified). */ #define TEXTLAYOUT_ELLIPSIS typedef struct LayoutChunk { CONST char *start; /* Pointer to simple string to be displayed. * * This is a pointer into the TkTextLayout's * * string. */ int numBytes; /* The number of bytes in this chunk. */ int numChars; /* The number of characters in this chunk. */ int numDisplayChars; /* The number of characters to display when * * this chunk is displayed. Can be less than * * numChars if extra space characters were * * absorbed by the end of the chunk. This * * will be < 0 if this is a chunk that is * * holding a tab or newline. */ int x, y; /* The origin of the first character in this * * chunk with respect to the upper-left hand * * corner of the TextLayout. */ int totalWidth; /* Width in pixels of this chunk. Used * * when hit testing the invisible spaces at * * the end of a chunk. */ int displayWidth; /* Width in pixels of the displayable * * characters in this chunk. Can be less than * * width if extra space characters were * * absorbed by the end of the chunk. */ #ifdef TEXTLAYOUT_ELLIPSIS int ellipsis; /* TRUE if adding "..." */ #endif } LayoutChunk; typedef struct LayoutInfo { Tk_Font tkfont; /* The font used when laying out the text. */ CONST char *string; /* The string that was layed out. */ int numLines; /* Number of lines */ int width; /* The maximum width of all lines in the * * text layout. */ int height; int numChunks; /* Number of chunks actually used in * * following array. */ int totalWidth; #define TEXTLAYOUT_ALLOCHAX #ifdef TEXTLAYOUT_ALLOCHAX int maxChunks; struct LayoutInfo *nextFree; #endif LayoutChunk chunks[1]; /* Array of chunks. The actual size will * * be maxChunks. THIS FIELD MUST BE THE LAST * * IN THE STRUCTURE. */ } LayoutInfo; #ifdef TEXTLAYOUT_ALLOCHAX TCL_DECLARE_MUTEX(textLayoutMutex) /* FIXME: memory leak, list is never freed. */ static LayoutInfo *freeLayoutInfo = NULL; #endif #ifdef TEXTLAYOUT_ALLOCHAX static LayoutChunk *NewChunk(LayoutInfo **layoutPtrPtr, #else static LayoutChunk *NewChunk(LayoutInfo **layoutPtrPtr, int *maxPtr, #endif CONST char *start, int numBytes, int curX, int newX, int y) { LayoutInfo *layoutPtr; LayoutChunk *chunkPtr; #ifdef TEXTLAYOUT_ALLOCHAX int numChars; #else int maxChunks, numChars; #endif size_t s; layoutPtr = *layoutPtrPtr; #ifdef TEXTLAYOUT_ALLOCHAX if (layoutPtr->numChunks == layoutPtr->maxChunks) { layoutPtr->maxChunks *= 2; s = sizeof(LayoutInfo) + ((layoutPtr->maxChunks - 1) * sizeof(LayoutChunk)); layoutPtr = (LayoutInfo *) ckrealloc((char *) layoutPtr, (int) s); *layoutPtrPtr = layoutPtr; } #else maxChunks = *maxPtr; if (layoutPtr->numChunks == maxChunks) { maxChunks *= 2; s = sizeof(LayoutInfo) + ((maxChunks - 1) * sizeof(LayoutChunk)); layoutPtr = (LayoutInfo *) ckrealloc((char *) layoutPtr, s); *layoutPtrPtr = layoutPtr; *maxPtr = maxChunks; } #endif numChars = Tcl_NumUtfChars(start, numBytes); chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks]; chunkPtr->start = start; chunkPtr->numBytes = numBytes; chunkPtr->numChars = numChars; chunkPtr->numDisplayChars = numChars; chunkPtr->x = curX; chunkPtr->y = y; chunkPtr->totalWidth = newX - curX; chunkPtr->displayWidth = newX - curX; chunkPtr->ellipsis = FALSE; layoutPtr->numChunks++; return chunkPtr; } TextLayout TextLayout_Compute( Tk_Font tkfont, /* Font that will be used to display text. */ CONST char *string, /* String whose dimensions are to be ** computed. */ int numChars, /* Number of characters to consider from ** string, or < 0 for strlen(). */ int wrapLength, /* Longest permissible line length, in ** pixels. <= 0 means no automatic wrapping: ** just let lines get as long as needed. */ Tk_Justify justify, /* How to justify lines. */ int maxLines, int lMargin1, int lMargin2, /* Extra indentation or zero */ int flags /* Flag bits OR-ed together. ** TK_IGNORE_TABS means that tab characters ** should not be expanded. TK_IGNORE_NEWLINES ** means that newline characters should not ** cause a line break. */ ) { CONST char *start, *end, *special; int n, y, bytesThisChunk, maxChunks; int baseline, height, curX, newX, maxWidth; LayoutInfo *layoutPtr; LayoutChunk *chunkPtr; Tk_FontMetrics fm; Tcl_DString lineBuffer; int *lineLengths; int curLine; int tabWidth = 20; /* FIXME */ Tcl_DStringInit(&lineBuffer); Tk_GetFontMetrics(tkfont, &fm); height = fm.ascent + fm.descent; if (numChars < 0) numChars = Tcl_NumUtfChars(string, -1); if (wrapLength == 0) wrapLength = -1; #ifdef TEXTLAYOUT_ALLOCHAX Tcl_MutexLock(&textLayoutMutex); if (freeLayoutInfo != NULL) { layoutPtr = freeLayoutInfo; freeLayoutInfo = layoutPtr->nextFree; } else { maxChunks = 1; layoutPtr = (LayoutInfo *) ckalloc(sizeof(LayoutInfo) + (maxChunks - 1) * sizeof(LayoutChunk)); layoutPtr->maxChunks = maxChunks; } Tcl_MutexUnlock(&textLayoutMutex); #else maxChunks = 1; layoutPtr = (LayoutInfo *) ckalloc(sizeof(LayoutInfo) + (maxChunks - 1) * sizeof(LayoutChunk)); #endif layoutPtr->tkfont = tkfont; layoutPtr->string = string; layoutPtr->numChunks = 0; layoutPtr->numLines = 0; baseline = fm.ascent; maxWidth = 0; curX = lMargin1; end = Tcl_UtfAtIndex(string, numChars); special = string; flags &= TK_WHOLE_WORDS | TK_IGNORE_TABS | TK_IGNORE_NEWLINES; flags |= TK_AT_LEAST_ONE; for (start = string; start < end;) { if (start >= special) { for (special = start; special < end; special++) { if (!(flags & TK_IGNORE_NEWLINES)) { if ((*special == '\n') || (*special == '\r')) break; } if (!(flags & TK_IGNORE_TABS)) { if (*special == '\t') break; } } } chunkPtr = NULL; if (start < special) { bytesThisChunk = Tk_MeasureChars(tkfont, start, (int) (special - start), wrapLength - curX, flags, &newX); newX += curX; flags &= ~TK_AT_LEAST_ONE; if (bytesThisChunk > 0) { #ifdef TEXTLAYOUT_ALLOCHAX chunkPtr = NewChunk(&layoutPtr, start, #else chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, #endif bytesThisChunk, curX, newX, baseline); start += bytesThisChunk; curX = newX; } } if ((start == special) && (special < end)) { chunkPtr = NULL; if (*special == '\t') { newX = curX + tabWidth; newX -= newX % tabWidth; #ifdef TEXTLAYOUT_ALLOCHAX NewChunk(&layoutPtr, start, 1, curX, newX, #else NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX, #endif baseline)->numDisplayChars = -1; start++; if ((start < end) && ((wrapLength <= 0) || (newX <= wrapLength))) { curX = newX; flags &= ~TK_AT_LEAST_ONE; continue; } } else { #ifdef TEXTLAYOUT_ALLOCHAX NewChunk(&layoutPtr, start, 1, curX, curX, #else NewChunk(&layoutPtr, &maxChunks, start, 1, curX, curX, #endif baseline)->numDisplayChars = -1; start++; goto wrapLine; } } while ((start < end) && isspace(UCHAR(*start))) { if (!(flags & TK_IGNORE_NEWLINES)) { if ((*start == '\n') || (*start == '\r')) break; } if (!(flags & TK_IGNORE_TABS)) { if (*start == '\t') break; } start++; } if (chunkPtr != NULL) { CONST char *end; end = chunkPtr->start + chunkPtr->numBytes; bytesThisChunk = (int) (start - end); if (bytesThisChunk > 0) { bytesThisChunk = Tk_MeasureChars(tkfont, end, bytesThisChunk, -1, 0, &chunkPtr->totalWidth); chunkPtr->numBytes += bytesThisChunk; chunkPtr->numChars += Tcl_NumUtfChars(end, bytesThisChunk); chunkPtr->totalWidth += curX; } } wrapLine: flags |= TK_AT_LEAST_ONE; if (curX > maxWidth) maxWidth = curX; Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX)); chunkPtr = layoutPtr->numChunks ? &layoutPtr->chunks[layoutPtr->numChunks - 1] : NULL; if ((chunkPtr != NULL) && !(flags & TK_IGNORE_NEWLINES) && (chunkPtr->start[0] == '\n')) curX = lMargin1; else curX = lMargin2; baseline += height; layoutPtr->numLines++; if ((maxLines > 0) && (layoutPtr->numLines >= maxLines)) break; } if ((start >= end) && (layoutPtr->numChunks > 0) && !(flags & TK_IGNORE_NEWLINES)) { if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == '\n') { chunkPtr = #ifdef TEXTLAYOUT_ALLOCHAX NewChunk(&layoutPtr, start, 0, curX, curX, #else NewChunk(&layoutPtr, &maxChunks, start, 0, curX, curX, #endif baseline); chunkPtr->numDisplayChars = -1; Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX)); baseline += height; } } #ifdef TEXTLAYOUT_ELLIPSIS /* Fiddle with chunks on the last line to add ellipsis if there is some * text remaining */ if ((start < end) && (layoutPtr->numChunks > 0)) { char *ellipsis = "..."; int ellipsisLen = (int) strlen(ellipsis); char staticStr[256], *buf = staticStr; int pixelsForText; chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks - 1]; if (wrapLength > 0) { y = chunkPtr->y; for (n = layoutPtr->numChunks - 1; n >= 0; n--) { chunkPtr = &layoutPtr->chunks[n]; /* Only consider the last line */ if (chunkPtr->y != y) break; if (chunkPtr->start[0] == '\n') continue; if (chunkPtr->x + chunkPtr->totalWidth < wrapLength) pixelsForText = wrapLength - chunkPtr->x; else pixelsForText = chunkPtr->totalWidth - 1; bytesThisChunk = Tree_Ellipsis(tkfont, (char *) chunkPtr->start, chunkPtr->numBytes, &pixelsForText, ellipsis, TRUE); if (pixelsForText > wrapLength - chunkPtr->x) pixelsForText = wrapLength - chunkPtr->x; if (bytesThisChunk > 0) { chunkPtr->numBytes = bytesThisChunk; chunkPtr->numChars = Tcl_NumUtfChars(chunkPtr->start, bytesThisChunk); chunkPtr->numDisplayChars = chunkPtr->numChars; chunkPtr->ellipsis = TRUE; chunkPtr->displayWidth = pixelsForText; chunkPtr->totalWidth = pixelsForText; lineLengths = (int *) Tcl_DStringValue(&lineBuffer); lineLengths[layoutPtr->numLines - 1] = chunkPtr->x + pixelsForText; if (chunkPtr->x + pixelsForText > maxWidth) maxWidth = chunkPtr->x + pixelsForText; break; } } } else { if (chunkPtr->start[0] == '\n') { if (layoutPtr->numChunks == 1) goto finish; if (layoutPtr->chunks[layoutPtr->numChunks - 2].y != chunkPtr->y) goto finish; chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks - 2]; } if (chunkPtr->numBytes + ellipsisLen > sizeof(staticStr)) buf = ckalloc(chunkPtr->numBytes + ellipsisLen); memcpy(buf, chunkPtr->start, chunkPtr->numBytes); memcpy(buf + chunkPtr->numBytes, ellipsis, ellipsisLen); Tk_MeasureChars(tkfont, buf, chunkPtr->numBytes + ellipsisLen, -1, 0, &chunkPtr->displayWidth); chunkPtr->totalWidth = chunkPtr->displayWidth; chunkPtr->ellipsis = TRUE; lineLengths = (int *) Tcl_DStringValue(&lineBuffer); lineLengths[layoutPtr->numLines - 1] = chunkPtr->x + chunkPtr->displayWidth; if (chunkPtr->x + chunkPtr->displayWidth > maxWidth) maxWidth = chunkPtr->x + chunkPtr->displayWidth; if (buf != staticStr) ckfree(buf); } } finish: #endif layoutPtr->width = maxWidth; layoutPtr->height = baseline - fm.ascent; layoutPtr->totalWidth = 0; if (layoutPtr->numChunks == 0) { layoutPtr->height = height; layoutPtr->numChunks = 1; layoutPtr->chunks[0].start = string; layoutPtr->chunks[0].numBytes = 0; layoutPtr->chunks[0].numChars = 0; layoutPtr->chunks[0].numDisplayChars = -1; layoutPtr->chunks[0].x = 0; layoutPtr->chunks[0].y = fm.ascent; layoutPtr->chunks[0].totalWidth = 0; layoutPtr->chunks[0].displayWidth = 0; } else { curLine = 0; chunkPtr = layoutPtr->chunks; y = chunkPtr->y; lineLengths = (int *) Tcl_DStringValue(&lineBuffer); for (n = 0; n < layoutPtr->numChunks; n++) { int extra; if (chunkPtr->y != y) { curLine++; y = chunkPtr->y; } extra = maxWidth - lineLengths[curLine]; if (justify == TK_JUSTIFY_CENTER) { chunkPtr->x += extra / 2; } else if (justify == TK_JUSTIFY_RIGHT) { chunkPtr->x += extra; } if (chunkPtr->x + chunkPtr->totalWidth > layoutPtr->totalWidth) layoutPtr->totalWidth = chunkPtr->x + chunkPtr->totalWidth; chunkPtr++; } /* dbwin("totalWidth %d displayWidth %d\n", layoutPtr->totalWidth, maxWidth); */ } Tcl_DStringFree(&lineBuffer); /* We don't want single-line text layouts for text elements, but it happens for column titles */ /* if (layoutPtr->numLines == 1) dbwin("WARNING: single-line TextLayout created\n"); */ return (TextLayout) layoutPtr; } void TextLayout_Free(TextLayout textLayout) { LayoutInfo *layoutPtr = (LayoutInfo *) textLayout; #ifdef TEXTLAYOUT_ALLOCHAX Tcl_MutexLock(&textLayoutMutex); layoutPtr->nextFree = freeLayoutInfo; freeLayoutInfo = layoutPtr; Tcl_MutexUnlock(&textLayoutMutex); #else ckfree((char *) layoutPtr); #endif } void TextLayout_Size(TextLayout textLayout, int *widthPtr, int *heightPtr) { LayoutInfo *layoutPtr = (LayoutInfo *) textLayout; if (widthPtr != NULL) (*widthPtr) = layoutPtr->width; if (heightPtr != NULL) (*heightPtr) = layoutPtr->height; } int TextLayout_TotalWidth(TextLayout textLayout) { LayoutInfo *layoutPtr = (LayoutInfo *) textLayout; return layoutPtr->totalWidth; } void TextLayout_Draw( Display *display, /* Display on which to draw. */ Drawable drawable, /* Window or pixmap in which to draw. */ GC gc, /* Graphics context to use for drawing text. */ TextLayout layout, /* Layout information, from a previous call * * to Tk_ComputeTextLayout(). */ int x, int y, /* Upper-left hand corner of rectangle in * * which to draw (pixels). */ int firstChar, /* The index of the first character to draw * * from the given text item. 0 specfies the * * beginning. */ int lastChar, /* The index just after the last character * * to draw from the given text item. A number * * < 0 means to draw all characters. */ int underline /* Character index to underline, or < 0 for * no underline. */ ) { LayoutInfo *layoutPtr = (LayoutInfo *) layout; int i, numDisplayChars, drawX; CONST char *firstByte; CONST char *lastByte; LayoutChunk *chunkPtr; if (lastChar < 0) lastChar = 100000000; chunkPtr = layoutPtr->chunks; for (i = 0; i < layoutPtr->numChunks; i++) { numDisplayChars = chunkPtr->numDisplayChars; if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) { if (firstChar <= 0) { drawX = 0; firstChar = 0; firstByte = chunkPtr->start; } else { firstByte = Tcl_UtfAtIndex(chunkPtr->start, firstChar); Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start, (int) (firstByte - chunkPtr->start), -1, 0, &drawX); } if (lastChar < numDisplayChars) numDisplayChars = lastChar; lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars); #ifdef TEXTLAYOUT_ELLIPSIS if (chunkPtr->ellipsis) { char staticStr[256], *buf = staticStr; char *ellipsis = "..."; int ellipsisLen = (int) strlen(ellipsis); if ((lastByte - firstByte) + ellipsisLen > sizeof(staticStr)) buf = ckalloc((int) (lastByte - firstByte) + ellipsisLen); memcpy(buf, firstByte, (lastByte - firstByte)); memcpy(buf + (lastByte - firstByte), ellipsis, ellipsisLen); Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont, buf, (int) (lastByte - firstByte) + ellipsisLen, x + chunkPtr->x + drawX, y + chunkPtr->y); if (buf != staticStr) ckfree(buf); } else #endif Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont, firstByte, (int) (lastByte - firstByte), x + chunkPtr->x + drawX, y + chunkPtr->y); if (underline >= firstChar && underline < numDisplayChars) { CONST char *fstBytePtr = Tcl_UtfAtIndex(chunkPtr->start, underline); CONST char *sndBytePtr = Tcl_UtfNext(fstBytePtr); Tk_UnderlineChars(display, drawable, gc, layoutPtr->tkfont, firstByte, x + chunkPtr->x + drawX, y + chunkPtr->y, (int) (fstBytePtr - chunkPtr->start), (int) (sndBytePtr - chunkPtr->start)); } } firstChar -= chunkPtr->numChars; lastChar -= chunkPtr->numChars; underline -= chunkPtr->numChars; if (lastChar <= 0) break; chunkPtr++; } } /* *---------------------------------------------------------------------- * * TreeCtrl_GetPadAmountFromObj -- * * Parse a pad amount configuration option. * A pad amount (typically the value of an option -XXXpadx or * -XXXpady, where XXX may be a possibly empty string) can * be either a single pixel width, or a list of two pixel widths. * If a single pixel width, the amount specified is used for * padding on both sides. If two amounts are specified, then * they specify the left/right or top/bottom padding. * * Results: * Standard Tcl Result. * * Side effects: * Sets internal representation of the object. In case of an error * the result of the interpreter is modified. * *---------------------------------------------------------------------- */ int TreeCtrl_GetPadAmountFromObj( Tcl_Interp *interp, /* Interpreter for error reporting, or NULL, * if no error message is wanted. */ Tk_Window tkwin, /* A window. Needed by Tk_GetPixels() */ Tcl_Obj *padObj, /* Object containing a pad amount. */ int *topLeftPtr, /* Pointer to the location, where to store the first component of the padding. */ int *bottomRightPtr /* Pointer to the location, where to store the second component of the padding. */ ) { int padc; /* Number of element objects in padv. */ Tcl_Obj **padv; /* Pointer to the element objects of the * parsed pad amount value. */ int topLeft, bottomRight; if (Tcl_ListObjGetElements(interp, padObj, &padc, &padv) != TCL_OK) { return TCL_ERROR; } /* * The value specifies a non empty string. * Check that this string is indeed a valid pad amount. */ if (padc < 1 || padc > 2) { if (interp != NULL) { error: Tcl_ResetResult(interp); Tcl_AppendResult(interp, "bad pad amount \"", Tcl_GetString(padObj), "\": must be a list of ", "1 or 2 positive screen distances", (char *) NULL); } return TCL_ERROR; } if ((Tk_GetPixelsFromObj(interp, tkwin, padv[0], &topLeft) != TCL_OK) || (topLeft < 0)) { goto error; } if (padc == 2) { if ((Tk_GetPixelsFromObj(interp, tkwin, padv[1], &bottomRight) != TCL_OK) || (bottomRight < 0)) { goto error; } } else { bottomRight = topLeft; } (*topLeftPtr) = topLeft; (*bottomRightPtr) = bottomRight; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeCtrl_NewPadAmountObj -- * * Create a Tcl object with an internal representation, that * corresponds to a pad amount, i.e. an integer Tcl_Obj or a * list Tcl_Obj with 2 elements. * * Results: * The created object. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeCtrl_NewPadAmountObj( int *padAmounts /* Internal form of a pad amount. */ ) { Tcl_Obj *newObj; /* * If both values are the same, create a list with one value, * otherwise create a two element list with the top/left value * first followed by the bottom/right value. */ if (padAmounts[PAD_TOP_LEFT] == padAmounts[PAD_BOTTOM_RIGHT]) { newObj = Tcl_NewIntObj(padAmounts[PAD_TOP_LEFT]); } else { newObj = Tcl_NewObj(); Tcl_ListObjAppendElement((Tcl_Interp *) NULL, newObj, Tcl_NewIntObj(padAmounts[PAD_TOP_LEFT])); Tcl_ListObjAppendElement((Tcl_Interp *) NULL, newObj, Tcl_NewIntObj(padAmounts[PAD_BOTTOM_RIGHT])); } return newObj; } /* *---------------------------------------------------------------------- * * PadAmountOptionSet -- * PadAmountOptionGet -- * PadAmountOptionRestore -- * PadAmountOptionFree -- * * Handlers for object-based pad amount configuration options. * A pad amount (typically the value of an option -XXXpadx or * -XXXpady, where XXX may be a possibly empty string) can * be either a single pixel width, or a list of two pixel widths. * If a single pixel width, the amount specified is used for * padding on both sides. If two amounts are specified, then * they specify the left/right or top/bottom padding. * * Results: * See user documentation for expected results from these functions. * PadAmountOptionSet Standard Tcl Result. * PadAmountOptionGet Tcl_Obj * containing a valid internal * representation of the pad amount. * PadAmountOptionRestore None. * PadAmountOptionFree None. * * Side effects: * Depends on the function. * PadAmountOptionSet Sets option value to new setting, * allocating a new integer array. * PadAmountOptionGet Creates a new Tcl_Obj. * PadAmountOptionRestore Resets option value to original value. * PadAmountOptionFree Free storage for internal rep. * *---------------------------------------------------------------------- */ static int PadAmountOptionSet( ClientData clientData, /* unused. */ Tcl_Interp *interp, /* Interpreter for error reporting, or NULL, * if no error message is wanted. */ Tk_Window tkwin, /* A window. Needed by Tk_GetPixels() */ Tcl_Obj **valuePtr, /* The argument to "-padx", "-pady", "-ipadx", * or "-ipady". The thing to be parsed. */ char *recordPtr, /* Pointer to start of widget record. */ int internalOffset, /* Offset of internal representation or * -1, if no internal repr is wanted. */ char *saveInternalPtr, /* Pointer to the place, where the saved * internal form (of type "int *") resides. */ int flags /* Flags as specified in Tk_OptionSpec. */ ) { int objEmpty; int topLeft, bottomRight; /* The two components of the padding. */ int *new; /* Pointer to the allocated array of integers * containing the parsed pad amounts. */ int **internalPtr; /* Pointer to the place, where the internal * form (of type "int *") resides. */ objEmpty = ObjectIsEmpty((*valuePtr)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) (*valuePtr) = NULL; else { /* * Check that the given object indeed specifies a valid pad amount. */ if (TreeCtrl_GetPadAmountFromObj(interp, tkwin, *valuePtr, &topLeft, &bottomRight) != TCL_OK) { return TCL_ERROR; } } /* * Store a pointer to an allocated array of the two padding values * into the widget record at the specified offset. */ if (internalOffset >= 0) { internalPtr = (int **) (recordPtr + internalOffset); *(int **) saveInternalPtr = *internalPtr; if (*valuePtr == NULL) new = NULL; else { new = (int *) ckalloc(2 * sizeof(int)); new[PAD_TOP_LEFT] = topLeft; new[PAD_BOTTOM_RIGHT] = bottomRight; } *internalPtr = new; } return TCL_OK; } static Tcl_Obj * PadAmountOptionGet( ClientData clientData, /* unused. */ Tk_Window tkwin, /* A window; unused. */ char *recordPtr, /* Pointer to start of widget record. */ int internalOffset /* Offset of internal representation. */ ) { int *padAmounts = *(int **)(recordPtr + internalOffset); if (padAmounts == NULL) return NULL; return TreeCtrl_NewPadAmountObj(padAmounts); } static void PadAmountOptionRestore( ClientData clientData, /* unused. */ Tk_Window tkwin, /* A window; unused. */ char *internalPtr, /* Pointer to the place, where the internal * form (of type "int *") resides. */ char *saveInternalPtr /* Pointer to the place, where the saved * internal form (of type "int *") resides. */ ) { *(int **) internalPtr = *(int **) saveInternalPtr; } static void PadAmountOptionFree( ClientData clientData, /* unused. */ Tk_Window tkwin, /* A window; unused */ char *internalPtr /* Pointer to the place, where the internal * form (of type "int *") resides. */ ) { if (*(int **)internalPtr != NULL) { ckfree((char *) *(int **)internalPtr); } } /* *---------------------------------------------------------------------- * * ObjectIsEmpty -- * * This procedure tests whether the string value of an object is * empty. * * Results: * The return value is 1 if the string value of objPtr has length * zero, and 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int ObjectIsEmpty( Tcl_Obj *obj /* Object to test. May be NULL. */ ) { int length; if (obj == NULL) return 1; if (obj->bytes != NULL) return (obj->length == 0); Tcl_GetStringFromObj(obj, &length); return (length == 0); } #define PERSTATE_ROUNDUP 5 /* *---------------------------------------------------------------------- * * PerStateInfo_Free -- * * Frees memory and resources associated with a single per-state * option. pInfo is set to an empty state ready to be used again. * * Results: * None. * * Side effects: * Memory is deallocated. Colors, etc are freed. * *---------------------------------------------------------------------- */ void PerStateInfo_Free( TreeCtrl *tree, /* Widget info. */ PerStateType *typePtr, /* Type-specific functions and values. */ PerStateInfo *pInfo /* Per-state info to free. */ ) { PerStateData *pData = pInfo->data; int i; if (pInfo->data == NULL) return; #ifdef TREECTRL_DEBUG if (pInfo->type != typePtr) panic("PerStateInfo_Free type mismatch: got %s expected %s", pInfo->type ? pInfo->type->name : "NULL", typePtr->name); #endif for (i = 0; i < pInfo->count; i++) { (*typePtr->freeProc)(tree, pData); pData = (PerStateData *) (((char *) pData) + typePtr->size); } #ifdef ALLOC_HAX TreeAlloc_CFree(tree->allocData, typePtr->name, (char *) pInfo->data, typePtr->size, pInfo->count, PERSTATE_ROUNDUP); #else WIPEFREE(pInfo->data, typePtr->size * pInfo->count); #endif pInfo->data = NULL; pInfo->count = 0; } /* *---------------------------------------------------------------------- * * PerStateInfo_FromObj -- * * Parse a Tcl_Obj to an array of PerStateData. The current data * is freed (if any). If the Tcl_Obj is NULL then pInfo is left in * an empty state ready to be used again. * * Results: * A standard Tcl result. * * Side effects: * Memory is allocated/deallocated. * *---------------------------------------------------------------------- */ int PerStateInfo_FromObj( TreeCtrl *tree, /* Widget info. */ int domain, /* STATE_DOMAIN_XXX index. */ StateFromObjProc proc, /* Procedure used to turn a Tcl_Obj into * a state bit-flag. */ PerStateType *typePtr, /* Type-specific functions and values. */ PerStateInfo *pInfo /* Per-state info to return. pInfo->obj * must be NULL or point to a valid Tcl_Obj. */ ) { int i, j; int objc, objc2; Tcl_Obj **objv, **objv2; PerStateData *pData; #ifdef TREECTRL_DEBUG pInfo->type = typePtr; #endif PerStateInfo_Free(tree, typePtr, pInfo); if (pInfo->obj == NULL) return TCL_OK; if (Tcl_ListObjGetElements(tree->interp, pInfo->obj, &objc, &objv) != TCL_OK) return TCL_ERROR; if (objc == 0) return TCL_OK; if (objc == 1) { #ifdef ALLOC_HAX pData = (PerStateData *) TreeAlloc_CAlloc(tree->allocData, typePtr->name, typePtr->size, 1, PERSTATE_ROUNDUP); #else pData = (PerStateData *) ckalloc(typePtr->size); #endif pData->stateOff = pData->stateOn = 0; /* all states */ if ((*typePtr->fromObjProc)(tree, objv[0], pData) != TCL_OK) { #ifdef ALLOC_HAX TreeAlloc_CFree(tree->allocData, typePtr->name, (char *) pData, typePtr->size, 1, PERSTATE_ROUNDUP); #else WIPEFREE(pData, typePtr->size); #endif return TCL_ERROR; } pInfo->data = pData; pInfo->count = 1; return TCL_OK; } if (objc & 1) { FormatResult(tree->interp, "list must have even number of elements"); return TCL_ERROR; } #ifdef ALLOC_HAX pData = (PerStateData *) TreeAlloc_CAlloc(tree->allocData, typePtr->name, typePtr->size, objc / 2, PERSTATE_ROUNDUP); #else pData = (PerStateData *) ckalloc(typePtr->size * (objc / 2)); #endif pInfo->data = pData; for (i = 0; i < objc; i += 2) { if ((*typePtr->fromObjProc)(tree, objv[i], pData) != TCL_OK) { goto freeIt; } pInfo->count++; if (Tcl_ListObjGetElements(tree->interp, objv[i + 1], &objc2, &objv2) != TCL_OK) { goto freeIt; } pData->stateOff = pData->stateOn = 0; /* all states */ for (j = 0; j < objc2; j++) { if (proc(tree, domain, objv2[j], &pData->stateOff, &pData->stateOn) != TCL_OK) { goto freeIt; } } pData = (PerStateData *) (((char *) pData) + typePtr->size); } return TCL_OK; freeIt: pData = pInfo->data; for (i = 0; i < pInfo->count; i++) { (*typePtr->freeProc)(tree, pData); pData = (PerStateData *) (((char *) pData) + typePtr->size); } #ifdef ALLOC_HAX TreeAlloc_CFree(tree->allocData, typePtr->name, (char *) pInfo->data, typePtr->size, objc / 2, PERSTATE_ROUNDUP); #else WIPEFREE(pInfo->data, typePtr->size * (objc / 2)); #endif pInfo->data = NULL; pInfo->count = 0; return TCL_ERROR; } /* *---------------------------------------------------------------------- * * PerStateInfo_ForState -- * * Return the best-matching PerStateData for a given state. * * Results: * The return value is a pointer to the best-matching PerStateData. * *match is set to a MATCH_xxx constant. NULL is returned if * no appropriate PerStateData was found. * * Side effects: * None. * *---------------------------------------------------------------------- */ PerStateData * PerStateInfo_ForState( TreeCtrl *tree, /* Widget info. */ PerStateType *typePtr, /* Type-specific functions and values. */ PerStateInfo *pInfo, /* Per-state info to search. */ int state, /* State bit-flags to compare. */ int *match /* Returned MATCH_xxx constant. */ ) { PerStateData *pData = pInfo->data; int stateOff = ~state, stateOn = state; int i; #ifdef TREECTRL_DEBUG if ((pInfo->data != NULL) && (pInfo->type != typePtr)) { panic("PerStateInfo_ForState type mismatch: got %s expected %s", pInfo->type ? pInfo->type->name : "NULL", typePtr->name); } #endif for (i = 0; i < pInfo->count; i++) { /* Any state */ if ((pData->stateOff == 0) && (pData->stateOn == 0)) { if (match) (*match) = MATCH_ANY; return pData; } /* Exact match */ if ((pData->stateOff == stateOff) && (pData->stateOn == stateOn)) { if (match) (*match) = MATCH_EXACT; return pData; } /* Partial match */ if (((pData->stateOff & stateOff) == pData->stateOff) && ((pData->stateOn & stateOn) == pData->stateOn)) { if (match) (*match) = MATCH_PARTIAL; return pData; } pData = (PerStateData *) (((char *) pData) + typePtr->size); } if (match) (*match) = MATCH_NONE; return NULL; } /* *---------------------------------------------------------------------- * * PerStateInfo_ObjForState -- * * Return a Tcl_Obj from the list object that was parsed by * PerStateInfo_FromObj(). pInfo is searched for the best-matching * PerStateData for the given state and the object used to * create that PerStateData is returned. * * Results: * *match is set to a MATCH_xxx constant. NULL is returned if * no appropriate PerStateData was found. The object should not * be modified by the caller. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tcl_Obj * PerStateInfo_ObjForState( TreeCtrl *tree, /* Widget info. */ PerStateType *typePtr, /* Type-specific functions and values. */ PerStateInfo *pInfo, /* Per-state info to search. */ int state, /* State bit-flags to compare. */ int *match /* Returned MATCH_xxx constant. */ ) { PerStateData *pData; Tcl_Obj *obj; int i; #ifdef TREECTRL_DEBUG if ((pInfo->data != NULL) && (pInfo->type != typePtr)) panic("PerStateInfo_ObjForState type mismatch: got %s expected %s", pInfo->type ? pInfo->type->name : "NULL", typePtr->name); #endif pData = PerStateInfo_ForState(tree, typePtr, pInfo, state, match); if (pData != NULL) { i = (int) ((char *) pData - (char *) pInfo->data) / typePtr->size; Tcl_ListObjIndex(tree->interp, pInfo->obj, i * 2, &obj); return obj; } return NULL; } static Tcl_Obj * DuplicateListObj( Tcl_Obj *objPtr ) { int objc; Tcl_Obj **objv; int result; /* * Comment from TclLsetFlat: * ... A plain Tcl_DuplicateObj * will just increase the intrep's refCount without upping the sublists' * refCount, so that their true shared status cannot be determined from * their refCount. */ result = Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv); return Tcl_NewListObj(objc, objv); } /* *---------------------------------------------------------------------- * * PerStateInfo_Undefine -- * * Called when a user-defined state flag is undefined. The state * flag is cleared from every PerStateData using that flag. The * list object that was parsed by PerStateInfo_FromObj() is modified * by removing any reference to the undefined state. * * Results: * The return value is a boolean indicating whether or not pInfo * was modified. * * Side effects: * The list object pointed to by pInfo->obj may be recreated. * *---------------------------------------------------------------------- */ int PerStateInfo_Undefine( TreeCtrl *tree, /* Widget info. */ PerStateType *typePtr, /* Type-specific functions and values. */ PerStateInfo *pInfo, /* Per-state info to modify. */ int domain, /* STATE_DOMAIN_XXX index. */ int state /* State bit-flag that was undefined. */ ) { PerStateData *pData = pInfo->data; int i, j, numStates, stateOff, stateOn; Tcl_Obj *configObj = pInfo->obj, *listObj, *stateObj; int modified = 0; #ifdef TREECTRL_DEBUG if ((pInfo->data != NULL) && (pInfo->type != typePtr)) panic("PerStateInfo_Undefine type mismatch: got %s expected %s", pInfo->type ? pInfo->type->name : "NULL", typePtr->name); #endif for (i = 0; i < pInfo->count; i++) { if ((pData->stateOff | pData->stateOn) & state) { pData->stateOff &= ~state; pData->stateOn &= ~state; if (Tcl_IsShared(configObj)) { configObj = DuplicateListObj(configObj); Tcl_DecrRefCount(pInfo->obj); Tcl_IncrRefCount(configObj); pInfo->obj = configObj; } Tcl_ListObjIndex(tree->interp, configObj, i * 2 + 1, &listObj); if (Tcl_IsShared(listObj)) { listObj = DuplicateListObj(listObj); Tcl_ListObjReplace(tree->interp, configObj, i * 2 + 1, 1, 1, &listObj); } Tcl_ListObjLength(tree->interp, listObj, &numStates); for (j = 0; j < numStates; ) { Tcl_ListObjIndex(tree->interp, listObj, j, &stateObj); stateOff = stateOn = 0; TreeStateFromObj(tree, domain, stateObj, &stateOff, &stateOn); /* FIXME: why this proc? */ if ((stateOff | stateOn) & state) { Tcl_ListObjReplace(tree->interp, listObj, j, 1, 0, NULL); numStates--; } else j++; } /* Given {bitmap {state1 state2 state3}}, we just invalidated * the string rep of the sublist {state1 state2 state3}, but not * the parent list. */ Tcl_InvalidateStringRep(configObj); modified = 1; } pData = (PerStateData *) (((char *) pData) + typePtr->size); } return modified; } /*****/ GC Tree_GetGC( TreeCtrl *tree, unsigned long mask, XGCValues *gcValues) { GCCache *pGC; unsigned long valid = GCBackground | GCDashList | GCDashOffset | GCFont | GCForeground | GCFunction | GCGraphicsExposures | GCLineStyle; if ((mask | valid) != valid) panic("Tree_GetGC: unsupported mask"); for (pGC = tree->gcCache; pGC != NULL; pGC = pGC->next) { if (mask != pGC->mask) continue; if ((mask & GCBackground) && (pGC->gcValues.background != gcValues->background)) continue; if ((mask & GCDashList) && (pGC->gcValues.dashes != gcValues->dashes)) /* FIXME: single value */ continue; if ((mask & GCDashOffset) && (pGC->gcValues.dash_offset != gcValues->dash_offset)) continue; if ((mask & GCFont) && (pGC->gcValues.font != gcValues->font)) continue; if ((mask & GCForeground) && (pGC->gcValues.foreground != gcValues->foreground)) continue; if ((mask & GCFunction) && (pGC->gcValues.function != gcValues->function)) continue; if ((mask & GCGraphicsExposures) && (pGC->gcValues.graphics_exposures != gcValues->graphics_exposures)) continue; return pGC->gc; } pGC = (GCCache *) ckalloc(sizeof(*pGC)); pGC->gcValues = (*gcValues); pGC->mask = mask; pGC->gc = Tk_GetGC(tree->tkwin, mask, gcValues); pGC->next = tree->gcCache; tree->gcCache = pGC; return pGC->gc; } void Tree_FreeAllGC( TreeCtrl *tree) { GCCache *pGC = tree->gcCache, *next; while (pGC != NULL) { next = pGC->next; Tk_FreeGC(tree->display, pGC->gc); WFREE(pGC, GCCache); pGC = next; } tree->gcCache = NULL; } /*****/ typedef struct PerStateDataBitmap PerStateDataBitmap; struct PerStateDataBitmap { PerStateData header; Pixmap bitmap; }; static int PSDBitmapFromObj( TreeCtrl *tree, Tcl_Obj *obj, PerStateDataBitmap *pBitmap) { if (ObjectIsEmpty(obj)) { /* Specify empty string to override masterX */ pBitmap->bitmap = None; } else { pBitmap->bitmap = Tk_AllocBitmapFromObj(tree->interp, tree->tkwin, obj); if (pBitmap->bitmap == None) return TCL_ERROR; } return TCL_OK; } static void PSDBitmapFree( TreeCtrl *tree, PerStateDataBitmap *pBitmap) { if (pBitmap->bitmap != None) Tk_FreeBitmap(tree->display, pBitmap->bitmap); } PerStateType pstBitmap = { "pstBitmap", sizeof(PerStateDataBitmap), (PerStateType_FromObjProc) PSDBitmapFromObj, (PerStateType_FreeProc) PSDBitmapFree }; Pixmap PerStateBitmap_ForState( TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match) { PerStateDataBitmap *pData; pData = (PerStateDataBitmap *) PerStateInfo_ForState(tree, &pstBitmap, pInfo, state, match); if (pData != NULL) return pData->bitmap; return None; } void PerStateBitmap_MaxSize( TreeCtrl *tree, PerStateInfo *pInfo, int *widthPtr, int *heightPtr) { PerStateDataBitmap *pData = (PerStateDataBitmap *) pInfo->data; int i, width, height, w, h; width = height = 0; for (i = 0; i < pInfo->count; i++, ++pData) { if (pData->bitmap == None) continue; Tk_SizeOfBitmap(tree->display, pData->bitmap, &w, &h); width = MAX(width, w); height = MAX(height, h); } (*widthPtr) = width; (*heightPtr) = height; } /*****/ typedef struct PerStateDataBoolean PerStateDataBoolean; struct PerStateDataBoolean { PerStateData header; int value; }; static int PSDBooleanFromObj( TreeCtrl *tree, Tcl_Obj *obj, PerStateDataBoolean *pBoolean) { if (ObjectIsEmpty(obj)) { pBoolean->value = -1; } else { if (Tcl_GetBooleanFromObj(tree->interp, obj, &pBoolean->value) != TCL_OK) return TCL_ERROR; } return TCL_OK; } static void PSDBooleanFree( TreeCtrl *tree, PerStateDataBoolean *pBoolean) { } PerStateType pstBoolean = { "pstBoolean", sizeof(PerStateDataBoolean), (PerStateType_FromObjProc) PSDBooleanFromObj, (PerStateType_FreeProc) PSDBooleanFree }; int PerStateBoolean_ForState( TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match) { PerStateDataBoolean *pData; pData = (PerStateDataBoolean *) PerStateInfo_ForState(tree, &pstBoolean, pInfo, state, match); if (pData != NULL) return pData->value; return -1; } /*****/ typedef struct PerStateDataBorder PerStateDataBorder; struct PerStateDataBorder { PerStateData header; Tk_3DBorder border; }; static int PSDBorderFromObj( TreeCtrl *tree, Tcl_Obj *obj, PerStateDataBorder *pBorder) { if (ObjectIsEmpty(obj)) { /* Specify empty string to override masterX */ pBorder->border = NULL; } else { pBorder->border = Tk_Alloc3DBorderFromObj(tree->interp, tree->tkwin, obj); if (pBorder->border == NULL) return TCL_ERROR; } return TCL_OK; } static void PSDBorderFree( TreeCtrl *tree, PerStateDataBorder *pBorder) { if (pBorder->border != NULL) Tk_Free3DBorder(pBorder->border); } PerStateType pstBorder = { "pstBorder", sizeof(PerStateDataBorder), (PerStateType_FromObjProc) PSDBorderFromObj, (PerStateType_FreeProc) PSDBorderFree }; Tk_3DBorder PerStateBorder_ForState( TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match) { PerStateDataBorder *pData; pData = (PerStateDataBorder *) PerStateInfo_ForState(tree, &pstBorder, pInfo, state, match); if (pData != NULL) return pData->border; return NULL; } /*****/ typedef struct PerStateDataColor PerStateDataColor; struct PerStateDataColor { PerStateData header; TreeColor *color; }; static int PSDColorFromObj( TreeCtrl *tree, Tcl_Obj *obj, PerStateDataColor *pColor) { if (ObjectIsEmpty(obj)) { /* Specify empty string to override masterX */ pColor->color = NULL; } else { pColor->color = Tree_AllocColorFromObj(tree, obj); if (pColor->color == NULL) return TCL_ERROR; } return TCL_OK; } static void PSDColorFree( TreeCtrl *tree, PerStateDataColor *pColor) { if (pColor->color != NULL) Tree_FreeColor(tree, pColor->color); } PerStateType pstColor = { "pstColor", sizeof(PerStateDataColor), (PerStateType_FromObjProc) PSDColorFromObj, (PerStateType_FreeProc) PSDColorFree }; TreeColor * PerStateColor_ForState( TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match) { PerStateDataColor *pData; pData = (PerStateDataColor *) PerStateInfo_ForState(tree, &pstColor, pInfo, state, match); if (pData != NULL) return pData->color; return NULL; } /*****/ typedef struct PerStateDataFont PerStateDataFont; struct PerStateDataFont { PerStateData header; Tk_Font tkfont; }; static int PSDFontFromObj( TreeCtrl *tree, Tcl_Obj *obj, PerStateDataFont *pFont) { if (ObjectIsEmpty(obj)) { /* Specify empty string to override masterX */ pFont->tkfont = NULL; } else { pFont->tkfont = Tk_AllocFontFromObj(tree->interp, tree->tkwin, obj); if (pFont->tkfont == NULL) return TCL_ERROR; } return TCL_OK; } static void PSDFontFree( TreeCtrl *tree, PerStateDataFont *pFont) { if (pFont->tkfont != NULL) Tk_FreeFont(pFont->tkfont); } PerStateType pstFont = { "pstFont", sizeof(PerStateDataFont), (PerStateType_FromObjProc) PSDFontFromObj, (PerStateType_FreeProc) PSDFontFree }; Tk_Font PerStateFont_ForState( TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match) { PerStateDataFont *pData; pData = (PerStateDataFont *) PerStateInfo_ForState(tree, &pstFont, pInfo, state, match); if (pData != NULL) return pData->tkfont; return NULL; } /*****/ typedef struct PerStateDataImage PerStateDataImage; struct PerStateDataImage { PerStateData header; Tk_Image image; char *string; }; static int PSDImageFromObj( TreeCtrl *tree, Tcl_Obj *obj, PerStateDataImage *pImage) { int length; char *string; if (ObjectIsEmpty(obj)) { /* Specify empty string to override masterX */ pImage->image = NULL; pImage->string = NULL; } else { string = Tcl_GetStringFromObj(obj, &length); pImage->image = Tree_GetImage(tree, string); if (pImage->image == NULL) return TCL_ERROR; pImage->string = ckalloc(length + 1); strcpy(pImage->string, string); } return TCL_OK; } static void PSDImageFree( TreeCtrl *tree, PerStateDataImage *pImage) { if (pImage->string != NULL) ckfree(pImage->string); if (pImage->image != NULL) Tree_FreeImage(tree, pImage->image); } PerStateType pstImage = { "pstImage", sizeof(PerStateDataImage), (PerStateType_FromObjProc) PSDImageFromObj, (PerStateType_FreeProc) PSDImageFree }; Tk_Image PerStateImage_ForState( TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match) { PerStateDataImage *pData; pData = (PerStateDataImage *) PerStateInfo_ForState(tree, &pstImage, pInfo, state, match); if (pData != NULL) return pData->image; return NULL; } void PerStateImage_MaxSize( TreeCtrl *tree, PerStateInfo *pInfo, int *widthPtr, int *heightPtr) { PerStateDataImage *pData = (PerStateDataImage *) pInfo->data; int i, width, height, w, h; width = height = 0; for (i = 0; i < pInfo->count; i++, ++pData) { if (pData->image == None) continue; Tk_SizeOfImage(pData->image, &w, &h); width = MAX(width, w); height = MAX(height, h); } (*widthPtr) = width; (*heightPtr) = height; } /*****/ typedef struct PerStateDataRelief PerStateDataRelief; struct PerStateDataRelief { PerStateData header; int relief; }; static int PSDReliefFromObj( TreeCtrl *tree, Tcl_Obj *obj, PerStateDataRelief *pRelief) { if (ObjectIsEmpty(obj)) { /* Specify empty string to override masterX */ pRelief->relief = TK_RELIEF_NULL; } else { if (Tk_GetReliefFromObj(tree->interp, obj, &pRelief->relief) != TCL_OK) return TCL_ERROR; } return TCL_OK; } static void PSDReliefFree( TreeCtrl *tree, PerStateDataRelief *pRelief) { } PerStateType pstRelief = { "pstRelief", sizeof(PerStateDataRelief), (PerStateType_FromObjProc) PSDReliefFromObj, (PerStateType_FreeProc) PSDReliefFree }; int PerStateRelief_ForState( TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match) { PerStateDataRelief *pData; pData = (PerStateDataRelief *) PerStateInfo_ForState(tree, &pstRelief, pInfo, state, match); if (pData != NULL) return pData->relief; return TK_RELIEF_NULL; } /*****/ int Tree_GetFlagsFromString( TreeCtrl *tree, const char *string, int length, const char *typeStr, const CharFlag flags[], int *flagsPtr ) { int i, j, bits = 0, allBits = 0, numFlags = 0; for (j = 0; flags[j].flagChar != '\0'; j++) { allBits |= flags[j].flagBit; numFlags++; } for (i = 0; i < length; i++) { for (j = 0; flags[j].flagChar != '\0'; j++) { if (string[i] == flags[j].flagChar || string[i] == toupper(flags[j].flagChar)) { bits |= flags[j].flagBit; break; } } if (flags[j].flagChar == '\0') { Tcl_ResetResult(tree->interp); Tcl_AppendResult(tree->interp, "bad ", typeStr, " \"", string, "\": must be a string ", "containing zero or more of ", (char *) NULL); for (j = 0; flags[j].flagChar != '\0'; j++) { char buf[8]; if (flags[j+1].flagChar != '\0') (void) sprintf(buf, "%c%s ", flags[j].flagChar, (numFlags > 2) ? "," : ""); else (void) sprintf(buf, "and %c", flags[j].flagChar); Tcl_AppendResult(tree->interp, buf, (char *) NULL); } return TCL_ERROR; } } (*flagsPtr) &= ~allBits; (*flagsPtr) |= bits; return TCL_OK; } int Tree_GetFlagsFromObj( TreeCtrl *tree, Tcl_Obj *obj, const char *typeStr, const CharFlag flags[], int *flagsPtr ) { int length; char *string; string = Tcl_GetStringFromObj(obj, &length); return Tree_GetFlagsFromString(tree, string, length, typeStr, flags, flagsPtr); } /*****/ /* The rect element's -open option */ typedef struct PerStateDataFlags PerStateDataFlags; struct PerStateDataFlags { PerStateData header; int flags; }; static int PSDFlagsFromObj( TreeCtrl *tree, Tcl_Obj *obj, PerStateDataFlags *pFlags) { if (ObjectIsEmpty(obj)) { pFlags->flags = 0xFFFFFFFF; } else { static const CharFlag openFlags[] = { { 'n', RECT_OPEN_N }, { 'e', RECT_OPEN_E }, { 's', RECT_OPEN_S }, { 'w', RECT_OPEN_W }, { 0, 0 } }; pFlags->flags = 0; if (Tree_GetFlagsFromObj(tree, obj, "open value", openFlags, &pFlags->flags) != TCL_OK) { return TCL_ERROR; } } return TCL_OK; } static void PSDFlagsFree( TreeCtrl *tree, PerStateDataFlags *pFlags) { } PerStateType pstFlags = { "pstFlags", sizeof(PerStateDataFlags), (PerStateType_FromObjProc) PSDFlagsFromObj, (PerStateType_FreeProc) PSDFlagsFree }; int PerStateFlags_ForState( TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match) { PerStateDataFlags *pData; pData = (PerStateDataFlags *) PerStateInfo_ForState(tree, &pstFlags, pInfo, state, match); if (pData != NULL) return pData->flags; return 0xFFFFFFFF; } /*****/ void PSTSave( PerStateInfo *pInfo, PerStateInfo *pSave) { #ifdef TREECTRL_DEBUG pSave->type = pInfo->type; /* could be NULL */ #endif pSave->data = pInfo->data; pSave->count = pInfo->count; pInfo->data = NULL; pInfo->count = 0; } void PSTRestore( TreeCtrl *tree, PerStateType *typePtr, PerStateInfo *pInfo, PerStateInfo *pSave) { PerStateInfo_Free(tree, typePtr, pInfo); pInfo->data = pSave->data; pInfo->count = pSave->count; } #ifdef ALLOC_HAX /* * The following TreeAlloc_xxx calls implement a mini memory allocator that * allocates blocks of same-sized chunks, and holds on to those chunks when * they are freed so they can be reused quickly. If you don't want to use it * just comment out #define ALLOC_HAX in tkTreeCtrl.h. */ typedef struct AllocElem AllocElem; typedef struct AllocBlock AllocBlock; typedef struct AllocList AllocList; typedef struct AllocData AllocData; #ifdef TREECTRL_DEBUG #define ALLOC_STATS #endif #ifdef ALLOC_STATS typedef struct AllocStats AllocStats; #endif /* * One of the following structures exists for each client piece of memory. * These structures are allocated in arrays (blocks). */ struct AllocElem { AllocElem *next; #ifdef TREECTRL_DEBUG char dbug[4]; /* "DBUG" */ int free; /* 1 if elem is available for reuse. */ int size; /* Number of bytes in body[]. */ #endif char body[1]; /* First byte of client's space. Actual * size of this field will be larger than * one. */ }; struct AllocBlock { int count; /* Size of .elem[] */ AllocBlock *next; /* Next block with same-sized elems. */ AllocElem elem[1]; /* Actual size will be larger than one. */ }; /* * One of the following structures maintains an array of blocks of AllocElems * of the same size. */ struct AllocList { int size; /* Size of every AllocElem.body[] */ AllocElem *head; /* Top of stack of unused pieces of memory. */ AllocBlock *blocks; /* Linked list of allocated blocks. The blocks * may contain a different number of elements. */ int blockSize; /* The number of AllocElems per block to allocate. * Starts at 16 and gets doubled up to 1024. */ AllocList *next; /* Points to an AllocList with a different .size */ }; /* * A pointer to one of the following structures is stored in each TreeCtrl. */ struct AllocData { AllocList *freeLists; /* Linked list. */ #ifdef ALLOC_STATS AllocStats *stats; /* For memory-usage reporting. */ #endif }; #ifdef ALLOC_STATS struct AllocStats { Tk_Uid id; /* Name for reporting results. */ unsigned count; /* Number of allocations. */ unsigned size; /* Total allocated bytes. */ AllocStats *next; /* Linked list. */ }; #endif /* * The following macro computes the offset of the "body" field within * AllocElem. It is used to get back to the header pointer from the * body pointer that's used by clients. */ #ifdef offsetofXXX #define BODY_OFFSET ((size_t) offsetof(AllocElem, body)) #else #define BODY_OFFSET ((size_t) (&((AllocElem *) 0)->body)) #endif #ifdef ALLOC_STATS static AllocStats * AllocStats_Get( ClientData _data, Tk_Uid id ) { AllocData *data = (AllocData *) _data; AllocStats *stats = data->stats; while (stats != NULL) { if (stats->id == id) break; stats = stats->next; } if (stats == NULL) { stats = (AllocStats *) ckalloc(sizeof(AllocStats)); stats->id = id; stats->count = 0; stats->size = 0; stats->next = data->stats; data->stats = stats; } return stats; } void TreeAlloc_Stats( Tcl_Interp *interp, ClientData _data ) { AllocData *data = (AllocData *) _data; AllocStats *stats = data->stats; int numElems = 0; Tcl_DString dString; Tcl_DStringInit(&dString); while (stats != NULL) { DStringAppendf(&dString, "%-20s: %8d : %8d B %5d KB\n", stats->id, stats->count, stats->size, (stats->size + 1023) / 1024); numElems += stats->count; stats = stats->next; } DStringAppendf(&dString, "%-31s: %8d B %5d KB\n", "AllocElem overhead", numElems * BODY_OFFSET, (numElems * BODY_OFFSET) / 1024); Tcl_DStringResult(interp, &dString); } #endif /* ALLOC_STATS */ /* *---------------------------------------------------------------------- * * TreeAlloc_Alloc -- * * Return storage for a piece of data of the given size. * * Results: * The return value is a pointer to memory for the caller's * use. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ char * TreeAlloc_Alloc( ClientData _data, /* Token returned by TreeAlloc_Init(). */ Tk_Uid id, /* ID for memory-usage reporting. */ int size /* Number of bytes needed. */ ) { AllocData *data = (AllocData *) _data; AllocList *freeLists = data->freeLists; AllocList *freeList = freeLists; AllocBlock *block; AllocElem *elem, *result; #ifdef ALLOC_STATS AllocStats *stats = AllocStats_Get(_data, id); #endif int i; #ifdef ALLOC_STATS stats->count++; stats->size += size; #endif while ((freeList != NULL) && (freeList->size != size)) freeList = freeList->next; if (freeList == NULL) { freeList = (AllocList *) ckalloc(sizeof(AllocList)); freeList->size = size; freeList->head = NULL; freeList->next = freeLists; freeList->blocks = NULL; freeList->blockSize = 16; freeLists = freeList; ((AllocData *) data)->freeLists = freeLists; } if (freeList->head == NULL) { unsigned elemSize = TCL_ALIGN(BODY_OFFSET + size); block = (AllocBlock *) ckalloc(Tk_Offset(AllocBlock, elem) + elemSize * freeList->blockSize); block->count = freeList->blockSize; block->next = freeList->blocks; /* dbwin("TreeAlloc_Alloc alloc %d of size %d\n", freeList->blockSize, size); */ freeList->blocks = block; if (freeList->blockSize < 1024) freeList->blockSize *= 2; freeList->head = block->elem; elem = freeList->head; for (i = 1; i < block->count - 1; i++) { #ifdef TREECTRL_DEBUG strncpy(elem->dbug, "DBUG", 4); elem->free = 1; elem->size = size; #endif elem->next = (AllocElem *) (((char *) freeList->head) + elemSize * i); elem = elem->next; } elem->next = NULL; #ifdef TREECTRL_DEBUG strncpy(elem->dbug, "DBUG", 4); elem->free = 1; elem->size = size; #endif } result = freeList->head; freeList->head = result->next; #ifdef TREECTRL_DEBUG if (!result->free) panic("TreeAlloc_Alloc: element not marked free"); result->free = 0; #endif return result->body; } /* *---------------------------------------------------------------------- * * TreeAlloc_Realloc -- * * Realloc. * * Results: * The return value is a pointer to memory for the caller's * use. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ char * TreeAlloc_Realloc( ClientData data, /* Token returned by TreeAlloc_Init(). */ Tk_Uid id, /* ID for memory-usage reporting. */ char *ptr, int size1, /* Number of bytes in ptr. */ int size2 /* Number of bytes needed. */ ) { char *ptr2; ptr2 = TreeAlloc_Alloc(data, id, size2); memcpy(ptr2, ptr, MIN(size1, size2)); TreeAlloc_Free(data, id, ptr, size1); return ptr2; } /* *---------------------------------------------------------------------- * * TreeAlloc_Free -- * * Mark a piece of memory as free for reuse. * * Results: * The piece of memory is added to a list of free pieces of the * same size. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeAlloc_Free( ClientData _data, /* Token returned by TreeAlloc_Init(). */ Tk_Uid id, /* ID for memory-usage reporting. */ char *ptr, /* Memory to mark for reuse. Must have * been allocated by TreeAlloc_Alloc(). */ int size /* Number of bytes. Must match the size * passed to TreeAlloc_CAlloc(). */ ) { AllocData *data = (AllocData *) _data; AllocList *freeLists = data->freeLists; AllocList *freeList = freeLists; AllocElem *elem; #ifdef ALLOC_STATS AllocStats *stats = AllocStats_Get(_data, id); #endif #ifdef ALLOC_STATS stats->count--; stats->size -= size; #endif /* Comment from Tcl_DbCkfree: */ /* * The following cast is *very* tricky. Must convert the pointer * to an integer before doing arithmetic on it, because otherwise * the arithmetic will be done differently (and incorrectly) on * word-addressed machines such as Crays (will subtract only bytes, * even though BODY_OFFSET is in words on these machines). */ /* Note: The Tcl source used to do "(unsigned long) ptr" but that * results in pointer truncation on 64-bit Windows builds. */ elem = (AllocElem *) (((size_t) ptr) - BODY_OFFSET); #ifdef TREECTRL_DEBUG if (strncmp(elem->dbug, "DBUG", 4) != 0) panic("TreeAlloc_Free: element header != DBUG"); if (elem->free) panic("TreeAlloc_Free: element already marked free"); if (elem->size != size) panic("TreeAlloc_Free: element size %d != size %d", elem->size, size); #endif while (freeList != NULL && freeList->size != size) freeList = freeList->next; if (freeList == NULL) panic("TreeAlloc_Free: can't find free list for size %d", size); WIPE(elem->body, size); elem->next = freeList->head; #ifdef TREECTRL_DEBUG elem->free = 1; #endif freeList->head = elem; } /* *---------------------------------------------------------------------- * * TreeAlloc_CAlloc -- * * Return storage for an array of pieces of memory. * * Results: * Pointer to the available memory. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ char * TreeAlloc_CAlloc( ClientData data, /* Token returned by TreeAlloc_Init(). */ Tk_Uid id, /* ID for memory-usage reporting. */ int size, /* Number of bytes needed for each piece * of memory. */ int count, /* Number of pieces of memory needed. */ int roundUp /* Positive number used to reduce the number * of lists of memory pieces of different * size. */ ) { int n = (count / roundUp) * roundUp + ((count % roundUp) ? roundUp : 0); #ifdef ALLOC_STATS AllocStats *stats = AllocStats_Get(data, id); #endif #ifdef ALLOC_STATS stats->count += count - 1; #endif return TreeAlloc_Alloc(data, id, size * n); } /* *---------------------------------------------------------------------- * * TreeAlloc_CFree -- * * Mark a piece of memory as free for reuse. * * Results: * The piece of memory is added to a list of free pieces of the * same size. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeAlloc_CFree( ClientData data, /* Token returned by TreeAlloc_Init(). */ Tk_Uid id, /* ID for memory-usage reporting. */ char *ptr, /* Memory to mark for reuse. Must have * been allocated by TreeAlloc_CAlloc(). */ int size, /* Same arg to TreeAlloc_CAlloc(). */ int count, /* Same arg to TreeAlloc_CAlloc(). */ int roundUp /* Same arg to TreeAlloc_CAlloc(). */ ) { int n = (count / roundUp) * roundUp + ((count % roundUp) ? roundUp : 0); #ifdef ALLOC_STATS AllocStats *stats = AllocStats_Get(data, id); #endif TreeAlloc_Free(data, id, ptr, size * n); #ifdef ALLOC_STATS stats->count -= count - 1; #endif } /* *---------------------------------------------------------------------- * * TreeAlloc_Init -- * * Allocate and initialize a new memory-manager record. * * Results: * Pointer to memory-manager record. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ ClientData TreeAlloc_Init(void) { AllocData *data = (AllocData *) ckalloc(sizeof(AllocData)); data->freeLists = NULL; #ifdef ALLOC_STATS data->stats = NULL; #endif return data; } /* *---------------------------------------------------------------------- * * TreeAlloc_Finalize -- * * Free all the memory associated with a memory-manager record. * * Results: * Pointer to memory-manager record. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ void TreeAlloc_Finalize( ClientData _data /* Pointer to AllocData created by * TreeAlloc_Init(). */ ) { AllocData *data = (AllocData *) _data; AllocList *freeList = data->freeLists; #ifdef ALLOC_STATS AllocStats *stats = data->stats; #endif while (freeList != NULL) { AllocList *nextList = freeList->next; AllocBlock *block = freeList->blocks; while (block != NULL) { AllocBlock *nextBlock = block->next; ckfree((char *) block); block = nextBlock; } ckfree((char *) freeList); freeList = nextList; } #ifdef ALLOC_STATS while (stats != NULL) { AllocStats *next = stats->next; ckfree((char *) stats); stats = next; } #endif ckfree((char *) data); } #endif /* ALLOC_HAX */ /* *---------------------------------------------------------------------- * * TreePtrList_Init -- * * Initializes an pointer list, discarding any previous contents * of the pointer list (TreePtrList_Free should have been called already * if the pointer list was previously in use). * * Results: * None. * * Side effects: * The pointer list is initialized to be empty. * *---------------------------------------------------------------------- */ void TreePtrList_Init( TreeCtrl *tree, /* Widget info. */ TreePtrList *tplPtr, /* Structure describing pointer list. */ int count /* Number of pointers the list should hold. * 0 for default. */ ) { #ifdef TREECTRL_DEBUG strncpy(tplPtr->magic, "MAGC", 4); #endif tplPtr->tree = tree; tplPtr->pointers = tplPtr->pointerSpace; tplPtr->count = 0; tplPtr->space = TIL_STATIC_SPACE; if (count + 1 > TIL_STATIC_SPACE) { tplPtr->space = count + 1; tplPtr->pointers = (ClientData *) ckalloc(tplPtr->space * sizeof(ClientData)); } tplPtr->pointers[0] = NULL; } /* *---------------------------------------------------------------------- * * TreePtrList_Grow -- * * Increase the available space in an pointer list. * * Results: * The pointers[] array is resized if needed. * * Side effects: * Memory gets reallocated if needed. * *---------------------------------------------------------------------- */ void TreePtrList_Grow( TreePtrList *tplPtr, /* Structure describing pointer list. */ int count /* Number of pointers the list should hold. */ ) { #ifdef TREECTRL_DEBUG if (strncmp(tplPtr->magic, "MAGC", 4) != 0) panic("TreePtrList_Grow: using uninitialized list"); #endif if (tplPtr->space >= count + 1) return; while (tplPtr->space < count + 1) tplPtr->space *= 2; if (tplPtr->pointers == tplPtr->pointerSpace) { ClientData *pointers; pointers = (ClientData *) ckalloc(tplPtr->space * sizeof(ClientData)); memcpy(pointers, tplPtr->pointers, (tplPtr->count + 1) * sizeof(ClientData)); tplPtr->pointers = pointers; } else { tplPtr->pointers = (ClientData *) ckrealloc((char *) tplPtr->pointers, tplPtr->space * sizeof(ClientData)); } } /* *---------------------------------------------------------------------- * * TreePtrList_Append -- * * Append an pointer to an pointer list. * * Results: * The return value is a pointer to the list of pointers. * * Side effects: * Memory gets reallocated if needed. * *---------------------------------------------------------------------- */ ClientData * TreePtrList_Append( TreePtrList *tplPtr, /* Structure describing pointer list. */ ClientData pointer /* Item to append. */ ) { #ifdef TREECTRL_DEBUG if (strncmp(tplPtr->magic, "MAGC", 4) != 0) panic("TreePtrList_Append: using uninitialized list"); #endif TreePtrList_Grow(tplPtr, tplPtr->count + 1); tplPtr->pointers[tplPtr->count] = pointer; tplPtr->count++; tplPtr->pointers[tplPtr->count] = NULL; return tplPtr->pointers; } /* *---------------------------------------------------------------------- * * TreePtrList_Concat -- * * Join two pointer lists. * * Results: * The return value is a pointer to the list of pointers. * * Side effects: * Memory gets reallocated if needed. * *---------------------------------------------------------------------- */ ClientData * TreePtrList_Concat( TreePtrList *tplPtr, /* Structure describing pointer list. */ TreePtrList *tpl2Ptr /* Item list to append. */ ) { #ifdef TREECTRL_DEBUG if (strncmp(tplPtr->magic, "MAGC", 4) != 0) panic("TreePtrList_Concat: using uninitialized list"); #endif TreePtrList_Grow(tplPtr, tplPtr->count + tpl2Ptr->count); memcpy(tplPtr->pointers + tplPtr->count, tpl2Ptr->pointers, tpl2Ptr->count * sizeof(ClientData)); tplPtr->count += tpl2Ptr->count; tplPtr->pointers[tplPtr->count] = NULL; return tplPtr->pointers; } /* *---------------------------------------------------------------------- * * TreePtrList_Free -- * * Frees up any memory allocated for the pointer list and * reinitializes the pointer list to an empty state. * * Results: * None. * * Side effects: * The previous contents of the pointer list are lost. * *---------------------------------------------------------------------- */ void TreePtrList_Free( TreePtrList *tplPtr /* Structure describing pointer list. */ ) { #ifdef TREECTRL_DEBUG if (strncmp(tplPtr->magic, "MAGC", 4) != 0) panic("TreePtrList_Free: using uninitialized list"); #endif if (tplPtr->pointers != tplPtr->pointerSpace) { ckfree((char *) tplPtr->pointers); } tplPtr->pointers = tplPtr->pointerSpace; tplPtr->count = 0; tplPtr->space = TIL_STATIC_SPACE; tplPtr->pointers[0] = NULL; } #define TAG_INFO_SIZE(tagSpace) \ (Tk_Offset(TagInfo, tagPtr) + ((tagSpace) * sizeof(Tk_Uid))) static CONST char *TagInfoUid = "TagInfo"; /* *---------------------------------------------------------------------- * * TagInfo_Add -- * * Adds tags to a list of tags. * * Results: * Non-duplicate tags are added. * * Side effects: * Memory may be (re)allocated. * *---------------------------------------------------------------------- */ TagInfo * TagInfo_Add( TreeCtrl *tree, /* Widget info. */ TagInfo *tagInfo, /* Tag list. May be NULL. */ Tk_Uid tags[], int numTags ) { int i, j; if (tagInfo == NULL) { if (numTags <= TREE_TAG_SPACE) { #ifdef ALLOC_HAX tagInfo = (TagInfo *) TreeAlloc_Alloc(tree->allocData, TagInfoUid, sizeof(TagInfo)); #else tagInfo = (TagInfo *) ckalloc(sizeof(TagInfo)); #endif tagInfo->tagSpace = TREE_TAG_SPACE; } else { int tagSpace = (numTags / TREE_TAG_SPACE) * TREE_TAG_SPACE + ((numTags % TREE_TAG_SPACE) ? TREE_TAG_SPACE : 0); if (tagSpace % TREE_TAG_SPACE) panic("TagInfo_Add miscalc"); #ifdef ALLOC_HAX tagInfo = (TagInfo *) TreeAlloc_Alloc(tree->allocData, TagInfoUid, TAG_INFO_SIZE(tagSpace)); #else tagInfo = (TagInfo *) ckalloc(TAG_INFO_SIZE(tagSpace)); #endif tagInfo->tagSpace = tagSpace; } tagInfo->numTags = 0; } for (i = 0; i < numTags; i++) { for (j = 0; j < tagInfo->numTags; j++) { if (tagInfo->tagPtr[j] == tags[i]) break; } if (j >= tagInfo->numTags) { /* Resize existing storage if needed. */ if (tagInfo->tagSpace == tagInfo->numTags) { tagInfo->tagSpace += TREE_TAG_SPACE; #ifdef ALLOC_HAX tagInfo = (TagInfo *) TreeAlloc_Realloc(tree->allocData, TagInfoUid, (char *) tagInfo, TAG_INFO_SIZE(tagInfo->tagSpace - TREE_TAG_SPACE), TAG_INFO_SIZE(tagInfo->tagSpace)); #else tagInfo = (TagInfo *) ckrealloc((char *) tagInfo, TAG_INFO_SIZE(tagInfo->tagSpace)); #endif } tagInfo->tagPtr[tagInfo->numTags++] = tags[i]; } } return tagInfo; } /* *---------------------------------------------------------------------- * * TagInfo_Remove -- * * Removes tags from a list of tags. * * Results: * Existing tags are removed. * * Side effects: * Memory may be reallocated. * *---------------------------------------------------------------------- */ TagInfo * TagInfo_Remove( TreeCtrl *tree, /* Widget info. */ TagInfo *tagInfo, /* Tag list. May be NULL. */ Tk_Uid tags[], int numTags ) { int i, j; if (tagInfo == NULL) return tagInfo; for (i = 0; i < numTags; i++) { for (j = 0; j < tagInfo->numTags; j++) { if (tagInfo->tagPtr[j] == tags[i]) { tagInfo->tagPtr[j] = tagInfo->tagPtr[tagInfo->numTags - 1]; tagInfo->numTags--; break; } } } if (tagInfo->numTags == 0) { TagInfo_Free(tree, tagInfo); tagInfo = NULL; } return tagInfo; } /* *---------------------------------------------------------------------- * * TagInfo_Names -- * * Build a list of unique tag names. * * Results: * Unique tags are added to a dynamically-allocated list. * * Side effects: * Memory may be (re)allocated. * *---------------------------------------------------------------------- */ Tk_Uid * TagInfo_Names( TreeCtrl *tree, /* Widget info. */ TagInfo *tagInfo, /* Tag list. May be NULL. */ Tk_Uid *tags, /* Current list, may be NULL. */ int *numTagsPtr, /* Number of tags in tags[]. */ int *tagSpacePtr /* Size of tags[]. */ ) { int numTags = *numTagsPtr, tagSpace = *tagSpacePtr; int i, j; if (tagInfo == NULL) return tags; for (i = 0; i < tagInfo->numTags; i++) { Tk_Uid tag = tagInfo->tagPtr[i]; for (j = 0; j < numTags; j++) { if (tag == tags[j]) break; } if (j < numTags) continue; if ((tags == NULL) || (numTags == tagSpace)) { if (tags == NULL) { tagSpace = 32; tags = (Tk_Uid *) ckalloc(sizeof(Tk_Uid) * tagSpace); } else { tagSpace *= 2; tags = (Tk_Uid *) ckrealloc((char *) tags, sizeof(Tk_Uid) * tagSpace); } } tags[numTags++] = tag; } *numTagsPtr = numTags; *tagSpacePtr = tagSpace; return tags; } /* *---------------------------------------------------------------------- * * TagInfo_Copy -- * * Copy a list of tags. * * Results: * Allocates a new TagInfo if given one is not NULL. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ TagInfo * TagInfo_Copy( TreeCtrl *tree, /* Widget info. */ TagInfo *tagInfo /* Tag list. May be NULL. */ ) { TagInfo *copy = NULL; if (tagInfo != NULL) { int tagSpace = tagInfo->tagSpace; #ifdef ALLOC_HAX copy = (TagInfo *) TreeAlloc_Alloc(tree->allocData, TagInfoUid, TAG_INFO_SIZE(tagSpace)); #else copy = (TagInfo *) ckalloc(TAG_INFO_SIZE(tagSpace)); #endif memcpy((void *) copy->tagPtr, tagInfo->tagPtr, tagInfo->numTags * sizeof(Tk_Uid)); copy->numTags = tagInfo->numTags; copy->tagSpace = tagSpace; } return copy; } /* *---------------------------------------------------------------------- * * TagInfo_Free -- * * Free a list of tags. * * Results: * TagInfo struct is freed if non-NULL. * * Side effects: * Memory may be freed. * *---------------------------------------------------------------------- */ void TagInfo_Free( TreeCtrl *tree, /* Widget info. */ TagInfo *tagInfo /* Tag list. May be NULL. */ ) { if (tagInfo != NULL) #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, TagInfoUid, (char *) tagInfo, TAG_INFO_SIZE(tagInfo->tagSpace)); #else ckfree((char *) tagInfo); #endif } int TagInfo_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *objPtr, TagInfo **tagInfoPtr ) { int i, numTags; Tcl_Obj **listObjv; TagInfo *tagInfo = NULL; if (Tcl_ListObjGetElements(tree->interp, objPtr, &numTags, &listObjv) != TCL_OK) { return TCL_ERROR; } if (numTags == 0) { *tagInfoPtr = NULL; return TCL_OK; } for (i = 0; i < numTags; i++) { Tk_Uid tag = Tk_GetUid(Tcl_GetString(listObjv[i])); tagInfo = TagInfo_Add(tree, tagInfo, &tag, 1); } *tagInfoPtr = tagInfo; return TCL_OK; } static Tcl_Obj * TagInfo_ToObj( TreeCtrl *tree, /* Widget info. */ TagInfo *tagInfo ) { Tcl_Obj *listObj; int i; if (tagInfo == NULL) return NULL; listObj = Tcl_NewListObj(0, NULL); for (i = 0; i < tagInfo->numTags; i++) { Tcl_ListObjAppendElement(NULL, listObj, Tcl_NewStringObj((char *) tagInfo->tagPtr[i], -1)); } return listObj; } /* *---------------------------------------------------------------------- * * TagInfoCO_Set -- * TagInfoCO_Get -- * TagInfoCO_Restore -- * TagInfoCO_Free -- * * These procedures implement a TK_OPTION_CUSTOM where the custom * option is a TagInfo record. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TagInfoCO_Set( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; int objEmpty; TagInfo *new, **internalPtr; if (internalOffset >= 0) internalPtr = (TagInfo **) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*value)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) (*value) = NULL; else { if (TagInfo_FromObj(tree, (*value), &new) != TCL_OK) return TCL_ERROR; } if (internalPtr != NULL) { if ((*value) == NULL) new = NULL; *((TagInfo **) saveInternalPtr) = *internalPtr; *internalPtr = new; } return TCL_OK; } static Tcl_Obj * TagInfoCO_Get( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; TagInfo *value = *(TagInfo **) (recordPtr + internalOffset); return TagInfo_ToObj(tree, value); } static void TagInfoCO_Restore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr ) { *(TagInfo **) internalPtr = *(TagInfo **) saveInternalPtr; } static void TagInfoCO_Free( ClientData clientData, /* unused. */ Tk_Window tkwin, /* A window; unused */ char *internalPtr /* Pointer to the place, where the internal * form resides. */ ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; TagInfo_Free(tree, *(TagInfo **)internalPtr); } Tk_ObjCustomOption TreeCtrlCO_tagInfo = { "tag list", TagInfoCO_Set, TagInfoCO_Get, TagInfoCO_Restore, TagInfoCO_Free, (ClientData) NULL }; /* *---------------------------------------------------------------------- * * TagExpr_Init -- * * This procedure initializes a TagExpr struct by parsing a Tcl_Obj * string representation of a tag expression. * * Results: * A standard Tcl result. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ int TagExpr_Init( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *exprObj, /* Tag expression string. */ TagExpr *expr /* Struct to initialize. */ ) { int i; char *tag; expr->tree = tree; expr->index = 0; expr->length = 0; expr->uid = NULL; expr->allocated = sizeof(expr->staticUids) / sizeof(Tk_Uid); expr->uids = expr->staticUids; expr->simple = TRUE; expr->rewritebuffer = expr->staticRWB; tag = Tcl_GetStringFromObj(exprObj, &expr->stringLength); /* short circuit impossible searches for null tags */ if (expr->stringLength == 0) { return TCL_OK; } /* * Pre-scan tag for at least one unquoted "&&" "||" "^" "!" * if not found then use string as simple tag */ for (i = 0; i < expr->stringLength ; i++) { if (tag[i] == '"') { i++; for ( ; i < expr->stringLength; i++) { if (tag[i] == '\\') { i++; continue; } if (tag[i] == '"') { break; } } } else { if ((tag[i] == '&' && tag[i+1] == '&') || (tag[i] == '|' && tag[i+1] == '|') || (tag[i] == '^') || (tag[i] == '!')) { expr->simple = FALSE; break; } } } if (expr->simple) { expr->uid = Tk_GetUid(tag); return TCL_OK; } expr->string = tag; expr->stringIndex = 0; /* Allocate buffer for rewritten tags (after de-escaping) */ if (expr->stringLength >= sizeof(expr->staticRWB)) expr->rewritebuffer = ckalloc(expr->stringLength + 1); if (TagExpr_Scan(expr) != TCL_OK) { TagExpr_Free(expr); return TCL_ERROR; } expr->length = expr->index; return TCL_OK; } /* * Uids for operands in compiled tag expressions. * Initialization is done by GetStaticUids(). */ typedef struct { Tk_Uid andUid; Tk_Uid orUid; Tk_Uid xorUid; Tk_Uid parenUid; Tk_Uid negparenUid; Tk_Uid endparenUid; Tk_Uid tagvalUid; Tk_Uid negtagvalUid; } SearchUids; static Tcl_ThreadDataKey searchUidTDK; /* *---------------------------------------------------------------------- * * GetStaticUids -- * * This procedure is invoked to return a structure filled with * the Uids used when doing tag searching. If it was never before * called in the current thread, it initializes the structure for * that thread (uids are only ever local to one thread [Bug * 1114977]). * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static SearchUids * GetStaticUids() { SearchUids *searchUids = (SearchUids *) Tcl_GetThreadData(&searchUidTDK, sizeof(SearchUids)); if (searchUids->andUid == NULL) { searchUids->andUid = Tk_GetUid("&&"); searchUids->orUid = Tk_GetUid("||"); searchUids->xorUid = Tk_GetUid("^"); searchUids->parenUid = Tk_GetUid("("); searchUids->endparenUid = Tk_GetUid(")"); searchUids->negparenUid = Tk_GetUid("!("); searchUids->tagvalUid = Tk_GetUid("!!"); searchUids->negtagvalUid = Tk_GetUid("!"); } return searchUids; } /* *---------------------------------------------------------------------- * * TagExpr_Scan -- * * This procedure recursively parses a string representation of a * tag expression into an array of Tk_Uids. * * Results: * The return value indicates if the tag expression * was successfully scanned (syntax). * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ int TagExpr_Scan( TagExpr *expr /* Info about a tag expression. */ ) { Tcl_Interp *interp = expr->tree->interp; int looking_for_tag; /* When true, scanner expects * next char(s) to be a tag, * else operand expected */ int found_tag; /* One or more tags found */ int found_endquote; /* For quoted tag string parsing */ int negate_result; /* Pending negation of next tag value */ char *tag; /* tag from tag expression string */ SearchUids *searchUids; /* Collection of uids for basic search * expression terms. */ char c; searchUids = GetStaticUids(); negate_result = 0; found_tag = 0; looking_for_tag = 1; while (expr->stringIndex < expr->stringLength) { c = expr->string[expr->stringIndex++]; if (expr->allocated == expr->index) { expr->allocated += 15; if (expr->uids != expr->staticUids) { expr->uids = (Tk_Uid *) ckrealloc((char *)(expr->uids), (expr->allocated)*sizeof(Tk_Uid)); } else { expr->uids = (Tk_Uid *) ckalloc((expr->allocated)*sizeof(Tk_Uid)); memcpy((void *) expr->uids, expr->staticUids, sizeof(expr->staticUids)); } } if (looking_for_tag) { switch (c) { case ' ' : /* ignore unquoted whitespace */ case '\t' : case '\n' : case '\r' : break; case '!' : /* negate next tag or subexpr */ if (looking_for_tag > 1) { Tcl_AppendResult(interp, "Too many '!' in tag search expression", (char *) NULL); return TCL_ERROR; } looking_for_tag++; negate_result = 1; break; case '(' : /* scan (negated) subexpr recursively */ if (negate_result) { expr->uids[expr->index++] = searchUids->negparenUid; negate_result = 0; } else { expr->uids[expr->index++] = searchUids->parenUid; } if (TagExpr_Scan(expr) != TCL_OK) { /* Result string should be already set * by nested call to tag_expr_scan() */ return TCL_ERROR; } looking_for_tag = 0; found_tag = 1; break; case '"' : /* quoted tag string */ if (negate_result) { expr->uids[expr->index++] = searchUids->negtagvalUid; negate_result = 0; } else { expr->uids[expr->index++] = searchUids->tagvalUid; } tag = expr->rewritebuffer; found_endquote = 0; while (expr->stringIndex < expr->stringLength) { c = expr->string[expr->stringIndex++]; if (c == '\\') { c = expr->string[expr->stringIndex++]; } if (c == '"') { found_endquote = 1; break; } *tag++ = c; } if (! found_endquote) { Tcl_AppendResult(interp, "Missing endquote in tag search expression", (char *) NULL); return TCL_ERROR; } if (! (tag - expr->rewritebuffer)) { Tcl_AppendResult(interp, "Null quoted tag string in tag search expression", (char *) NULL); return TCL_ERROR; } *tag++ = '\0'; expr->uids[expr->index++] = Tk_GetUid(expr->rewritebuffer); looking_for_tag = 0; found_tag = 1; break; case '&' : /* illegal chars when looking for tag */ case '|' : case '^' : case ')' : Tcl_AppendResult(interp, "Unexpected operator in tag search expression", (char *) NULL); return TCL_ERROR; default : /* unquoted tag string */ if (negate_result) { expr->uids[expr->index++] = searchUids->negtagvalUid; negate_result = 0; } else { expr->uids[expr->index++] = searchUids->tagvalUid; } tag = expr->rewritebuffer; *tag++ = c; /* copy rest of tag, including any embedded whitespace */ while (expr->stringIndex < expr->stringLength) { c = expr->string[expr->stringIndex]; if (c == '!' || c == '&' || c == '|' || c == '^' || c == '(' || c == ')' || c == '"') { break; } *tag++ = c; expr->stringIndex++; } /* remove trailing whitespace */ while (1) { c = *--tag; /* there must have been one non-whitespace char, * so this will terminate */ if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { break; } } *++tag = '\0'; expr->uids[expr->index++] = Tk_GetUid(expr->rewritebuffer); looking_for_tag = 0; found_tag = 1; } } else { /* ! looking_for_tag */ switch (c) { case ' ' : /* ignore whitespace */ case '\t' : case '\n' : case '\r' : break; case '&' : /* AND operator */ c = expr->string[expr->stringIndex++]; if (c != '&') { Tcl_AppendResult(interp, "Singleton '&' in tag search expression", (char *) NULL); return TCL_ERROR; } expr->uids[expr->index++] = searchUids->andUid; looking_for_tag = 1; break; case '|' : /* OR operator */ c = expr->string[expr->stringIndex++]; if (c != '|') { Tcl_AppendResult(interp, "Singleton '|' in tag search expression", (char *) NULL); return TCL_ERROR; } expr->uids[expr->index++] = searchUids->orUid; looking_for_tag = 1; break; case '^' : /* XOR operator */ expr->uids[expr->index++] = searchUids->xorUid; looking_for_tag = 1; break; case ')' : /* end subexpression */ expr->uids[expr->index++] = searchUids->endparenUid; goto breakwhile; default : /* syntax error */ Tcl_AppendResult(interp, "Invalid boolean operator in tag search expression", (char *) NULL); return TCL_ERROR; } } } breakwhile: if (found_tag && ! looking_for_tag) { return TCL_OK; } Tcl_AppendResult(interp, "Missing tag in tag search expression", (char *) NULL); return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TagExpr_Eval -- * * This procedure recursively evaluates a compiled tag expression. * * Results: * The return value indicates if the tag expression * successfully matched the tags of the given item. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int _TagExpr_Eval( TagExpr *expr, /* Info about a tag expression. */ TagInfo *tagInfo /* Tags to test. */ ) { int looking_for_tag; /* When true, scanner expects * next char(s) to be a tag, * else operand expected */ int negate_result; /* Pending negation of next tag value */ Tk_Uid uid; Tk_Uid *tagPtr; int count; int result; /* Value of expr so far */ int parendepth; SearchUids *searchUids; /* Collection of uids for basic search * expression terms. */ TagInfo dummy; if (expr->stringLength == 0) /* empty expression (an error?) */ return 0; /* No tags given. */ if (tagInfo == NULL) { dummy.numTags = 0; tagInfo = &dummy; } /* A single tag. */ if (expr->simple) { for (tagPtr = tagInfo->tagPtr, count = tagInfo->numTags; count > 0; tagPtr++, count--) { if (*tagPtr == expr->uid) { return 1; } } return 0; } searchUids = GetStaticUids(); result = 0; /* just to keep the compiler quiet */ negate_result = 0; looking_for_tag = 1; while (expr->index < expr->length) { uid = expr->uids[expr->index++]; if (looking_for_tag) { if (uid == searchUids->tagvalUid) { /* * assert(expr->index < expr->length); */ uid = expr->uids[expr->index++]; result = 0; /* * set result 1 if tag is found in item's tags */ for (tagPtr = tagInfo->tagPtr, count = tagInfo->numTags; count > 0; tagPtr++, count--) { if (*tagPtr == uid) { result = 1; break; } } } else if (uid == searchUids->negtagvalUid) { negate_result = ! negate_result; /* * assert(expr->index < expr->length); */ uid = expr->uids[expr->index++]; result = 0; /* * set result 1 if tag is found in item's tags */ for (tagPtr = tagInfo->tagPtr, count = tagInfo->numTags; count > 0; tagPtr++, count--) { if (*tagPtr == uid) { result = 1; break; } } } else if (uid == searchUids->parenUid) { /* * evaluate subexpressions with recursion */ result = _TagExpr_Eval(expr, tagInfo); } else if (uid == searchUids->negparenUid) { negate_result = ! negate_result; /* * evaluate subexpressions with recursion */ result = _TagExpr_Eval(expr, tagInfo); /* * } else { * assert(0); */ } if (negate_result) { result = ! result; negate_result = 0; } looking_for_tag = 0; } else { /* ! looking_for_tag */ if (((uid == searchUids->andUid) && (!result)) || ((uid == searchUids->orUid) && result)) { /* * short circuit expression evaluation * * if result before && is 0, or result before || is 1, * then the expression is decided and no further * evaluation is needed. */ parendepth = 0; while (expr->index < expr->length) { uid = expr->uids[expr->index++]; if (uid == searchUids->tagvalUid || uid == searchUids->negtagvalUid) { expr->index++; continue; } if (uid == searchUids->parenUid || uid == searchUids->negparenUid) { parendepth++; continue; } if (uid == searchUids->endparenUid) { parendepth--; if (parendepth < 0) { break; } } } return result; } else if (uid == searchUids->xorUid) { /* * if the previous result was 1 * then negate the next result */ negate_result = result; } else if (uid == searchUids->endparenUid) { return result; /* * } else { * assert(0); */ } looking_for_tag = 1; } } /* * assert(! looking_for_tag); */ return result; } int TagExpr_Eval( TagExpr *expr, /* Info about a tag expression. */ TagInfo *tagInfo /* Tags to test. */ ) { expr->index = 0; return _TagExpr_Eval(expr, tagInfo); } /* *---------------------------------------------------------------------- * * TagExpr_Free -- * * This procedure frees the given struct. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TagExpr_Free( TagExpr *expr ) { if (expr->rewritebuffer != expr->staticRWB) ckfree(expr->rewritebuffer); if (expr->uids != expr->staticUids) ckfree((char *) expr->uids); } /* *---------------------------------------------------------------------- * * OptionHax_Remember -- * OptionHax_Forget -- * * These procedures are used to work around a limitation in * the Tk_SavedOption structure: the internal form of a configuration * option cannot be larger than a double. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void OptionHax_Remember( TreeCtrl *tree, char *ptr ) { #ifdef TREECTRL_DEBUG int i; for (i = 0; i < tree->optionHaxCnt; i++) { if (ptr == tree->optionHax[i]) { panic("OptionHax_Remember: ptr is not new"); } } if (tree->optionHaxCnt == sizeof(tree->optionHax) / sizeof(tree->optionHax[0])) panic("OptionHax_Remember: too many options"); #endif tree->optionHax[tree->optionHaxCnt++] = ptr; /*dbwin("OptionHax_Remember %p\n", ptr);*/ } static int OptionHax_Forget( TreeCtrl *tree, char *ptr ) { int i; for (i = 0; i < tree->optionHaxCnt; i++) { if (ptr == tree->optionHax[i]) { tree->optionHax[i] = tree->optionHax[--tree->optionHaxCnt]; /*dbwin("OptionHax_Forget %p\n", ptr);*/ return 1; } } return 0; } /* *---------------------------------------------------------------------- * * Tree_FindOptionSpec -- * * Return a pointer to a name Tk_OptionSpec in a table. * * Results: * Returns a pointer or panics. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tk_OptionSpec * Tree_FindOptionSpec( Tk_OptionSpec *optionTable, CONST char *optionName ) { while (optionTable->type != TK_OPTION_END) { if (strcmp(optionTable->optionName, optionName) == 0) return optionTable; optionTable++; } panic("Tree_FindOptionSpec: can't find %s", optionName); return NULL; } /* *---------------------------------------------------------------------- * * PerStateCO_Set -- * PerStateCO_Get -- * PerStateCO_Restore -- * PerStateCO_Free -- * * These procedures implement a TK_OPTION_CUSTOM where the custom * option is a PerStateInfo record. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ typedef struct PerStateCOClientData { PerStateType *typePtr; StateFromObjProc proc; } PerStateCOClientData; static int PerStateCO_Set( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags ) { PerStateCOClientData *cd = (PerStateCOClientData *) clientData; TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; int objEmpty; PerStateInfo new, *internalPtr, *hax; if (internalOffset >= 0) internalPtr = (PerStateInfo *) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*value)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) (*value) = NULL; else { new.obj = (*value); new.data = NULL; new.count = 0; /* Tcl_IncrRefCount((*value));*/ if (tree->configStateDomain == -1) panic("PerStateCO_Set configStateDomain == -1"); if (PerStateInfo_FromObj(tree, tree->configStateDomain, cd->proc, cd->typePtr, &new) != TCL_OK) { /* Tcl_DecrRefCount((*value));*/ return TCL_ERROR; } } if (internalPtr != NULL) { if ((*value) == NULL) { new.obj = NULL; new.data = NULL; new.count = 0; } OptionHax_Remember(tree, saveInternalPtr); if (internalPtr->obj != NULL) { hax = (PerStateInfo *) ckalloc(sizeof(PerStateInfo)); *hax = *internalPtr; *((PerStateInfo **) saveInternalPtr) = hax; } else { *((PerStateInfo **) saveInternalPtr) = NULL; } *internalPtr = new; /*dbwin("PerStateCO_Set %p %s\n", internalPtr, cd->typePtr->name);*/ } return TCL_OK; } static Tcl_Obj * PerStateCO_Get( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset ) { PerStateInfo *value = (PerStateInfo *) (recordPtr + internalOffset); return value->obj; /* May be NULL. */ } static void PerStateCO_Restore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; PerStateInfo *psi = (PerStateInfo *) internalPtr; PerStateInfo *hax = *(PerStateInfo **) saveInternalPtr; /*dbwin("PerStateCO_Restore\n");*/ if (hax != NULL) { #ifdef TREECTRL_DEBUG psi->type = hax->type; #endif psi->data = hax->data; psi->count = hax->count; ckfree((char *) hax); } else { #ifdef TREECTRL_DEBUG psi->type = NULL; #endif /* psi->obj = NULL;*/ psi->data = NULL; psi->count = 0; } OptionHax_Forget(tree, saveInternalPtr); } static void PerStateCO_Free( ClientData clientData, /* unused. */ Tk_Window tkwin, /* A window; unused */ char *internalPtr /* Pointer to the place, where the internal * form resides. */ ) { PerStateCOClientData *cd = (PerStateCOClientData *) clientData; TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; PerStateInfo *hax; Tcl_Obj *objPtr = NULL; if (OptionHax_Forget(tree, internalPtr)) { hax = *(PerStateInfo **) internalPtr; if (hax != NULL) { objPtr = hax->obj; PerStateInfo_Free(tree, cd->typePtr, hax); ckfree((char *) hax); } } else { /*dbwin("PerStateCO_Free %p %s\n", internalPtr, cd->typePtr->name);*/ objPtr = ((PerStateInfo *) internalPtr)->obj; PerStateInfo_Free(tree, cd->typePtr, (PerStateInfo *) internalPtr); } /* if (objPtr != NULL) Tcl_DecrRefCount(objPtr);*/ } /* *---------------------------------------------------------------------- * * PerStateCO_Alloc -- * * Allocates a Tk_ObjCustomOption record and clientData. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ Tk_ObjCustomOption * PerStateCO_Alloc( CONST char *optionName, PerStateType *typePtr, StateFromObjProc proc ) { PerStateCOClientData *cd; Tk_ObjCustomOption *co; /* ClientData for the Tk custom option record */ cd = (PerStateCOClientData *) ckalloc(sizeof(PerStateCOClientData)); cd->typePtr = typePtr; cd->proc = proc; /* The Tk custom option record */ co = (Tk_ObjCustomOption *) ckalloc(sizeof(Tk_ObjCustomOption)); co->name = (char *) optionName + 1; co->setProc = PerStateCO_Set; co->getProc = PerStateCO_Get; co->restoreProc = PerStateCO_Restore; co->freeProc = PerStateCO_Free; co->clientData = (ClientData) cd; return co; } /* *---------------------------------------------------------------------- * * PerStateCO_Init -- * * Initializes a Tk_OptionSpec.clientData for a custom option. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int PerStateCO_Init( Tk_OptionSpec *optionTable, CONST char *optionName, PerStateType *typePtr, StateFromObjProc proc ) { Tk_OptionSpec *specPtr; specPtr = Tree_FindOptionSpec(optionTable, optionName); if (specPtr->type != TK_OPTION_CUSTOM) panic("PerStateCO_Init: %s is not TK_OPTION_CUSTOM", optionName); if (specPtr->clientData != NULL) return TCL_OK; specPtr->clientData = PerStateCO_Alloc(optionName, typePtr, proc); return TCL_OK; } #define DEBUG_DYNAMICxxx static CONST char *DynamicOptionUid = "DynamicOption"; /* *---------------------------------------------------------------------- * * DynamicOption_Find -- * * Returns a pointer to a dynamic-option record or NULL. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static DynamicOption * DynamicOption_Find( DynamicOption *first, /* Head of linked list. */ int id /* Unique id. */ ) { DynamicOption *opt = first; while (opt != NULL) { if (opt->id == id) return opt; opt = opt->next; } return NULL; } /* *---------------------------------------------------------------------- * * DynamicOption_FindData -- * * Returns a pointer to the option-specific data for a * dynamic-option record or NULL. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void * DynamicOption_FindData( DynamicOption *first, /* Head of linked list. */ int id /* Unique id. */ ) { DynamicOption *opt = DynamicOption_Find(first, id); if (opt != NULL) return opt->data; return NULL; } /* *---------------------------------------------------------------------- * * DynamicOption_AllocIfNeeded -- * * Returns a pointer to a dynamic-option record. * * Results: * If the dynamic-option record exists, it is returned. Otherwise * a new one is allocated and initialized. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ DynamicOption * DynamicOption_AllocIfNeeded( TreeCtrl *tree, DynamicOption **firstPtr, /* Pointer to the head of linked list. * Will be updated if a new record is * created. */ int id, /* Unique id. */ int size, /* Size of option-specific data. */ DynamicOptionInitProc *init /* Proc to intialize the option-specific * data. May be NULL. */ ) { DynamicOption *opt = *firstPtr; while (opt != NULL) { if (opt->id == id) return opt; opt = opt->next; } #ifdef DEBUG_DYNAMIC dbwin("DynamicOption_AllocIfNeeded allocated id=%d\n", id); #endif #ifdef ALLOC_HAX opt = (DynamicOption *) TreeAlloc_Alloc(tree->allocData, DynamicOptionUid, Tk_Offset(DynamicOption, data) + size); #else opt = (DynamicOption *) ckalloc(Tk_Offset(DynamicOption, data) + size); #endif opt->id = id; memset(opt->data, '\0', size); if (init != NULL) (*init)(opt->data); opt->next = *firstPtr; *firstPtr = opt; return opt; } /* *---------------------------------------------------------------------- * * DynamicCO_Set -- * DynamicCO_Get -- * DynamicCO_Restore -- * DynamicCO_Free -- * * These procedures implement a TK_OPTION_CUSTOM where the custom * option is a DynamicOption record. * * A dynamic option is one for which storage is not allocated until * the option is configured for the first time. Dynamic options are * saved in a linked list. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ /* This is the Tk_OptionSpec.clientData field for a dynamic option. */ typedef struct DynamicCOClientData { int id; /* Unique id. */ int size; /* Size of client data. */ int objOffset; /* Offset in the client data to store the * object representation of the option. * May be < 0. */ int internalOffset; /* Offset in the client data to store the * internal representation of the option. * May be < 0. */ Tk_ObjCustomOption *custom; /* Table of procedures and clientData for * the actual option. */ DynamicOptionInitProc *init;/* This gets called to initialize the client * data when it is first allocated. May be * NULL. */ } DynamicCOClientData; /* This is used to save the current value of an option when a call to * Tk_SetOptions is in progress. */ typedef struct DynamicCOSave { Tcl_Obj *objPtr; /* The object representation of the option. */ double internalForm; /* The internal form of the option. */ } DynamicCOSave; static int DynamicCO_Set( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; DynamicCOClientData *cd = clientData; DynamicOption **firstPtr, *opt; DynamicCOSave *save; Tcl_Obj **objPtrPtr = NULL; /* Get pointer to the head of the list of dynamic options. */ firstPtr = (DynamicOption **) (recordPtr + internalOffset); /* Get the dynamic option record. Create it if needed, and update the * linked list of dynamic options. */ opt = DynamicOption_AllocIfNeeded(tree, firstPtr, cd->id, cd->size, cd->init); if (cd->objOffset >= 0) objPtrPtr = (Tcl_Obj **) (opt->data + cd->objOffset); save = (DynamicCOSave *) ckalloc(sizeof(DynamicCOSave)); #ifdef DEBUG_DYNAMIC dbwin("DynamicCO_Set id=%d saveInternalPtr=%p save=%p\n", cd->id, saveInternalPtr, save); #endif if (objPtrPtr != NULL) { save->objPtr = *objPtrPtr; #ifdef DEBUG_DYNAMIC if (save->objPtr) dbwin(" old object '%s' refCount=%d\n", Tcl_GetString(save->objPtr), save->objPtr->refCount); else dbwin(" old object NULL\n"); #endif } if (cd->custom->setProc(cd->custom->clientData, interp, tkwin, value, opt->data, cd->internalOffset, (char *) &save->internalForm, flags) != TCL_OK) { ckfree((char *) save); return TCL_ERROR; } if (objPtrPtr != NULL) { #ifdef DEBUG_DYNAMIC if (*value) dbwin(" new object '%s' refCount=%d\n", Tcl_GetString(*value), (*value)->refCount); else dbwin(" new object NULL\n"); #endif *objPtrPtr = *value; if (*value != NULL) Tcl_IncrRefCount(*value); } *(DynamicCOSave **) saveInternalPtr = save; OptionHax_Remember(tree, saveInternalPtr); return TCL_OK; } static Tcl_Obj * DynamicCO_Get( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset ) { DynamicCOClientData *cd = clientData; DynamicOption *first = *(DynamicOption **) (recordPtr + internalOffset); DynamicOption *opt = DynamicOption_Find(first, cd->id); #ifdef DEBUG_DYNAMIC dbwin("DynamicCO_Get id=%d opt=%p objOffset=%d\n", cd->id, opt, cd->objOffset); #endif if (opt == NULL) return NULL; if (cd->objOffset >= 0) { #ifdef TREECTRL_DEBUG Tcl_Obj *objPtr = *(Tcl_Obj **) (opt->data + cd->objOffset); if (objPtr && objPtr->refCount == 0) panic("DynamicCO_Get refCount=0"); #endif return *(Tcl_Obj **) (opt->data + cd->objOffset); } if (cd->custom->getProc != NULL) return cd->custom->getProc(cd->custom->clientData, tkwin, opt->data, cd->internalOffset); return NULL; } static void DynamicCO_Restore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; DynamicCOClientData *cd = clientData; DynamicOption *first = *(DynamicOption **) internalPtr; DynamicOption *opt = DynamicOption_Find(first, cd->id); DynamicCOSave *save = *(DynamicCOSave **)saveInternalPtr; Tcl_Obj **objPtrPtr; if (opt == NULL) panic("DynamicCO_Restore: opt=NULL"); #ifdef DEBUG_DYNAMIC dbwin("DynamicCO_Restore id=%d internalOffset=%d save=%p\n", cd->id, cd->internalOffset, save); #endif if (cd->internalOffset >= 0 && cd->custom->restoreProc != NULL) cd->custom->restoreProc(cd->custom->clientData, tkwin, opt->data + cd->internalOffset, (char *) &save->internalForm); if (cd->objOffset >= 0) { objPtrPtr = (Tcl_Obj **) (opt->data + cd->objOffset); #ifdef DEBUG_DYNAMIC if (*objPtrPtr) dbwin("DynamicCO_Restore replace object '%s' refCount=%d\n", Tcl_GetString(*objPtrPtr), (*objPtrPtr)->refCount); else dbwin("DynamicCO_Restore replace object NULL\n"); if (save->objPtr) dbwin("DynamicCO_Restore restore object '%s' refCount=%d\n", Tcl_GetString(save->objPtr), save->objPtr->refCount); else dbwin("DynamicCO_Restore restore object NULL\n"); #endif /* if (*objPtrPtr != NULL) Tcl_DecrRefCount(*objPtrPtr);*/ *objPtrPtr = save->objPtr; } ckfree((char *) save); OptionHax_Forget(tree, saveInternalPtr); } static void DynamicCO_Free( ClientData clientData, Tk_Window tkwin, char *internalPtr ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; DynamicCOClientData *cd = clientData; Tcl_Obj **objPtrPtr; if (OptionHax_Forget(tree, internalPtr)) { DynamicCOSave *save = *(DynamicCOSave **) internalPtr; #ifdef DEBUG_DYNAMIC dbwin("DynamicCO_Free id=%d internalPtr=%p save=%p\n", cd->id, internalPtr, save); #endif if (cd->internalOffset >= 0 && cd->custom->freeProc != NULL) cd->custom->freeProc(cd->custom->clientData, tkwin, (char *) &save->internalForm); if (cd->objOffset >= 0) { #ifdef DEBUG_DYNAMIC if (save->objPtr) { dbwin("DynamicCO_Free free object '%s' refCount=%d-1\n", Tcl_GetString(save->objPtr), (save->objPtr)->refCount); if (save->objPtr->refCount == 0) panic("DynamicCO_Free refCount=0"); } else dbwin("DynamicCO_Free free object NULL\n"); #endif if (save->objPtr) { Tcl_DecrRefCount(save->objPtr); } } ckfree((char *) save); } else { DynamicOption *first = *(DynamicOption **) internalPtr; DynamicOption *opt = DynamicOption_Find(first, cd->id); #ifdef DEBUG_DYNAMIC dbwin("DynamicCO_Free id=%d internalPtr=%p save=NULL\n", cd->id, internalPtr); #endif if (opt != NULL && cd->internalOffset >= 0 && cd->custom->freeProc != NULL) cd->custom->freeProc(cd->custom->clientData, tkwin, opt->data + cd->internalOffset); if (opt != NULL && cd->objOffset >= 0) { objPtrPtr = (Tcl_Obj **) (opt->data + cd->objOffset); #ifdef DEBUG_DYNAMIC if (*objPtrPtr) { dbwin("DynamicCO_Free free object '%s' refCount=%d-1\n", Tcl_GetString(*objPtrPtr), (*objPtrPtr)->refCount); if ((*objPtrPtr)->refCount == 0) panic("DynamicCO_Free refCount=0"); } else dbwin("DynamicCO_Free free object NULL\n"); #endif if (*objPtrPtr != NULL) { Tcl_DecrRefCount(*objPtrPtr); } } } } /* *---------------------------------------------------------------------- * * DynamicOption_Init -- * * Initialize a Tk_OptionSpec.clientData field before calling * Tk_CreateOptionTable. * * Results: * None. * * Side effects: * Memory may be allocated. * *---------------------------------------------------------------------- */ int DynamicCO_Init( Tk_OptionSpec *optionTable, /* Table to search. */ CONST char *optionName, /* Name of the option. */ int id, /* Unique id. */ int size, /* Size of client data. */ int objOffset, /* Offset in the client data to store the * object representation of the option. * May be < 0. */ int internalOffset, /* Offset in the client data to store the * internal representation of the option. * May be < 0. */ Tk_ObjCustomOption *custom, /* Table of procedures and clientData for * the actual option. */ DynamicOptionInitProc *init /* This gets called to initialize the client * data when it is first allocated. May be * NULL. */ ) { Tk_OptionSpec *specPtr; DynamicCOClientData *cd; Tk_ObjCustomOption *co; if (size <= 0) panic("DynamicCO_Init: option %s size=%d", optionName, size); specPtr = Tree_FindOptionSpec(optionTable, optionName); if (specPtr->type != TK_OPTION_CUSTOM) panic("DynamicCO_Init: %s is not TK_OPTION_CUSTOM", optionName); if (specPtr->clientData != NULL) return TCL_OK; /* ClientData for the Tk custom option record */ cd = (DynamicCOClientData *) ckalloc(sizeof(DynamicCOClientData)); cd->id = id; cd->size = size; cd->objOffset = objOffset; cd->internalOffset = internalOffset; cd->custom = custom; cd->init = init; /* The Tk custom option record */ co = (Tk_ObjCustomOption *) ckalloc(sizeof(Tk_ObjCustomOption)); co->name = (char *) optionName + 1; co->setProc = DynamicCO_Set; co->getProc = DynamicCO_Get; co->restoreProc = DynamicCO_Restore; co->freeProc = DynamicCO_Free; co->clientData = (ClientData) cd; /* Update the option table */ specPtr->clientData = co; #ifdef DEBUG_DYNAMIC dbwin("DynamicCO_Init id=%d size=%d objOffset=%d internalOffset=%d custom->name=%s\n", id, size, objOffset, internalOffset, custom->name); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * DynamicOption_Free -- * * Free a linked list of dynamic-option records. This gets called * after Tk_FreeConfigOptions. * * Results: * None. * * Side effects: * Memory may be freed. * *---------------------------------------------------------------------- */ void DynamicOption_Free( TreeCtrl *tree, DynamicOption *first, Tk_OptionSpec *optionTable ) { DynamicOption *opt = first; DynamicCOClientData *cd; Tk_ObjCustomOption *co; int i; while (opt != NULL) { DynamicOption *next = opt->next; for (i = 0; optionTable[i].type != TK_OPTION_END; i++) { if (optionTable[i].type != TK_OPTION_CUSTOM) continue; co = (Tk_ObjCustomOption *) optionTable[i].clientData; if (co->setProc != DynamicCO_Set) continue; cd = (DynamicCOClientData *) co->clientData; if (cd->id != opt->id) continue; #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, DynamicOptionUid, (char *) opt, Tk_Offset(DynamicOption, data) + cd->size); #else ckfree((char *) opt); #endif break; } opt = next; } } /* *---------------------------------------------------------------------- * * DynamicOption_Free1 -- * * Free a single dynamic-option record. This is a big hack so that * dynamic-option records that aren't associated with a Tk_OptionSpec * array can be used. * * Results: * None. * * Side effects: * Memory may be freed. * *---------------------------------------------------------------------- */ void DynamicOption_Free1( TreeCtrl *tree, DynamicOption **firstPtr, int id, int size ) { DynamicOption *opt = *firstPtr, *prev = NULL; while (opt != NULL) { if (opt->id == id) { if (prev == NULL) *firstPtr = opt->next; else prev->next = opt->next; #ifdef ALLOC_HAX TreeAlloc_Free(tree->allocData, DynamicOptionUid, (char *) opt, Tk_Offset(DynamicOption, data) + size); #else ckfree((char *) opt); #endif return; } prev = opt; opt = opt->next; } } /* *---------------------------------------------------------------------- * * Tree_InitOptions -- * Tree_SetOptions -- * * These procedures are just wrappers around Tk_InitOptions and * Tk_SetOptions. They set tree->configStateDomain so that any * per-state options know which state domain to use. * * Results: * A standard Tcl result. * * Side effects: * Whatever the wrapped function does. * *---------------------------------------------------------------------- */ int Tree_InitOptions( TreeCtrl *tree, int domain, void *recordPtr, Tk_OptionTable optionTable ) { int result; if (tree->configStateDomain != -1) panic("Tree_InitOptions configStateDomain != -1"); tree->configStateDomain = domain; result = Tk_InitOptions(tree->interp, recordPtr, optionTable, tree->tkwin); tree->configStateDomain = -1; return result; } int Tree_SetOptions( TreeCtrl *tree, int domain, void *recordPtr, Tk_OptionTable optionTable, int objc, Tcl_Obj *CONST objv[], Tk_SavedOptions *savePtr, int *maskPtr ) { int result; if (tree->configStateDomain != -1) panic("Tree_SetOptions configStateDomain != -1"); tree->configStateDomain = domain; result = Tk_SetOptions(tree->interp, recordPtr, optionTable, objc, objv, tree->tkwin, savePtr, maskPtr); tree->configStateDomain = -1; return result; } /* *---------------------------------------------------------------------- * * StringCO_Set -- * StringCO_Get -- * StringCO_Restore -- * StringCO_Free -- * * These procedures implement a TK_OPTION_CUSTOM where the custom * option is exactly the same as a TK_OPTION_STRING. This is used * when storage for the option is dynamically allocated. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int StringCO_Set( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **valuePtr, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags ) { int objEmpty; char *internalPtr, *new, *value; int length; if (internalOffset >= 0) internalPtr = (char *) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*valuePtr)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) (*valuePtr) = NULL; if (internalPtr != NULL) { if (*valuePtr != NULL) { value = Tcl_GetStringFromObj(*valuePtr, &length); new = ckalloc((unsigned) (length + 1)); strcpy(new, value); } else { new = NULL; } *((char **) saveInternalPtr) = *((char **) internalPtr); *((char **) internalPtr) = new; } return TCL_OK; } static Tcl_Obj * StringCO_Get( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset ) { char **internalPtr = (char **) (recordPtr + internalOffset); return Tcl_NewStringObj(*internalPtr, -1); } static void StringCO_Restore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr ) { *(char **) internalPtr = *(char **) saveInternalPtr; } static void StringCO_Free( ClientData clientData, Tk_Window tkwin, char *internalPtr ) { if (*((char **) internalPtr) != NULL) { ckfree(*((char **) internalPtr)); *((char **) internalPtr) = NULL; } } Tk_ObjCustomOption TreeCtrlCO_string = { "string", StringCO_Set, StringCO_Get, StringCO_Restore, StringCO_Free, (ClientData) NULL }; /* *---------------------------------------------------------------------- * * PixelsCO_Set -- * PixelsCO_Get -- * PixelsCO_Restore -- * * These procedures implement a TK_OPTION_CUSTOM where the custom * option is exactly the same as a TK_OPTION_PIXELS. This is used * when storage for the option is dynamically allocated. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int PixelsCO_Set( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **valuePtr, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags ) { int objEmpty; int *internalPtr, new; if (internalOffset >= 0) internalPtr = (int *) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*valuePtr)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) { (*valuePtr) = NULL; new = 0; } else { if (Tk_GetPixelsFromObj(interp, tkwin, *valuePtr, &new) != TCL_OK) return TCL_ERROR; } if (internalPtr != NULL) { *((int *) saveInternalPtr) = *internalPtr; *internalPtr = new; } return TCL_OK; } static Tcl_Obj * PixelsCO_Get( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset ) { int *internalPtr = (int *) (recordPtr + internalOffset); return Tcl_NewIntObj(*internalPtr); } static void PixelsCO_Restore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr ) { *(int *) internalPtr = *(int *) saveInternalPtr; } Tk_ObjCustomOption TreeCtrlCO_pixels = { "string", PixelsCO_Set, PixelsCO_Get, PixelsCO_Restore, NULL, (ClientData) NULL }; /* *---------------------------------------------------------------------- * * StyleCO_Set -- * StyleCO_Get -- * StyleCO_Restore -- * * These procedures implement a TK_OPTION_CUSTOM where the custom * option is a TreeStyle. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int StyleCO_Set( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **valuePtr, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags ) { int domain = PTR2INT(clientData), domainS; TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; int objEmpty; TreeStyle *internalPtr, new; if (internalOffset >= 0) internalPtr = (TreeStyle *) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*valuePtr)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) { (*valuePtr) = NULL; new = NULL; } else { if (TreeStyle_FromObj(tree, *valuePtr, &new) != TCL_OK) return TCL_ERROR; domainS = TreeStyle_GetStateDomain(tree, new); if (domainS != domain) { FormatResult(interp, "expected state domain \"%s\" but got \"%s\"", tree->stateDomain[domain].name, tree->stateDomain[domainS].name); return TCL_ERROR; } } if (internalPtr != NULL) { *((TreeStyle *) saveInternalPtr) = *internalPtr; *internalPtr = new; } return TCL_OK; } static Tcl_Obj * StyleCO_Get( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset ) { TreeStyle *internalPtr = (TreeStyle *) (recordPtr + internalOffset); if (*internalPtr == NULL) return NULL; return TreeStyle_ToObj(*internalPtr); } static void StyleCO_Restore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr ) { *(TreeStyle *) internalPtr = *(TreeStyle *) saveInternalPtr; } Tk_ObjCustomOption TreeCtrlCO_style = { "style", StyleCO_Set, StyleCO_Get, StyleCO_Restore, NULL, (ClientData) NULL }; /* *---------------------------------------------------------------------- * * TreeStyleCO_Init -- * * Initializes a Tk_OptionSpec.clientData for a custom option. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeStyleCO_Init( Tk_OptionSpec *optionTable, CONST char *optionName, int domain ) { Tk_OptionSpec *specPtr; Tk_ObjCustomOption *co; specPtr = Tree_FindOptionSpec(optionTable, optionName); if (specPtr->type != TK_OPTION_CUSTOM) panic("TreeStyleCO_Init: %s is not TK_OPTION_CUSTOM", optionName); if (specPtr->clientData != NULL) return; co = (Tk_ObjCustomOption *) ckalloc(sizeof(Tk_ObjCustomOption)); *co = TreeCtrlCO_style; co->clientData = INT2PTR(domain); specPtr->clientData = co; } /* *---------------------------------------------------------------------- * * BooleanFlagCO_Set -- * BooleanFlagCO_Get -- * BooleanFlagCO_Restore -- * * These procedures implement a TK_OPTION_CUSTOM where the custom * option is a boolean value whose internal rep is a single bit of * an int rather than the entire int. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int BooleanFlagCO_Set( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags ) { int theFlag = PTR2INT(clientData); int new, *internalPtr; if (internalOffset >= 0) internalPtr = (int *) (recordPtr + internalOffset); else internalPtr = NULL; if (Tcl_GetBooleanFromObj(interp, (*value), &new) != TCL_OK) return TCL_ERROR; if (internalPtr != NULL) { *((int *) saveInternalPtr) = *internalPtr; if (new) *internalPtr |= theFlag; else *internalPtr &= ~theFlag; } return TCL_OK; } static Tcl_Obj * BooleanFlagCO_Get( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset ) { int theFlag = PTR2INT(clientData); int value = *(int *) (recordPtr + internalOffset); return Tcl_NewBooleanObj(value & theFlag); } static void BooleanFlagCO_Restore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr ) { int theFlag = PTR2INT(clientData); int value = *(int *) saveInternalPtr; if (value & theFlag) *((int *) internalPtr) |= theFlag; else *((int *) internalPtr) &= ~theFlag; } int BooleanFlagCO_Init( Tk_OptionSpec *optionTable, CONST char *optionName, int theFlag ) { Tk_OptionSpec *specPtr; Tk_ObjCustomOption *co; specPtr = Tree_FindOptionSpec(optionTable, optionName); if (specPtr->type != TK_OPTION_CUSTOM) panic("BooleanFlagCO_Init: %s is not TK_OPTION_CUSTOM", optionName); if (specPtr->clientData != NULL) return TCL_OK; /* The Tk custom option record */ co = (Tk_ObjCustomOption *) ckalloc(sizeof(Tk_ObjCustomOption)); co->name = "boolean"; co->setProc = BooleanFlagCO_Set; co->getProc = BooleanFlagCO_Get; co->restoreProc = BooleanFlagCO_Restore; co->freeProc = NULL; co->clientData = (ClientData) INT2PTR(theFlag); specPtr->clientData = co; return TCL_OK; } /* *---------------------------------------------------------------------- * * ItemButtonCO_Set -- * ItemButtonCO_Get -- * ItemButtonCO_Restore -- * * These procedures implement a TK_OPTION_CUSTOM where the custom * option is a boolean value or "auto"; the internal rep is two * bits of an int: one bit for the boolean, and one for "auto". * This is used for the item option -button. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ struct ItemButtonCOClientData { int flag1; /* Bit to set when object is "true". */ int flag2; /* Bit to set when object is "auto". */ }; static int ItemButtonCO_Set( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **value, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags ) { struct ItemButtonCOClientData *cd = clientData; int new, *internalPtr, on, off; char *s; int length; if (internalOffset >= 0) internalPtr = (int *) (recordPtr + internalOffset); else internalPtr = NULL; s = Tcl_GetStringFromObj((*value), &length); if (s[0] == 'a' && strncmp(s, "auto", length) == 0) { on = cd->flag2; off = cd->flag1; } else { if (Tcl_GetBooleanFromObj(interp, (*value), &new) != TCL_OK) { FormatResult(interp, "expected boolean or auto but got \"%s\"", s); return TCL_ERROR; } if (new) { on = cd->flag1; off = cd->flag2; } else { on = 0; off = cd->flag1 | cd->flag2; } } if (internalPtr != NULL) { *((int *) saveInternalPtr) = *internalPtr; *internalPtr |= on; *internalPtr &= ~off; } return TCL_OK; } static Tcl_Obj * ItemButtonCO_Get( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset ) { struct ItemButtonCOClientData *cd = clientData; int value = *(int *) (recordPtr + internalOffset); if (value & cd->flag2) return Tcl_NewStringObj("auto", -1); return Tcl_NewBooleanObj((value & cd->flag1) != 0); } static void ItemButtonCO_Restore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr ) { struct ItemButtonCOClientData *cd = clientData; int value = *(int *) saveInternalPtr; *((int *) internalPtr) &= ~(cd->flag1 | cd->flag2); *((int *) internalPtr) |= value & (cd->flag1 | cd->flag2); } int ItemButtonCO_Init( Tk_OptionSpec *optionTable, CONST char *optionName, int flag1, int flag2 ) { Tk_OptionSpec *specPtr; Tk_ObjCustomOption *co; struct ItemButtonCOClientData *cd; specPtr = Tree_FindOptionSpec(optionTable, optionName); if (specPtr->type != TK_OPTION_CUSTOM) panic("BooleanFlagCO_Init: %s is not TK_OPTION_CUSTOM", optionName); if (specPtr->clientData != NULL) return TCL_OK; /* ClientData for the Tk custom option record. */ cd = (struct ItemButtonCOClientData *)ckalloc( sizeof(struct ItemButtonCOClientData)); cd->flag1 = flag1; cd->flag2 = flag2; /* The Tk custom option record */ co = (Tk_ObjCustomOption *) ckalloc(sizeof(Tk_ObjCustomOption)); co->name = "button option"; co->setProc = ItemButtonCO_Set; co->getProc = ItemButtonCO_Get; co->restoreProc = ItemButtonCO_Restore; co->freeProc = NULL; co->clientData = cd; specPtr->clientData = co; return TCL_OK; } /* *---------------------------------------------------------------------- * * Tree_GetIntForIndex -- * * This is basically a direct copy of TclGetIntForIndex with one * important difference: the caller gets to know whether the index * was of the form "end?-offset?". * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tree_GetIntForIndex( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *objPtr, /* Points to an object containing either "end" * or an integer. */ int *indexPtr, /* Location filled in with an integer * representing an index. */ int *endRelativePtr /* Set to 1 if the returned index is relative * to "end". */ ) { int endValue = 0; char *bytes; if (TclGetIntForIndex(tree->interp, objPtr, endValue, indexPtr) != TCL_OK) return TCL_ERROR; bytes = Tcl_GetString(objPtr); if (*bytes == 'e') { *endRelativePtr = 1; } else { *endRelativePtr = 0; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tree_DrawRoundRectX11 -- * * Draw a rounded rectangle with a solid color. * * Results: * None. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ void Tree_DrawRoundRectX11( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ GC gc, /* Graphics context. */ TreeRectangle tr, /* Where to draw. */ int outlineWidth, int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { int x = tr.x, y = tr.y, width = tr.width, height = tr.height; TreeRectangle rects[4], *pr = rects; int nrects = 0; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; int i; /* Calculate the bounds of each edge that should be drawn */ if (drawW) { pr->x = x, pr->y = y, pr->width = outlineWidth, pr->height = height; if (drawN) pr->y += ry, pr->height -= ry; if (drawS) pr->height -= ry; if (pr->width > 0 && pr->height > 0) pr++, nrects++; } if (drawN) { pr->x = x, pr->y = y, pr->width = width, pr->height = outlineWidth; if (drawW) pr->x += rx, pr->width -= rx; if (drawE) pr->width -= rx; if (pr->width > 0 && pr->height > 0) pr++, nrects++; } if (drawE) { pr->x = x + width - outlineWidth, pr->y = y, pr->width = outlineWidth, pr->height = height; if (drawN) pr->y += ry, pr->height -= ry; if (drawS) pr->height -= ry; if (pr->width > 0 && pr->height > 0) pr++, nrects++; } if (drawS) { pr->x = x, pr->y = y + height - outlineWidth, pr->width = width, pr->height = outlineWidth; if (drawW) pr->x += rx, pr->width -= rx; if (drawE) pr->width -= rx; if (pr->width > 0 && pr->height > 0) pr++, nrects++; } for (i = 0; i < nrects; i++) Tree_FillRectangle(tree, td, clip, gc, rects[i]); /* On Win32 the code below works, leaving a 1-pixel hole at each * corner. But on X11 there is no hole. */ if (rx == 1 && ry == 1) return; width -= 1, height -= 1; if (drawW && drawN) Tree_DrawArc(tree, td, clip, gc, x, y, rx*2, ry*2, 64*90, 64*90); /* top-left */ if (drawW && drawS) Tree_DrawArc(tree, td, clip, gc, x, y + height - ry*2, rx*2, ry*2, 64*180, 64*90); /* bottom-left */ if (drawE && drawN) Tree_DrawArc(tree, td, clip, gc, x + width - rx*2, y, rx*2, ry*2, 64*0, 64*90); /* top-right */ if (drawE && drawS) Tree_DrawArc(tree, td, clip, gc, x + width - rx*2, y + height - ry*2, rx*2, ry*2, 64*270, 64*90); /* bottom-right */ for (i = 1; i < outlineWidth; i++) { x += 1, width -= 2; if (drawW && drawN) Tree_DrawArc(tree, td, clip, gc, x, y, rx*2, ry*2, 64*90, 64*90); /* top-left */ if (drawW && drawS) Tree_DrawArc(tree, td, clip, gc, x, y + height - ry*2, rx*2, ry*2, 64*180, 64*90); /* bottom-left */ if (drawE && drawN) Tree_DrawArc(tree, td, clip, gc, x + width - rx*2, y, rx*2, ry*2, 64*0, 64*90); /* top-right */ if (drawE && drawS) Tree_DrawArc(tree, td, clip, gc, x + width - rx*2, y + height - ry*2, rx*2, ry*2, 64*270, 64*90); /* bottom-right */ y += 1, height -= 2; if (drawW && drawN) Tree_DrawArc(tree, td, clip, gc, x, y, rx*2, ry*2, 64*90, 64*90); /* top-left */ if (drawW && drawS) Tree_DrawArc(tree, td, clip, gc, x, y + height - ry*2, rx*2, ry*2, 64*180, 64*90); /* bottom-left */ if (drawE && drawN) Tree_DrawArc(tree, td, clip, gc, x + width - rx*2, y, rx*2, ry*2, 64*0, 64*90); /* top-right */ if (drawE && drawS) Tree_DrawArc(tree, td, clip, gc, x + width - rx*2, y + height - ry*2, rx*2, ry*2, 64*270, 64*90); /* bottom-right */ } } /* *---------------------------------------------------------------------- * * Tree_FillRoundRectX11 -- * * Fill a rounded rectangle with a solid color. * * Results: * None. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ void Tree_FillRoundRectX11( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ GC gc, /* Graphics context. */ TreeRectangle tr, /* Rectangle to paint. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { TreeRectangle rects[3], *rectp = rects; int nrects = 0; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; int i; tr.height -= 1, tr.width -= 1; if (drawW && drawN) Tree_FillArc(tree, td, clip, gc, tr.x, tr.y, rx*2, ry*2, 64*90, 64*90); /* top-left */ if (drawW && drawS) Tree_FillArc(tree, td, clip, gc, tr.x, tr.y + tr.height - ry*2, rx*2, ry*2, 64*180, 64*90); /* bottom-left */ if (drawE && drawN) Tree_FillArc(tree, td, clip, gc, tr.x + tr.width - rx*2, tr.y, rx*2, ry*2, 64*0, 64*90); /* top-right */ if (drawE && drawS) Tree_FillArc(tree, td, clip, gc, tr.x + tr.width - rx*2, tr.y + tr.height - ry*2, rx*2, ry*2, 64*270, 64*90); /* bottom-right */ tr.height += 1, tr.width += 1; /* Everything but left/right edges */ rectp->x = tr.x + rx; rectp->y = tr.y; rectp->width = tr.width - rx * 2; rectp->height = tr.height; if (rectp->width > 0 && rectp->height > 0) { nrects++; rectp++; } /* Left edge */ rectp->x = tr.x; rectp->y = tr.y; rectp->width = rx; rectp->height = tr.height; if (drawW && drawN) rectp->y += ry, rectp->height -= ry; if (drawW && drawS) rectp->height -= ry; if (rectp->width > 0 && rectp->height > 0) { nrects++; rectp++; } /* Right edge */ rectp->x = tr.x + tr.width - rx; rectp->y = tr.y; rectp->width = rx; rectp->height = tr.height; if (drawE && drawN) rectp->y += ry, rectp->height -= ry; if (drawE && drawS) rectp->height -= ry; if (rectp->width > 0 && rectp->height > 0) { nrects++; rectp++; } for (i = 0; i < nrects; i++) Tree_FillRectangle(tree, td, clip, gc, rects[i]); } /*****/ typedef struct PerStateDataGradient PerStateDataGradient; struct PerStateDataGradient { PerStateData header; TreeGradient gradient; }; static int PSDGradientFromObj( TreeCtrl *tree, Tcl_Obj *obj, PerStateDataGradient *pGradient) { if (ObjectIsEmpty(obj)) { /* Specify empty string to override masterX */ pGradient->gradient = NULL; } else { if (TreeGradient_FromObj(tree, obj, &pGradient->gradient) != TCL_OK) return TCL_ERROR; pGradient->gradient->refCount++; } return TCL_OK; } static void PSDGradientFree( TreeCtrl *tree, PerStateDataGradient *pGradient) { if (pGradient->gradient != NULL) TreeGradient_Release(tree, pGradient->gradient); } PerStateType pstGradient = { "pstGradient", sizeof(PerStateDataGradient), (PerStateType_FromObjProc) PSDGradientFromObj, (PerStateType_FreeProc) PSDGradientFree }; TreeGradient PerStateGradient_ForState( TreeCtrl *tree, PerStateInfo *pInfo, int state, int *match) { PerStateDataGradient *pData; pData = (PerStateDataGradient *) PerStateInfo_ForState(tree, &pstGradient, pInfo, state, match); if (pData != NULL) return pData->gradient; return NULL; } /*****/ /* *---------------------------------------------------------------------- * * Tree_AllocColorFromObj -- * * Allocate a TreeColor structure based on the given object. * * Results: * A new TreeColor struct or NULL if an error occurred. * * Side effects: * Memory may be allocated. If the color refers to a gradient * its refCount is incremented. * *---------------------------------------------------------------------- */ TreeColor * Tree_AllocColorFromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *obj /* Gradient name or Tk color specification */ ) { TreeGradient gradient = NULL; XColor *color = NULL; TreeColor *tc; if (TreeGradient_FromObj(tree, obj, &gradient) == TCL_OK) { gradient->refCount++; } else { Tcl_ResetResult(tree->interp); color = Tk_AllocColorFromObj(tree->interp, tree->tkwin, obj); if (color == NULL) { FormatResult(tree->interp, "unknown color or gradient name \"%s\"", Tcl_GetString(obj)); return NULL; } } tc = (TreeColor *) ckalloc(sizeof(TreeColor)); tc->color = color; tc->gradient = gradient; return tc; } /* *---------------------------------------------------------------------- * * Tree_FreeColor -- * * Free a TreeColor. * * Results: * None. * * Side effects: * Memory may be freed. If the color refers to a gradient * its refCount is decremented. * *---------------------------------------------------------------------- */ void Tree_FreeColor( TreeCtrl *tree, /* Widget info. */ TreeColor *tc /* Color to free, may be NULL */ ) { if (tc != NULL) { if (tc->color) Tk_FreeColor(tc->color); if (tc->gradient) TreeGradient_Release(tree, tc->gradient); WFREE(tc, TreeColor); } } /* *---------------------------------------------------------------------- * * TreeColor_ToObj -- * * Returns the Tcl_Obj representation of a TreeColor. * * Results: * The returned representation is bogus, ensure any TreeColor * options store the object representation. * * Side effects: * Creates a new Tcl_Obj. * *---------------------------------------------------------------------- */ Tcl_Obj * TreeColor_ToObj( TreeCtrl *tree, /* Widget info. */ TreeColor *tc /* Color to get Tcl_Obj rep of */ ) { /* FIXME */ return Tcl_NewStringObj("insert tree color rep here", -1); } /* *---------------------------------------------------------------------- * * TreeColor_IsOpaque -- * * Test whether a tree color would be drawn fully opaque or not. * * Results: * 1 if opaque, 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeColor_IsOpaque( TreeCtrl *tree, /* Widget info. */ TreeColor *tc /* Color info. */ ) { if (tc == NULL) return 0; if (tc->gradient != NULL) return TreeGradient_IsOpaque(tree, tc->gradient); return tc->color != NULL; } /* *---------------------------------------------------------------------- * * TreeColorCO_Set -- * TreeColorCO_Get -- * TreeColorCO_Restore -- * * These procedures implement a TK_OPTION_CUSTOM where the custom * option is a TreeColor. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static int TreeColorCO_Set( ClientData clientData, Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj **valuePtr, char *recordPtr, int internalOffset, char *saveInternalPtr, int flags ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; int objEmpty; TreeColor **internalPtr, *new; if (internalOffset >= 0) internalPtr = (TreeColor **) (recordPtr + internalOffset); else internalPtr = NULL; objEmpty = ObjectIsEmpty((*valuePtr)); if ((flags & TK_OPTION_NULL_OK) && objEmpty) { (*valuePtr) = NULL; new = 0; } else { new = Tree_AllocColorFromObj(tree, *valuePtr); if (new == NULL) return TCL_ERROR; } if (internalPtr != NULL) { *((TreeColor **) saveInternalPtr) = *internalPtr; *internalPtr = new; } return TCL_OK; } static Tcl_Obj * TreeColorCO_Get( ClientData clientData, Tk_Window tkwin, char *recordPtr, int internalOffset ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; TreeColor **internalPtr = (TreeColor **) (recordPtr + internalOffset); return TreeColor_ToObj(tree, *internalPtr); } static void TreeColorCO_Restore( ClientData clientData, Tk_Window tkwin, char *internalPtr, char *saveInternalPtr ) { *(TreeColor **) internalPtr = *(TreeColor **) saveInternalPtr; } static void TreeColorCO_Free( ClientData clientData, Tk_Window tkwin, char *internalPtr ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; TreeColor *value = *((TreeColor **) internalPtr); if (value != NULL) { Tree_FreeColor(tree, value); *((TreeColor **) internalPtr) = NULL; } } Tk_ObjCustomOption TreeCtrlCO_treecolor = { "tree color", TreeColorCO_Set, TreeColorCO_Get, TreeColorCO_Restore, TreeColorCO_Free, (ClientData) NULL }; /*****/ /* *** Borrowed some gradient code from TkPath *** */ static GradientStop * NewGradientStop( double offset, XColor *color, double opacity ) { GradientStop *stopPtr; stopPtr = (GradientStop *) ckalloc(sizeof(GradientStop)); memset(stopPtr, '\0', sizeof(GradientStop)); stopPtr->offset = offset; stopPtr->color = color; stopPtr->opacity = opacity; return stopPtr; } static GradientStopArray * NewGradientStopArray( int nstops ) { GradientStopArray *stopArrPtr; GradientStop **stops; stopArrPtr = (GradientStopArray *) ckalloc(sizeof(GradientStopArray)); memset(stopArrPtr, '\0', sizeof(GradientStopArray)); /* Array of *pointers* to GradientStop. */ stops = (GradientStop **) ckalloc(nstops*sizeof(GradientStop *)); memset(stops, '\0', nstops*sizeof(GradientStop *)); stopArrPtr->nstops = nstops; stopArrPtr->stops = stops; return stopArrPtr; } static void FreeAllStops( GradientStop **stops, int nstops ) { int i; for (i = 0; i < nstops; i++) { if (stops[i] != NULL) { Tk_FreeColor(stops[i]->color); WFREE(stops[i], GradientStop); } } WCFREE(stops, GradientStop*, nstops); } static void FreeStopArray( GradientStopArray *stopArrPtr ) { if (stopArrPtr != NULL) { FreeAllStops(stopArrPtr->stops, stopArrPtr->nstops); WFREE(stopArrPtr, GradientStopArray); } } /* * The stops are a list of stop lists where each stop list is: * {offset color ?opacity?} */ static int StopsSet( ClientData clientData, Tcl_Interp *interp, /* Current interp; may be used for errors. */ Tk_Window tkwin, /* Window for which option is being set. */ Tcl_Obj **value, /* Pointer to the pointer to the value object. * We use a pointer to the pointer because * we may need to return a value (NULL). */ char *recordPtr, /* Pointer to storage for the widget record. */ int internalOffset, /* Offset within *recordPtr at which the internal value is to be stored. */ char *oldInternalPtr, /* Pointer to storage for the old value. */ int flags /* Flags for the option, set Tk_SetOptions. */ ) { char *internalPtr; int i, nstops, stopLen; int objEmpty = 0; Tcl_Obj *valuePtr; double offset, lastOffset, opacity; Tcl_Obj **objv; Tcl_Obj *stopObj; Tcl_Obj *obj; XColor *color; GradientStopArray *new = NULL; valuePtr = *value; if (internalOffset >= 0) internalPtr = recordPtr + internalOffset; else internalPtr = NULL; objEmpty = ObjectIsEmpty(valuePtr); if ((flags & TK_OPTION_NULL_OK) && objEmpty) { valuePtr = NULL; } else { /* Deal with each stop list in turn. */ if (Tcl_ListObjGetElements(interp, valuePtr, &nstops, &objv) != TCL_OK) { return TCL_ERROR; } if (nstops < 2) { FormatResult(interp, "at least 2 stops required, %d given", nstops); return TCL_ERROR; } new = NewGradientStopArray(nstops); lastOffset = 0.0; for (i = 0; i < nstops; i++) { stopObj = objv[i]; if (Tcl_ListObjLength(interp, stopObj, &stopLen) != TCL_OK) { goto error; } if ((stopLen < 2) || (stopLen > 3)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "stop list not {offset color ?opacity?}", -1)); goto error; } Tcl_ListObjIndex(interp, stopObj, 0, &obj); if (Tcl_GetDoubleFromObj(interp, obj, &offset) != TCL_OK) { goto error; } if ((offset < 0.0) || (offset > 1.0)) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "stop offsets must be in the range 0.0 to 1.0", -1)); goto error; } if ((i == 0) && (offset != 0.0)) { FormatResult(interp, "first stop offset must be 0.0, got %.4g", offset); goto error; } if ((i == nstops - 1) && (offset != 1.0)) { FormatResult(interp, "last stop offset must be 1.0, got %.4g", offset); goto error; } if (offset < lastOffset) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "stop offsets must be ordered", -1)); goto error; } Tcl_ListObjIndex(interp, stopObj, 1, &obj); color = Tk_AllocColorFromObj(interp, Tk_MainWindow(interp), obj); if (color == NULL) goto error; if (stopLen == 3) { Tcl_ListObjIndex(interp, stopObj, 2, &obj); if (Tcl_GetDoubleFromObj(interp, obj, &opacity) != TCL_OK) { goto error; } } else { opacity = 1.0; } /* Make new stop. */ new->stops[i] = NewGradientStop(offset, color, opacity); lastOffset = offset; } } if (internalPtr != NULL) { *((GradientStopArray **) oldInternalPtr) = *((GradientStopArray **) internalPtr); *((GradientStopArray **) internalPtr) = new; } return TCL_OK; error: if (new != NULL) { FreeStopArray(new); } return TCL_ERROR; } static void StopsRestore( ClientData clientData, Tk_Window tkwin, char *internalPtr, /* Pointer to storage for value. */ char *oldInternalPtr /* Pointer to old value. */ ) { *(GradientStopArray **)internalPtr = *(GradientStopArray **)oldInternalPtr; } static void StopsFree( ClientData clientData, Tk_Window tkwin, char *internalPtr ) { if (*((char **) internalPtr) != NULL) { FreeStopArray(*(GradientStopArray **)internalPtr); } } static Tk_ObjCustomOption stopsCO = { "stops", StopsSet, NULL, StopsRestore, StopsFree, (ClientData) NULL }; /*****/ typedef enum { GCT_AREA = 0, GCT_CANVAS, GCT_COLUMN, GCT_ITEM } GradientCoordType; static const char *coordTypeNames[] = { "area", "canvas", "column", "item", NULL }; struct GradientCoord { GradientCoordType type; float value; TreeColumn column; /* optional arg to GCT_COLUMN */ TreeItem item; /* optional arg to GCT_ITEM */ int area; /* required arg to GCT_AREA */ }; static int GradientCoordSet( ClientData clientData, Tcl_Interp *interp, /* Current interp; may be used for errors. */ Tk_Window tkwin, /* Window for which option is being set. */ Tcl_Obj **value, /* Pointer to the pointer to the value object. * We use a pointer to the pointer because * we may need to return a value (NULL). */ char *recordPtr, /* Pointer to storage for the widget record. */ int internalOffset, /* Offset within *recordPtr at which the internal value is to be stored. */ char *oldInternalPtr, /* Pointer to storage for the old value. */ int flags /* Flags for the option, set Tk_SetOptions. */ ) { TreeCtrl *tree = (TreeCtrl *) ((TkWindow *) tkwin)->instanceData; char *internalPtr; int objEmpty = 0; Tcl_Obj *valuePtr; Tcl_Obj **objv; int objc; double coordValue; GradientCoordType coordType; GradientCoord *new = NULL; TreeColumn column = NULL; TreeItem item = NULL; int area = TREE_AREA_NONE; valuePtr = *value; if (internalOffset >= 0) internalPtr = recordPtr + internalOffset; else internalPtr = NULL; objEmpty = ObjectIsEmpty(valuePtr); if ((flags & TK_OPTION_NULL_OK) && objEmpty) { valuePtr = NULL; } else { if (Tcl_ListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK) { return TCL_ERROR; } if (objc < 2) { FormatResult(interp, "expected list {offset coordType ?arg ...?}"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], coordTypeNames, "coordinate type", 0, (int *) &coordType) != TCL_OK) { return TCL_ERROR; } if (Tcl_GetDoubleFromObj(interp, objv[0], &coordValue) != TCL_OK) { return TCL_ERROR; } if (coordType == GCT_AREA) { if (objc != 3) { FormatResult(interp, "wrong # args after \"area\": must be 1"); return TCL_ERROR; } if (TreeArea_FromObj(tree, objv[2], &area) != TCL_OK) { return TCL_ERROR; } } if (coordType == GCT_COLUMN && objc > 2) { if (objc > 3) { FormatResult(interp, "wrong # args after \"column\": must be 0 or 1"); return TCL_ERROR; } if (TreeColumn_FromObj(tree, objv[2], &column, CFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } } if (coordType == GCT_ITEM && objc > 2) { if (objc > 3) { FormatResult(interp, "wrong # args after \"item\": must be 0 or 1"); return TCL_ERROR; } if (TreeItem_FromObj(tree, objv[2], &item, IFO_NOT_NULL) != TCL_OK) { return TCL_ERROR; } } new = (GradientCoord *) ckalloc(sizeof(GradientCoord)); new->type = coordType; new->value = (float) coordValue; new->column = column; new->item = item; new->area = area; } if (internalPtr != NULL) { *((GradientCoord **) oldInternalPtr) = *((GradientCoord **) internalPtr); *((GradientCoord **) internalPtr) = new; } return TCL_OK; } static void GradientCoordRestore( ClientData clientData, Tk_Window tkwin, char *internalPtr, /* Pointer to storage for value. */ char *oldInternalPtr) /* Pointer to old value. */ { *(GradientCoord **)internalPtr = *(GradientCoord **)oldInternalPtr; } static void GradientCoordFree( ClientData clientData, Tk_Window tkwin, char *internalPtr) { if (*((char **) internalPtr) != NULL) { ckfree(*(char **)internalPtr); } } static Tk_ObjCustomOption gradientCoordCO = { "coordinate", GradientCoordSet, NULL, GradientCoordRestore, GradientCoordFree, (ClientData) NULL }; /* *-------------------------------------------------------------- * * TreeGradient_ColumnDeleted -- * * Removes any reference to a column from the coordinates of * all gradients. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void TreeGradient_ColumnDeleted( TreeCtrl *tree, /* Widget info. */ TreeColumn column /* Column about to be deleted. */ ) { Tcl_HashEntry *hPtr; Tcl_HashSearch search; TreeGradient gradient; hPtr = Tcl_FirstHashEntry(&tree->gradientHash, &search); while (hPtr != NULL) { gradient = (TreeGradient) Tcl_GetHashValue(hPtr); #define CHECK_GCOORD(GCRD,OBJ) \ if ((GCRD != NULL) && (GCRD->column == column)) { \ ckfree((char *) GCRD); \ Tcl_DecrRefCount(OBJ); \ GCRD = NULL; \ OBJ = NULL; \ } CHECK_GCOORD(gradient->left, gradient->leftObj); CHECK_GCOORD(gradient->right, gradient->rightObj); CHECK_GCOORD(gradient->top, gradient->topObj); CHECK_GCOORD(gradient->bottom, gradient->bottomObj); #undef CHECK_GCOORD hPtr = Tcl_NextHashEntry(&search); } } /* *-------------------------------------------------------------- * * TreeGradient_ItemDeleted -- * * Removes any reference to an item from the coordinates of * all gradients. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void TreeGradient_ItemDeleted( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item about to be deleted. */ ) { Tcl_HashEntry *hPtr; Tcl_HashSearch search; TreeGradient gradient; hPtr = Tcl_FirstHashEntry(&tree->gradientHash, &search); while (hPtr != NULL) { gradient = (TreeGradient) Tcl_GetHashValue(hPtr); #define CHECK_GCOORD(GCRD,OBJ) \ if ((GCRD != NULL) && (GCRD->item == item)) { \ ckfree((char *) GCRD); \ Tcl_DecrRefCount(OBJ); \ GCRD = NULL; \ OBJ = NULL; \ } CHECK_GCOORD(gradient->left, gradient->leftObj); CHECK_GCOORD(gradient->right, gradient->rightObj); CHECK_GCOORD(gradient->top, gradient->topObj); CHECK_GCOORD(gradient->bottom, gradient->bottomObj); #undef CHECK_GCOORD hPtr = Tcl_NextHashEntry(&search); } } static TreeColumn FindNthVisibleColumn( TreeCtrl *tree, TreeColumn column, int *n ) { int index = TreeColumn_Index(column); TreeColumn column2 = column, column3 = column; if ((*n) > 0) { while ((*n) > 0 && ++index < tree->columnCount) { column3 = TreeColumn_Next(column3); if (TreeColumn_Visible(column3)) { column2 = column3; (*n) -= 1; } } } else { while ((*n) < 0 && --index >= 0) { column3 = TreeColumn_Prev(column3); if (TreeColumn_Visible(column3)) { column2 = column3; (*n) += 1; } } } return column2; } static int GetGradientBrushCoordX( TreeCtrl *tree, /* Widget Info. */ GradientCoord *gcrd, /* Left or right coordinate. */ TreeColumn column, /* Column or NULL. */ TreeItem item, /* Item or NULL. */ int *xPtr /* Returned canvas coordinate. * Will remain unchanged if the * gradient coordinate cannot be * resolved. */ ) { if (gcrd == NULL) return 0; switch (gcrd->type) { case GCT_AREA: { TreeRectangle tr; if (Tree_AreaBbox(tree, gcrd->area, &tr) == TRUE) { (*xPtr) = (int) (TreeRect_Left(tr) + TreeRect_Width(tr) * gcrd->value); (*xPtr) += tree->xOrigin; /* Window -> Canvas */ return 1; } break; } case GCT_CANVAS: { int canvasWidth = Tree_FakeCanvasWidth(tree); (*xPtr) = (int) (canvasWidth * gcrd->value); return 1; } /* FIXME: if item != NULL then make column offset relative to item */ case GCT_COLUMN: if (gcrd->column != NULL) column = gcrd->column; if (column != NULL) { int x, w; if (gcrd->value < 0.0) { int n = (int) ceil(-gcrd->value); n = -n; /* backwards */ column = FindNthVisibleColumn(tree, column, &n); if (TreeColumn_Visible(column)) { double tmp, frac; if ((n < 0) || (frac = modf(-gcrd->value, &tmp)) == 0.0) frac = 1.0; x = TreeColumn_Offset(column); w = TreeColumn_UseWidth(column); (*xPtr) = (int) (x + w * (1.0 - frac)); return 1; } } else if (gcrd->value > 1.0) { int n = (int) ceil(gcrd->value - 1.0); column = FindNthVisibleColumn(tree, column, &n); if (TreeColumn_Visible(column)) { double tmp, frac; if ((n > 0) || (frac = modf(gcrd->value, &tmp)) == 0.0) frac = 1.0; x = TreeColumn_Offset(column); w = TreeColumn_UseWidth(column); (*xPtr) = (int) (x + w * frac); return 1; } } else { if (TreeColumn_Visible(column)) { x = TreeColumn_Offset(column); w = TreeColumn_UseWidth(column); (*xPtr) = (int) (x + w * gcrd->value); return 1; } } } break; case GCT_ITEM: if (gcrd->item != NULL) item = gcrd->item; if (item != NULL) { TreeRectangle tr; int lock; if (tree->columnCountVis > 0) lock = COLUMN_LOCK_NONE; else if (tree->columnCountVisLeft > 0) lock = COLUMN_LOCK_LEFT; else if (tree->columnCountVisRight > 0) lock = COLUMN_LOCK_RIGHT; else break; /* not possible else wouldn't be drawing */ if (gcrd->value < 0.0) { int clip = 0, row, col, row2, col2; if (Tree_ItemToRNC(tree, item, &row, &col) == TCL_OK) { int n = (int) ceil(-gcrd->value); TreeItem item2 = Tree_RNCToItem(tree, row, col - n); (void) Tree_ItemToRNC(tree, item2, &row2, &col2); if (row2 == row) item = item2; /* there is an item to the left */ if (row2 != row || col2 != col - n) clip = 1; /* no item 'n' columns to the left */ } if (Tree_ItemBbox(tree, item, lock, &tr) != -1) { double tmp, frac; if (clip || (frac = modf(-gcrd->value, &tmp)) == 0.0) frac = 1.0; (*xPtr) = (int) (tr.x + tr.width * (1.0 - frac)); return 1; } } else if (gcrd->value > 1.0) { int clip = 0, row, col, row2, col2; if (Tree_ItemToRNC(tree, item, &row, &col) == TCL_OK) { int n = (int) ceil(gcrd->value - 1.0); TreeItem item2 = Tree_RNCToItem(tree, row, col + n); (void) Tree_ItemToRNC(tree, item2, &row2, &col2); if (row2 == row) item = item2; /* there is an item to the right */ if (row2 != row || col2 != col + n) clip = 1; /* no item 'n' columns to the right */ } if (Tree_ItemBbox(tree, item, lock, &tr) != -1) { double tmp, frac; if (clip || (frac = modf(gcrd->value, &tmp)) == 0.0) frac = 1.0; (*xPtr) = (int) (tr.x + tr.width * frac); return 1; } } else if (Tree_ItemBbox(tree, item, lock, &tr) != -1) { (*xPtr) = (int) (tr.x + tr.width * gcrd->value); return 1; } } break; } return 0; } static int GetGradientBrushCoordY( TreeCtrl *tree, /* Widget Info. */ GradientCoord *gcrd, /* Top or bottom coordinate. */ TreeColumn column, /* Column or NULL. */ TreeItem item, /* Item or NULL. */ int *yPtr /* Returned canvas coordinate. * Will remain unchanged if the * gradient coordinate cannot be * resolved. */ ) { if (gcrd == NULL) return 0; switch (gcrd->type) { case GCT_AREA: { TreeRectangle tr; if (Tree_AreaBbox(tree, gcrd->area, &tr) == TRUE) { (*yPtr) = (int) (TreeRect_Top(tr) + TreeRect_Height(tr) * gcrd->value); (*yPtr) += tree->yOrigin; /* Window -> Canvas */ return 1; } break; } case GCT_CANVAS: { int canvasHeight = Tree_FakeCanvasHeight(tree); (*yPtr) = (int) (canvasHeight * gcrd->value); return 1; } case GCT_COLUMN: /* Can't think of any use for this */ break; case GCT_ITEM: if (gcrd->item != NULL) item = gcrd->item; if (item != NULL) { TreeRectangle tr; int lock; if (tree->columnCountVis > 0) lock = COLUMN_LOCK_NONE; else if (tree->columnCountVisLeft > 0) lock = COLUMN_LOCK_LEFT; else if (tree->columnCountVisRight > 0) lock = COLUMN_LOCK_RIGHT; else break; /* not possible else wouldn't be drawing */ if (gcrd->value < 0.0) { int clip = 0, row, col, row2, col2; if (Tree_ItemToRNC(tree, item, &row, &col) == TCL_OK) { int n = (int) ceil(-gcrd->value); TreeItem item2 = Tree_RNCToItem(tree, row - n, col); (void) Tree_ItemToRNC(tree, item2, &row2, &col2); if (col2 == col) item = item2; /* there is an item above */ if (row2 != row - n || col2 != col) clip = 1; /* no item 'n' rows above */ } if (Tree_ItemBbox(tree, item, lock, &tr) != -1) { double tmp, frac; if (clip || (frac = modf(-gcrd->value, &tmp)) == 0.0) frac = 1.0; (*yPtr) = (int) (tr.y + tr.height * (1.0 - frac)); return 1; } } else if (gcrd->value > 1.0) { int clip = 0, row, col, row2, col2; if (Tree_ItemToRNC(tree, item, &row, &col) == TCL_OK) { int n = (int) ceil(gcrd->value - 1.0); TreeItem item2 = Tree_RNCToItem(tree, row + n, col); (void) Tree_ItemToRNC(tree, item2, &row2, &col2); if (col2 == col) item = item2; /* there is an item below */ if (row2 != row + n || col2 != col) clip = 1; /* no item 'n' rows below */ } if (Tree_ItemBbox(tree, item, lock, &tr) != -1) { double tmp, frac; if (clip || (frac = modf(gcrd->value, &tmp)) == 0.0) frac = 1.0; (*yPtr) = (int) (tr.y + tr.height * frac); return 1; } } else if (Tree_ItemBbox(tree, item, lock, &tr) != -1) { (*yPtr) = (int) (tr.y + tr.height * gcrd->value); return 1; } } break; } return 0; } /* *-------------------------------------------------------------- * * TreeGradient_GetBrushBounds -- * * Returns the bounds of the brush that should be used to * draw a gradient. * * Results: * Return 1 if the brush size is non-empty, 0 otherwise. * * Side effects: * May recalculate item/column layout info if it is out-of-date. * *-------------------------------------------------------------- */ int TreeGradient_GetBrushBounds( TreeCtrl *tree, /* Widget Info. */ TreeGradient gradient, /* Gradient token. */ const TreeRectangle *trPaint, /* Area to paint, canvas coords. */ TreeRectangle *trBrush, /* Returned brush bounds. */ TreeColumn column, /* Column or NULL. */ TreeItem item /* Item or NULL. */ ) { int x1, y1, x2, y2; x1 = trPaint->x; y1 = trPaint->y; x2 = trPaint->x + trPaint->width; y2 = trPaint->y + trPaint->height; /* FIXME: If an item's or column's visibility changes, may need to redraw */ (void) GetGradientBrushCoordX(tree, gradient->left, column, item, &x1); (void) GetGradientBrushCoordX(tree, gradient->right, column, item, &x2); (void) GetGradientBrushCoordY(tree, gradient->top, column, item, &y1); (void) GetGradientBrushCoordY(tree, gradient->bottom, column, item, &y2); trBrush->x = x1; trBrush->y = y1; trBrush->width = x2 - x1; trBrush->height = y2 - y1; return trBrush->width > 0 && trBrush->height > 0; } /* *-------------------------------------------------------------- * * TreeGradient_IsRelativeToCanvas -- * * Returns true if the gradient brush is relative to the * canvas along the horizontal and vertical axes. * * Results: * None. * * Side effects: * None. * *-------------------------------------------------------------- */ void TreeGradient_IsRelativeToCanvas( TreeGradient gradient, int *relX, int *relY ) { (*relX) = (*relY) = 1; if (gradient->vertical == 0 && ((gradient->left != NULL && gradient->left->type == GCT_AREA) || (gradient->right != NULL && gradient->right->type == GCT_AREA))) (*relX) = 0; if (gradient->vertical==1 && ((gradient->top != NULL && gradient->top->type == GCT_AREA) || (gradient->bottom != NULL && gradient->bottom->type == GCT_AREA))) (*relY) = 0; } /* *-------------------------------------------------------------- * * TreeColor_GetBrushBounds -- * * Determines the bounds of the gradient brush. * * Results: * None. * * Side effects: * May mark an item as needing to be redrawn when scrolling * occurs if the gradient brush isn't relative to the canvas. * *-------------------------------------------------------------- */ void TreeColor_GetBrushBounds( TreeCtrl *tree, /* Widget info. */ TreeColor *tc, /* Color or gradient. */ TreeRectangle trPaint, /* Area to be painted. */ int xOrigin, /* Offset of trPaint from canvas. */ int yOrigin, TreeColumn column, /* Column trPaint is in, or NULL. */ TreeItem item, /* Item trPaint is in, or NULL. */ TreeRectangle *trBrush /* Returned brush bounds. */ ) { int relX, relY; if (tc->gradient != NULL) { trPaint.x += xOrigin; trPaint.y += yOrigin; (void) TreeGradient_GetBrushBounds(tree, tc->gradient, &trPaint, trBrush, column, item); trBrush->x -= xOrigin; trBrush->y -= yOrigin; if (item != NULL) { TreeGradient_IsRelativeToCanvas(tc->gradient, &relX, &relY); if (relX == 0) Tree_InvalidateItemOnScrollX(tree, item); if (relY == 0) Tree_InvalidateItemOnScrollY(tree, item); } } else { *trBrush = trPaint; } } /*****/ #define GRAD_CONF_STOPS 0x0001 #define GRAD_CONF_STEPS 0x0002 static char *orientStringTable[] = { "horizontal", "vertical", (char *) NULL }; static Tk_OptionSpec gradientOptionSpecs[] = { {TK_OPTION_CUSTOM, "-bottom", NULL, NULL, NULL, Tk_Offset(TreeGradient_, bottomObj), Tk_Offset(TreeGradient_, bottom), TK_OPTION_NULL_OK, (ClientData) &gradientCoordCO, 0}, {TK_OPTION_CUSTOM, "-left", NULL, NULL, NULL, Tk_Offset(TreeGradient_, leftObj), Tk_Offset(TreeGradient_, left), TK_OPTION_NULL_OK, (ClientData) &gradientCoordCO, 0}, {TK_OPTION_CUSTOM, "-right", NULL, NULL, NULL, Tk_Offset(TreeGradient_, rightObj), Tk_Offset(TreeGradient_, right), TK_OPTION_NULL_OK, (ClientData) &gradientCoordCO, 0}, {TK_OPTION_CUSTOM, "-top", NULL, NULL, NULL, Tk_Offset(TreeGradient_, topObj), Tk_Offset(TreeGradient_, top), TK_OPTION_NULL_OK, (ClientData) &gradientCoordCO, 0}, {TK_OPTION_STRING_TABLE, "-orient", (char *) NULL, (char *) NULL, "horizontal", -1, Tk_Offset(TreeGradient_, vertical), 0, (ClientData) orientStringTable, 0}, {TK_OPTION_INT, "-steps", (char *) NULL, (char *) NULL, "1", -1, Tk_Offset(TreeGradient_, steps), 0, (ClientData) NULL, GRAD_CONF_STEPS}, {TK_OPTION_CUSTOM, "-stops", NULL, NULL, NULL, Tk_Offset(TreeGradient_, stopsObj), Tk_Offset(TreeGradient_, stopArrPtr), TK_OPTION_NULL_OK, (ClientData) &stopsCO, GRAD_CONF_STOPS}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} }; /* *---------------------------------------------------------------------- * * TreeGradient_FromObj -- * * Convert a Tcl_Obj to a TreeGradient. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeGradient_FromObj( TreeCtrl *tree, /* Widget info. */ Tcl_Obj *obj, /* Object to convert from. */ TreeGradient *gradientPtr) /* Returned gradient token. */ { char *name; Tcl_HashEntry *hPtr; name = Tcl_GetString(obj); hPtr = Tcl_FindHashEntry(&tree->gradientHash, name); if (hPtr != NULL) { (*gradientPtr) = (TreeGradient) Tcl_GetHashValue(hPtr); } if ((hPtr == NULL) || ((*gradientPtr)->deletePending != 0)) { Tcl_AppendResult(tree->interp, "gradient \"", name, "\" doesn't exist", NULL); return TCL_ERROR; } return TCL_OK; } /* *---------------------------------------------------------------------- * * Gradient_ToObj -- * * Create a new Tcl_Obj representing a gradient. * * Results: * A Tcl_Obj. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ static Tcl_Obj * Gradient_ToObj( TreeGradient gradient /* Gradient to create Tcl_Obj from. */ ) { return Tcl_NewStringObj(gradient->name, -1); } /* *---------------------------------------------------------------------- * * CalcStepColors -- * * Calculates the colors between (and including) 2 color stops. * These colors are only used when native gradients aren't * supported. * * Results: * 'stepColors' is filled in with exactly 'step's XColors. * * Side effects: * Colors are allocated. * *---------------------------------------------------------------------- */ static void CalcStepColors( TreeCtrl *tree, /* Widget info. */ GradientStop *stop1, /* The first color stop. */ GradientStop *stop2, /* The second color stop. */ XColor *stepColors[], /* Returned colors. */ int steps /* Number of colors to allocate. */ ) { int i; XColor *c1 = stop1->color, *c2 = stop2->color; if (steps == 1) { stepColors[0] = Tk_GetColorByValue(tree->tkwin, (stop1->offset > 0) ? stop2->color : stop1->color); return; } #undef CLAMP #define CLAMP(a,b,c) (((a)<(b))?(b):(((a)>(c))?(c):(a))) for (i = 1; i <= steps; i++) { XColor pref; int range, increment; double factor = (i - 1) * 1.0f / (steps - 1); range = (c2->red - c1->red); increment = (int)(range * factor); pref.red = CLAMP(c1->red + increment, 0, USHRT_MAX); range = (c2->green - c1->green); increment = (int)(range * factor); pref.green = CLAMP(c1->green + increment, 0, USHRT_MAX); range = (c2->blue - c1->blue); increment = (int)(range * factor); pref.blue = CLAMP(c1->blue + increment, 0, USHRT_MAX); stepColors[i - 1] = Tk_GetColorByValue(tree->tkwin, &pref); } #undef CLAMP } /* *---------------------------------------------------------------------- * * Gradient_CalcStepColors -- * * Calculates the entire list of step colors. * These colors are only used when native gradients aren't * supported. * * Results: * The TreeGradient.stepColors array is written with exactly * #steps X #stops XColors. * * Side effects: * Colors are allocated. * *---------------------------------------------------------------------- */ #ifdef TREECTRL_DEBUG int sameXColor(XColor *c1, XColor *c2) { return c1->red == c2->red && c1->green==c2->green && c1->blue==c2->blue; } #endif static void Gradient_CalcStepColors( TreeCtrl *tree, /* Widget info. */ TreeGradient gradient /* Gradient token. */ ) { int i, step1, step2; for (i = 0; i < gradient->stopArrPtr->nstops - 1; i++) { GradientStop *stop1 = gradient->stopArrPtr->stops[i]; GradientStop *stop2 = gradient->stopArrPtr->stops[i+1]; step1 = (int)floor(stop1->offset * (gradient->nStepColors)); step2 = (int)floor(stop2->offset * (gradient->nStepColors))-1; /*dbwin("CalcStepColors %g -> %g steps=%d-%d\n", stop1->offset,stop2->offset,step1,step2);*/ CalcStepColors(tree, stop1, stop2, gradient->stepColors + step1, step2 - step1 + 1); } #ifdef TREECTRL_DEBUG if (!sameXColor(gradient->stepColors[0], gradient->stopArrPtr->stops[0]->color)) dbwin("stepColors[0] not same"); if (!sameXColor(gradient->stepColors[gradient->nStepColors - 1], gradient->stopArrPtr->stops[gradient->stopArrPtr->nstops - 1]->color)) dbwin("stepColors[end-1] not same"); #endif } /* *---------------------------------------------------------------------- * * Gradient_Config -- * * This procedure is called to process an objc/objv list to set * configuration options for a TreeGradient. * * Results: * The return value is a standard Tcl result. If TCL_ERROR is * returned, then an error message is left in interp's result. * * Side effects: * Configuration information, such as text string, colors, font, * etc. get set for gradient; old resources get freed, if there * were any. Display changes may occur. * *---------------------------------------------------------------------- */ static int Gradient_Config( TreeCtrl *tree, /* Widget info. */ TreeGradient gradient, /* Gradient token. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[], /* Argument values. */ int createFlag /* TRUE if the gradient is being created. */ ) { TreeGradient_ saved; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; int mask, maskFree = 0; saved.nStepColors = 0; saved.stepColors = NULL; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tk_SetOptions(tree->interp, (char *) gradient, tree->gradientOptionTable, objc, objv, tree->tkwin, &savedOptions, &mask) != TCL_OK) { mask = 0; continue; } /* Wouldn't have to do this if Tk_InitOptions() would return * a mask of configured options like Tk_SetOptions() does. */ if (createFlag) { mask |= GRAD_CONF_STOPS | GRAD_CONF_STEPS; } /* * Step 1: Save old values */ if (mask & (GRAD_CONF_STOPS | GRAD_CONF_STEPS)) { saved.nStepColors = gradient->nStepColors; saved.stepColors = gradient->stepColors; } /* * Step 2: Process new values */ if (mask & (GRAD_CONF_STOPS | GRAD_CONF_STEPS)) { if (gradient->steps < 1 || gradient->steps > 25) { FormatResult(tree->interp, "steps must be >= 1 and <= 25"); continue; } if ((gradient->stopArrPtr != NULL) && (gradient->stopArrPtr->nstops > 0)) { gradient->nStepColors = gradient->stopArrPtr->nstops * gradient->steps; gradient->stepColors = (XColor **)ckalloc(sizeof(XColor*)*gradient->nStepColors); Gradient_CalcStepColors(tree, gradient); maskFree |= GRAD_CONF_STEPS; } else { gradient->nStepColors = 0; gradient->stepColors = NULL; } } /* * Step 3: Free saved values */ if (mask & (GRAD_CONF_STOPS | GRAD_CONF_STEPS)) { if (saved.stepColors != NULL) { /* will be NULL when createFlag==1 */ int i; for (i = 0; i < saved.nStepColors; i++) { Tk_FreeColor(saved.stepColors[i]); } WCFREE(saved.stepColors, XColor*, saved.nStepColors); } } Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); /* * Free new values. */ if (maskFree & (GRAD_CONF_STOPS | GRAD_CONF_STEPS)) { if (gradient->stepColors != NULL) { int i; for (i = 0; i < gradient->nStepColors; i++) { Tk_FreeColor(gradient->stepColors[i]); } WCFREE(gradient->stepColors, XColor*, gradient->nStepColors); } } /* * Restore old values. */ if (mask & (GRAD_CONF_STOPS | GRAD_CONF_STEPS)) { gradient->nStepColors = saved.nStepColors; gradient->stepColors = saved.stepColors; } Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * Gradient_FreeResources -- * * Free memory etc associated with a TreeGradient. * * Results: * None. * * Side effects: * Memory is deallocated. * *---------------------------------------------------------------------- */ static void Gradient_FreeResources( TreeCtrl *tree, /* Widget info. */ TreeGradient gradient, /* Gradient token. */ int deleting /* TRUE if deleting the gradient, FALSE if createing a new gradient to replace a deletePending gradient. */ ) { Tcl_HashEntry *hPtr; int i; Tk_FreeConfigOptions((char *) gradient, tree->gradientOptionTable, tree->tkwin); if (gradient->stepColors != NULL) { for (i = 0; i < gradient->nStepColors; i++) Tk_FreeColor(gradient->stepColors[i]); WCFREE(gradient->stepColors, XColor*, gradient->nStepColors); } if (deleting == 0) return; hPtr = Tcl_FindHashEntry(&tree->gradientHash, gradient->name); if (hPtr) /* NULL during creation */ Tcl_DeleteHashEntry(hPtr); WFREE(gradient, TreeGradient_); } /* *---------------------------------------------------------------------- * * TreeGradient_Release -- * * Decrease refCount on a gradient and free it if deletion was * pending. * * Results: * None. * * Side effects: * Memory may be deallocated. * *---------------------------------------------------------------------- */ void TreeGradient_Release( TreeCtrl *tree, /* Widget info. */ TreeGradient gradient /* Gradient token. */ ) { #ifdef TREECTRL_DEBUG if (gradient->refCount <= 0) panic("TreeGradient_Release: refCount <= 0"); #endif gradient->refCount--; if ((gradient->refCount == 0) && (gradient->deletePending != 0)) { Gradient_FreeResources(tree, gradient, 1); } } /* *---------------------------------------------------------------------- * * Gradient_CreateAndConfig -- * * Allocate and initialize a gradient. * * Results: * Pointer to the new Gradient, or NULL if an error occurs. * * Side effects: * Memory is allocated. * *---------------------------------------------------------------------- */ static TreeGradient Gradient_CreateAndConfig( TreeCtrl *tree, /* Widget info. */ char *name, /* Name of new gradient. */ int objc, /* Number of config-option arg-value pairs. */ Tcl_Obj *CONST objv[] /* Config-option arg-value pairs. */ ) { TreeGradient gradient; gradient = (TreeGradient) ckalloc(sizeof(TreeGradient_)); memset(gradient, '\0', sizeof(TreeGradient_)); gradient->name = Tk_GetUid(name); if (Tk_InitOptions(tree->interp, (char *) gradient, tree->gradientOptionTable, tree->tkwin) != TCL_OK) { WFREE(gradient, TreeGradient_); return NULL; } if (Gradient_Config(tree, gradient, objc, objv, TRUE) != TCL_OK) { Gradient_FreeResources(tree, gradient, 1); return NULL; } return gradient; } static void Gradient_Changed( TreeCtrl *tree, /* Widget info. */ TreeGradient gradient /* Gradient token. */ ) { Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_OUT_OF_DATE | DINFO_DRAW_HEADER); } static void Gradient_Deleted( TreeCtrl *tree, /* Widget info. */ TreeGradient gradient /* Gradient token. */ ) { } /* *---------------------------------------------------------------------- * * TreeGradientCmd -- * * This procedure is invoked to process the [gradient] * widget command. See the user documentation for details on what * it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ int TreeGradientCmd( ClientData clientData, /* Widget info. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { TreeCtrl *tree = clientData; static CONST char *commandNames[] = { "cget", "configure", "create", "delete", "names", "native", (char *) NULL }; enum { COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_CREATE, COMMAND_DELETE, COMMAND_NAMES, COMMAND_NATIVE }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandNames, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case COMMAND_CGET: { Tcl_Obj *resultObjPtr = NULL; TreeGradient gradient; if (objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "name option"); return TCL_ERROR; } if (TreeGradient_FromObj(tree, objv[3], &gradient) != TCL_OK) return TCL_ERROR; resultObjPtr = Tk_GetOptionValue(interp, (char *) gradient, tree->gradientOptionTable, objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); break; } case COMMAND_CONFIGURE: { Tcl_Obj *resultObjPtr = NULL; TreeGradient gradient; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "name ?option? ?value option value ...?"); return TCL_ERROR; } if (TreeGradient_FromObj(tree, objv[3], &gradient) != TCL_OK) return TCL_ERROR; if (objc <= 5) { resultObjPtr = Tk_GetOptionInfo(interp, (char *) gradient, tree->gradientOptionTable, (objc == 4) ? (Tcl_Obj *) NULL : objv[4], tree->tkwin); if (resultObjPtr == NULL) return TCL_ERROR; Tcl_SetObjResult(interp, resultObjPtr); } else { if (Gradient_Config(tree, gradient, objc - 4, objv + 4, 0) != TCL_OK) return TCL_ERROR; Gradient_Changed(tree, gradient); } break; } /* T gradient create NAME ?option value ...? */ case COMMAND_CREATE: { char *name; int len; Tcl_HashEntry *hPtr; int isNew; TreeGradient gradient; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "name ?option value ...?"); return TCL_ERROR; } name = Tcl_GetStringFromObj(objv[3], &len); if (!len) { FormatResult(interp, "invalid gradient name \"\""); return TCL_ERROR; } /* Just like named fonts, if we create a new gradient that has the * same name as one that is awaiting deletion, we copy the new * config to the old gradient and forget it is being deleted. */ hPtr = Tcl_FindHashEntry(&tree->gradientHash, name); if (hPtr != NULL) { TreeGradient gradient2; gradient = (TreeGradient) Tcl_GetHashValue(hPtr); if (gradient->deletePending == 0) { FormatResult(interp, "gradient \"%s\" already exists", name); return TCL_ERROR; } gradient2 = Gradient_CreateAndConfig(tree, name, objc - 4, objv + 4); if (gradient2 == NULL) return TCL_ERROR; Gradient_FreeResources(tree, gradient, 0); gradient->stopArrPtr = gradient2->stopArrPtr; gradient->steps = gradient2->steps; gradient->nStepColors = gradient2->nStepColors; gradient->stepColors = gradient2->stepColors; gradient->deletePending = 0; WFREE(gradient2, TreeGradient_); Gradient_Changed(tree, gradient); break; } gradient = Gradient_CreateAndConfig(tree, name, objc - 4, objv + 4); if (gradient == NULL) return TCL_ERROR; hPtr = Tcl_CreateHashEntry(&tree->gradientHash, name, &isNew); Tcl_SetHashValue(hPtr, gradient); Tcl_SetObjResult(interp, Gradient_ToObj((TreeGradient) gradient)); break; } /* T gradient delete ?name ...? */ case COMMAND_DELETE: { int i; TreeGradient gradient; if (objc < 3) { Tcl_WrongNumArgs(interp, 3, objv, "?name ...?"); return TCL_ERROR; } for (i = 3; i < objc; i++) { if (TreeGradient_FromObj(tree, objv[i], &gradient) != TCL_OK) return TCL_ERROR; if (gradient->refCount > 0) { gradient->deletePending = 1; } else { Gradient_Deleted(tree, gradient); Gradient_FreeResources(tree, gradient, 1); } } break; } /* T gradient names */ case COMMAND_NAMES: { Tcl_Obj *listObj; Tcl_HashSearch search; Tcl_HashEntry *hPtr; TreeGradient gradient; if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, NULL); return TCL_ERROR; } listObj = Tcl_NewListObj(0, NULL); hPtr = Tcl_FirstHashEntry(&tree->gradientHash, &search); while (hPtr != NULL) { gradient = (TreeGradient) Tcl_GetHashValue(hPtr); if (gradient->deletePending == 0) { Tcl_ListObjAppendElement(interp, listObj, Gradient_ToObj(gradient)); } hPtr = Tcl_NextHashEntry(&search); } Tcl_SetObjResult(interp, listObj); break; } /* T gradient native ?bool? */ case COMMAND_NATIVE: { int native; if (objc > 4) { Tcl_WrongNumArgs(interp, 3, objv, "?preference?"); return TCL_ERROR; } if (objc == 4) { if (Tcl_GetBooleanFromObj(interp, objv[3], &native) != TCL_OK) { return TCL_ERROR; } if (native != tree->nativeGradients) { Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_OUT_OF_DATE | DINFO_DRAW_HEADER); tree->nativeGradients = native; } } native = Tree_HasNativeGradients(tree); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(native)); break; } } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeGradient_IsOpaque -- * * Test whether a gradient would be drawn fully opaque or not. * * Results: * 1 if opaque, 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeGradient_IsOpaque( TreeCtrl *tree, /* Widget info. */ TreeGradient gradient /* Gradient token. */ ) { GradientStopArray *stopArrPtr = gradient->stopArrPtr; int i; if (stopArrPtr->nstops < 2) return 0; /* no colors == fully transparent */ if (!tree->nativeGradients || !Tree_HasNativeGradients(tree)) return 1; for (i = 0; i < stopArrPtr->nstops; i++) { GradientStop *stop = stopArrPtr->stops[i]; if (stop->opacity < 1.0f) return 0; } return 1; } /* *---------------------------------------------------------------------- * * TreeGradient_InitWidget -- * * Gradient-related package initialization. * * Results: * A standard Tcl result. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeGradient_InitWidget( TreeCtrl *tree /* Widget info. */ ) { tree->gradientOptionTable = Tk_CreateOptionTable(tree->interp, gradientOptionSpecs); tree->nativeGradients = 1; /* Preference, not availability */ } /* *---------------------------------------------------------------------- * * TreeGradient_FreeWidget -- * * Free gradient-related resources for a deleted TreeCtrl. * * Results: * None. * * Side effects: * Memory is freed. * *---------------------------------------------------------------------- */ void TreeGradient_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { Tcl_HashEntry *hPtr; Tcl_HashSearch search; TreeGradient gradient; while (1) { hPtr = Tcl_FirstHashEntry(&tree->gradientHash, &search); if (hPtr == NULL) break; gradient = (TreeGradient) Tcl_GetHashValue(hPtr); if (gradient->refCount != 0) { panic("TreeGradient_Free: one or more gradients still being used"); } Gradient_FreeResources(tree, gradient, 1); } Tcl_DeleteHashTable(&tree->gradientHash); } /* *---------------------------------------------------------------------- * * TreeGradient_FillRoundRectX11 -- * * Paint a rectangle with a gradient using XFillRectangle. * We can't paint a rounded rectangle with a gradient on X11. * If I could clip drawing to arc's then I could do it. * * Results: * None. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ void TreeGradient_FillRoundRectX11( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to paint. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { if (tr.height <= 0 || tr.width <= 0 || gradient->nStepColors <= 0) return; /* Use the first stop color */ Tree_FillRoundRect(tree, td, clip, gradient->stopArrPtr->stops[0]->color, tr, rx, ry, open); } /* *---------------------------------------------------------------------- * * TreeGradient_FillRectX11 -- * * Paint a rectangle with a gradient using XFillRectangle. * * Results: * None. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ void _TreeGradient_FillRectX11( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr /* Rectangle to paint. */ ) { TreeRectangle trSub, trPaint; int i; float delta; GC gc; if (tr.height <= 0 || tr.width <= 0 || gradient->nStepColors <= 0) return; trSub = trBrush; if (gradient->vertical) { delta = ((float)trBrush.height) / gradient->nStepColors; for (i = 0; i < gradient->nStepColors; i++) { float y1 = trBrush.y + i * delta; float y2 = trBrush.y + (i+1) * delta; trSub.y = (int)y1; trSub.height = (int)(ceil(y2) - floor(y1)); if (TreeRect_Intersect(&trPaint, &trSub, &tr)) { gc = Tk_GCForColor(gradient->stepColors[i], Tk_WindowId(tree->tkwin)); Tree_FillRectangle(tree, td, clip, gc, trPaint); } } } else { delta = ((float)trBrush.width) / gradient->nStepColors; for (i = 0; i < gradient->nStepColors; i++) { float x1 = trBrush.x + i * delta; float x2 = trBrush.x + (i+1) * delta; trSub.x = (int)x1; trSub.width = (int)(ceil(x2) - floor(x1)); if (TreeRect_Intersect(&trPaint, &trSub, &tr)) { gc = Tk_GCForColor(gradient->stepColors[i], Tk_WindowId(tree->tkwin)); Tree_FillRectangle(tree, td, clip, gc, trPaint); } } } } void TreeGradient_FillRectX11( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr /* Rectangle to paint. */ ) { TreeRectangle trSub; int oldX = trBrush.x, oldY = trBrush.y; if (trBrush.height < 1 || trBrush.width < 1) return; if (tr.height < 1 || tr.width < 1) return; /* This implements tiling of the gradient brush */ while (tr.x < trBrush.x) trBrush.x -= trBrush.width; while (tr.x >= trBrush.x + trBrush.width) trBrush.x += trBrush.width; while (tr.y < trBrush.y) trBrush.y -= trBrush.height; while (tr.y >= trBrush.y + trBrush.height) trBrush.y += trBrush.height; oldX = trBrush.x, oldY = trBrush.y; while (trBrush.x < tr.x + tr.width) { trBrush.y = oldY; while (trBrush.y < tr.y + tr.height) { TreeRect_Intersect(&trSub, &trBrush, &tr); _TreeGradient_FillRectX11(tree, td, clip, gradient, trBrush, trSub); trBrush.y += trBrush.height; } trBrush.x += trBrush.width; } } void TreeGradient_DrawRectX11( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to outline. */ int outlineWidth, /* Width of outline. */ int open /* RECT_OPEN_x flags */ ) { TreeRectangle trEdge; if (!(open & RECT_OPEN_W)) { trEdge.x = tr.x, trEdge.y = tr.y, trEdge.width = outlineWidth, trEdge.height = tr.height; TreeGradient_FillRectX11(tree, td, clip, gradient, trBrush, trEdge); } if (!(open & RECT_OPEN_N)) { trEdge.x = tr.x, trEdge.y = tr.y, trEdge.width = tr.width, trEdge.height = outlineWidth; TreeGradient_FillRectX11(tree, td, clip, gradient, trBrush, trEdge); } if (!(open & RECT_OPEN_E)) { trEdge.x = tr.x + tr.width - outlineWidth, trEdge.y = tr.y, trEdge.width = outlineWidth, trEdge.height = tr.height; TreeGradient_FillRectX11(tree, td, clip, gradient, trBrush, trEdge); } if (!(open & RECT_OPEN_S)) { trEdge.x = tr.x, trEdge.y = tr.y + tr.height - outlineWidth, trEdge.width = tr.width, trEdge.height = outlineWidth; TreeGradient_FillRectX11(tree, td, clip, gradient, trBrush, trEdge); } } /* *---------------------------------------------------------------------- * * TreeColor_DrawRect -- * * Draw a rectangle with a gradient or solid color. * * Results: * If the gradient has <2 stops then nothing is drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ void TreeColor_DrawRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeColor *tc, /* Color info. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to outline. */ int outlineWidth, /* Width of outline. */ int open /* RECT_OPEN_x flags */ ) { if (tc == NULL || outlineWidth < 1 || open == RECT_OPEN_WNES) return; if (tc->gradient != NULL) { TreeGradient_DrawRect(tree, td, clip, tc->gradient, trBrush, tr, outlineWidth, open); } if (tc->color != NULL) { GC gc = Tk_GCForColor(tc->color, td.drawable); TreeRectangle trEdge; if (!(open & RECT_OPEN_W)) { trEdge.x = tr.x, trEdge.y = tr.y, trEdge.width = outlineWidth, trEdge.height = tr.height; Tree_FillRectangle(tree, td, clip, gc, trEdge); } if (!(open & RECT_OPEN_N)) { trEdge.x = tr.x, trEdge.y = tr.y, trEdge.width = tr.width, trEdge.height = outlineWidth; Tree_FillRectangle(tree, td, clip, gc, trEdge); } if (!(open & RECT_OPEN_E)) { trEdge.x = tr.x + tr.width - outlineWidth, trEdge.y = tr.y, trEdge.width = outlineWidth, trEdge.height = tr.height; Tree_FillRectangle(tree, td, clip, gc, trEdge); } if (!(open & RECT_OPEN_S)) { trEdge.x = tr.x, trEdge.y = tr.y + tr.height - outlineWidth, trEdge.width = tr.width, trEdge.height = outlineWidth; Tree_FillRectangle(tree, td, clip, gc, trEdge); } } } /* *---------------------------------------------------------------------- * * TreeColor_FillRect -- * * Paint a rectangle with a gradient or solid color. * * Results: * If the gradient has <2 stops then nothing is drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ void TreeColor_FillRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeColor *tc, /* Color info. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr /* Rectangle to paint. */ ) { if (tc == NULL) return; if (tc->gradient != NULL) { TreeGradient_FillRect(tree, td, clip, tc->gradient, trBrush, tr); } if (tc->color != NULL) { GC gc = Tk_GCForColor(tc->color, td.drawable); Tree_FillRectangle(tree, td, clip, gc, tr); } } /* *---------------------------------------------------------------------- * * TreeColor_DrawRoundRect -- * * Draw a rounded rectangle with a gradient or solid color. * * Results: * If the gradient has <2 stops then nothing is drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ void TreeColor_DrawRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeColor *tc, /* Color info. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to outline. */ int outlineWidth, /* Width of outline. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { if (tc == NULL) return; if (tc->gradient != NULL) { TreeGradient_DrawRoundRect(tree, td, clip, tc->gradient, trBrush, tr, outlineWidth, rx, ry, open); } if (tc->color != NULL) { Tree_DrawRoundRect(tree, td, clip, tc->color, tr, outlineWidth, rx, ry, open); } } /* *---------------------------------------------------------------------- * * TreeColor_FillRoundRect -- * * Paint a rounded rectangle with a gradient or solid color. * * Results: * If the gradient has <2 stops then nothing is drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ void TreeColor_FillRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeColor *tc, /* Color info. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to paint. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { if (tc == NULL) return; if (tc->gradient != NULL) { TreeGradient_FillRoundRect(tree, td, clip, tc->gradient, trBrush, tr, rx, ry, open); } if (tc->color != NULL) { Tree_FillRoundRect(tree, td, clip, tc->color, tr, rx, ry, open); } } tktreectrl-2.4.1/library/0000755000076400010400000000000011646706172015671 5ustar TimAdministratorstktreectrl-2.4.1/library/filelist-bindings.tcl0000644000076400010400000010034311562306551021776 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker bind TreeCtrlFileList { TreeCtrl::FileListEditCancel %W TreeCtrl::DoubleButton1 %W %x %y break } bind TreeCtrlFileList { set TreeCtrl::Priv(selectMode) toggle TreeCtrl::FileListButton1 %W %x %y break } bind TreeCtrlFileList { set TreeCtrl::Priv(selectMode) add TreeCtrl::FileListButton1 %W %x %y break } bind TreeCtrlFileList { set TreeCtrl::Priv(selectMode) set TreeCtrl::FileListButton1 %W %x %y break } bind TreeCtrlFileList { TreeCtrl::FileListMotion1 %W %x %y break } bind TreeCtrlFileList { TreeCtrl::FileListLeave1 %W %x %y break } bind TreeCtrlFileList { TreeCtrl::FileListRelease1 %W %x %y break } # Escape cancels any drag-and-drop operation in progress bind TreeCtrlFileList { TreeCtrl::FileListEscapeKey %W } ## Bindings for the Entry widget used for editing # Accept edit when we lose the focus bind TreeCtrlEntry { if {[winfo ismapped %W]} { TreeCtrl::EditClose [winfo parent %W] entry 1 0 } } # Accept edit on bind TreeCtrlEntry { TreeCtrl::EditClose [winfo parent %W] entry 1 1 break } # Cancel edit on , use break as we are doing a "closing" action # and don't want that propagated upwards bind TreeCtrlEntry { TreeCtrl::EditClose [winfo parent %W] entry 0 1 break } ## Bindings for the Text widget used for editing # Accept edit when we lose the focus bind TreeCtrlText { if {[winfo ismapped %W]} { TreeCtrl::EditClose [winfo parent %W] text 1 0 } } # Accept edit on bind TreeCtrlText { TreeCtrl::EditClose [winfo parent %W] text 1 1 break } # Cancel edit on , use break as we are doing a "closing" action # and don't want that propagated upwards bind TreeCtrlText { TreeCtrl::EditClose [winfo parent %W] text 0 1 break } namespace eval TreeCtrl { variable Priv # Number of milliseconds after clicking a selected item before the Edit # widget appears. set Priv(edit,delay) 500 # Try to deal with people importing ttk::entry into the global namespace; # we want tk::entry if {[llength [info commands ::tk::entry]]} { set Priv(entryCmd) ::tk::entry } else { set Priv(entryCmd) ::entry } } # ::TreeCtrl::IsSensitive # # Returns 1 if the given window coordinates are over an element that should # respond to mouse clicks. The list of elements that respond to mouse clicks # is set by calling ::TreeCtrl::SetSensitive. # # Arguments: # T The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::IsSensitive {T x y} { variable Priv $T identify -array id $x $y if {$id(where) ne "item" || $id(element) eq ""} { return 0 } if {![$T item enabled $id(item)]} { return 0 } foreach list $Priv(sensitive,$T) { set eList [lassign $list C S] if {[$T column compare $id(column) != $C]} continue if {[$T item style set $id(item) $C] ne $S} continue if {[lsearch -exact $eList $id(element)] == -1} continue return 1 } return 0 } # ::TreeCtrl::IsSensitiveMarquee # # Returns 1 if the given window coordinates are over an element that # should respond to the marquee. The list of elements that respond to the # marquee is set by calling ::TreeCtrl::SetSensitiveMarquee, or if that list # is empty then the same list passed to ::TreeCtrl::SetSensitive. # # Arguments: # T The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::IsSensitiveMarquee {T x y} { variable Priv $T identify -array id $x $y if {$id(where) ne "item" || $id(element) eq ""} { return 0 } if {![$T item enabled $id(item)]} { return 0 } if {![info exists Priv(sensitive,marquee,$T)]} { set sensitive $Priv(sensitive,$T) } elseif {[llength $Priv(sensitive,marquee,$T)] == 0} { set sensitive $Priv(sensitive,$T) } else { set sensitive $Priv(sensitive,marquee,$T) } foreach list $sensitive { set eList [lassign $list C S] if {[$T column compare $id(column) != $C]} continue if {[$T item style set $id(item) $C] ne $S} continue if {[lsearch -exact $eList $id(element)] == -1} continue return 1 } return 0 } # ::TreeCtrl::FileListButton1 # # Handle . # # Arguments: # T The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::FileListButton1 {T x y} { variable Priv focus $T $T identify -array id $x $y set marquee 0 set Priv(buttonMode) "" foreach e {text entry} { if {[winfo exists $T.$e] && [winfo ismapped $T.$e]} { EditClose $T $e 1 0 } } FileListEditCancel $T # Click outside any item if {$id(where) eq ""} { set marquee 1 # Click in header } elseif {$id(where) eq "header"} { ButtonPress1 $T $x $y # Click in item } elseif {$id(where) eq "item"} { if {$id(button) || $id(line) ne ""} { ButtonPress1 $T $x $y } elseif {$id(column) ne ""} { set item $id(item) set drag 0 if {[IsSensitive $T $x $y]} { set Priv(drag,wasSel) [$T selection includes $item] $T activate $item if {$Priv(selectMode) eq "add"} { BeginExtend $T $item } elseif {$Priv(selectMode) eq "toggle"} { BeginToggle $T $item } elseif {![$T selection includes $item]} { BeginSelect $T $item } # Changing the selection might change the list if {[$T item id $item] eq ""} return # Click selected item(s) to drag or rename if {[$T selection includes $item]} { set drag 1 } } elseif {[FileListEmulateWin7 $T] && [IsSensitiveMarquee $T $x $y]} { # Click selected item(s) to drag or rename if {[$T selection includes $item]} { set Priv(drag,wasSel) 1 $T activate $item set drag 1 # Click marquee-sensitive parts of an unselected item # in single-select mode changes nothing until a drag # occurs or the mouse button is released. } elseif {[$T cget -selectmode] eq "single"} { set Priv(drag,wasSel) 0 set drag 1 } else { set marquee 1 } } else { set marquee 1 } if {$drag} { set Priv(drag,motion) 0 set Priv(drag,click,x) $x set Priv(drag,click,y) $y set Priv(drag,x) [$T canvasx $x] set Priv(drag,y) [$T canvasy $y] set Priv(drop) "" set Priv(drag,item) $item set Priv(drag,C) $id(column) set Priv(drag,E) $id(element) set Priv(buttonMode) drag } } } if {$marquee && [$T cget -selectmode] eq "single"} { set marquee 0 $T selection clear } if {$marquee} { set Priv(buttonMode) marquee if {![info exists Priv(sensitive,marquee,$T)]} { set Priv(sensitive,marquee,$T) {} } if {$Priv(selectMode) ne "set"} { set Priv(selection) [$T selection get] } else { if {![FileListEmulateWin7 $T]} { $T selection clear } set Priv(selection) {} } MarqueeBegin $T $x $y set Priv(marquee,motion) 0 if {[FileListEmulateWin7 $T]} { if {[IsSensitiveMarquee $T $x $y]} { set item $id(item) $T activate $item if {$Priv(selectMode) ne "add"} { $T selection anchor $item } } } } return } # ::TreeCtrl::FileListMotion1 # # Override default to handle "drag" and "marquee". # # Arguments: # T The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::FileListMotion1 {T x y} { variable Priv if {![info exists Priv(buttonMode)]} return switch $Priv(buttonMode) { "drag" - "marquee" { set Priv(autoscan,command,$T) {FileListMotion %T %x %y} AutoScanCheck $T $x $y FileListMotion $T $x $y } default { Motion1 $T $x $y } } return } # ::TreeCtrl::FileListMotion # # Handle . # # Arguments: # T The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::FileListMotion {T x y} { variable Priv if {![info exists Priv(buttonMode)]} return switch $Priv(buttonMode) { "marquee" { MarqueeUpdate $T $x $y set select $Priv(selection) set deselect {} set items {} set Priv(marquee,motion) 1 set sensitive $Priv(sensitive,marquee,$T) if {[llength $sensitive] == 0} { set sensitive $Priv(sensitive,$T) } # Check items covered by the marquee foreach list [$T marque identify] { set item [lindex $list 0] if {![$T item enabled $item]} continue # Check covered columns in this item foreach sublist [lrange $list 1 end] { set column [lindex $sublist 0] set ok 0 # Check covered elements in this column foreach E [lrange $sublist 1 end] { foreach sList $sensitive { set sEList [lassign $sList sC sS] if {[$T column compare $column != $sC]} continue if {[$T item style set $item $sC] ne $sS} continue if {[lsearch -exact $sEList $E] == -1} continue set ok 1 break } } # Some sensitive elements in this column are covered if {$ok} { lappend items $item } } } foreach item $items { # Toggle selected status if {$Priv(selectMode) eq "toggle"} { set i [lsearch -exact $Priv(selection) $item] if {$i == -1} { lappend select $item } else { set i [lsearch -exact $select $item] set select [lreplace $select $i $i] } } else { lappend select $item } } $T selection modify $select all } "drag" { if {!$Priv(drag,motion)} { # Detect initial mouse movement if {(abs($x - $Priv(drag,click,x)) <= 4) && (abs($y - $Priv(drag,click,y)) <= 4)} return # In Win7 single-selectmode, when the insensitive parts of an # unselected item are clicked, the active item and selection # aren't changed until the drag begins. if {[FileListEmulateWin7 $T] && [$T cget -selectmode] eq "single" && !$Priv(drag,wasSel)} { $T activate $Priv(drag,item) $T selection modify $Priv(drag,item) all } set Priv(selection) [$T selection get] set Priv(drop) "" $T dragimage clear # For each selected item, add some elements to the dragimage foreach I $Priv(selection) { foreach list $Priv(dragimage,$T) { set EList [lassign $list C S] if {[$T item style set $I $C] eq $S} { eval $T dragimage add $I $C $EList } } } set Priv(drag,motion) 1 TryEvent $T Drag begin {} } # Find the element under the cursor set drop "" $T identify -array id $x $y if {[IsSensitive $T $x $y]} { set sensitive 1 } elseif {[FileListEmulateWin7 $T] && [IsSensitiveMarquee $T $x $y]} { set sensitive 1 } else { set sensitive 0 } if {$sensitive} { set item $id(item) # If the item is not in the pre-drag selection # (i.e. not being dragged) and it is a directory, # see if we can drop on it if {[lsearch -exact $Priv(selection) $item] == -1} { if {[$T item order $item -visible] < $Priv(DirCnt,$T)} { set drop $item # We can drop if dragged item isn't an ancestor foreach item2 $Priv(selection) { if {[$T item isancestor $item2 $item]} { set drop "" break } } } } } # Select the directory under the cursor (if any) and deselect # the previous drop-directory (if any) $T selection modify $drop $Priv(drop) set Priv(drop) $drop # Show the dragimage in its new position if {0 && [$T dragimage cget -style] ne ""} { set x [$T canvasx $x] set y [$T canvasy $y] } else { set x [expr {[$T canvasx $x] - $Priv(drag,x)}] set y [expr {[$T canvasy $y] - $Priv(drag,y)}] } $T dragimage offset $x $y $T dragimage configure -visible yes } default { Motion1 $T $x $y } } return } # ::TreeCtrl::FileListLeave1 # # Handle . # # Arguments: # T The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::FileListLeave1 {T x y} { variable Priv # This gets called when I click the mouse on Unix, and buttonMode is unset if {![info exists Priv(buttonMode)]} return switch $Priv(buttonMode) { default { Leave1 $T $x $y } } return } # ::TreeCtrl::FileListRelease1 # # Handle . # # Arguments: # T The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::FileListRelease1 {T x y} { variable Priv if {![info exists Priv(buttonMode)]} return switch $Priv(buttonMode) { "marquee" { AutoScanCancel $T MarqueeEnd $T $x $y if {[FileListEmulateWin7 $T]} { # If the mouse was clicked in whitespace or insensitive part # of an item and the mouse did not move then the selection # is not modified until after the mouse button is released. if {!$Priv(marquee,motion)} { if {[IsSensitiveMarquee $T $x $y]} { set item [$T item id active] if {$Priv(selectMode) eq "add"} { BeginExtend $T $item } elseif {$Priv(selectMode) eq "toggle"} { BeginToggle $T $item } else { BeginSelect $T $item } } elseif {$Priv(selectMode) eq "set"} { # Clicked whitespace $T selection clear } } } } "drag" { AutoScanCancel $T # Some dragging occurred if {$Priv(drag,motion)} { $T dragimage configure -visible no if {$Priv(drop) ne ""} { $T selection modify {} $Priv(drop) TryEvent $T Drag receive \ [list I $Priv(drop) l $Priv(selection)] } TryEvent $T Drag end {} } else { set rename 0 if {[FileListEmulateWin7 $T]} { # If the mouse was clicked in the insensitive parts of # a selected item and multiple items are selected and the # mouse did not move then the selection is not modified # until after the mouse button is released. set item $Priv(drag,item) if {[$T selection count] == 1 && $Priv(selectMode) eq "set"} { # In single-selectmode, when clicking the insensitive # parts of an unselected item, the active item and # selection aren't changed until the button is released. if {[$T cget -selectmode] eq "single" && !$Priv(drag,wasSel)} { $T activate $item $T selection modify $item all } else { # If clicked already-selected item, rename it set rename $Priv(drag,wasSel) } } elseif {[IsSensitive $T $x $y] && !$Priv(drag,wasSel)} { # Selection was modified on ButtonPress, do nothing } elseif {$Priv(selectMode) eq "add"} { # Shift-click does nothing to already-selected item #BeginExtend $T $item } elseif {$Priv(selectMode) eq "toggle"} { BeginToggle $T $item } else { # Make this the only selected item BeginSelect $T $item } } elseif {$Priv(selectMode) eq "toggle"} { # don't rename } elseif {$Priv(drag,wasSel)} { # Clicked/released a selected item, but didn't drag set rename 1 } if {$rename} { set I [$T item id active] set C $Priv(drag,C) set E $Priv(drag,E) set S [$T item style set $I $C] set ok 0 foreach list $Priv(edit,$T) { set eEList [lassign $list eC eS] if {[$T column compare $C != $eC]} continue if {$S ne $eS} continue if {[lsearch -exact $eEList $E] == -1} continue set ok 1 break } if {$ok} { FileListEditCancel $T set Priv(editId,$T) \ [after $Priv(edit,delay) [list ::TreeCtrl::FileListEdit $T $I $C $E]] } } } } default { Release1 $T $x $y } } set Priv(buttonMode) "" return } # ::TreeCtrl::EscapeKey # # Handle the key. # # T The treectrl widget. proc ::TreeCtrl::FileListEscapeKey {T} { variable Priv if {[info exists Priv(buttonMode)] && $Priv(buttonMode) eq "drag"} { set Priv(buttonMode) "" AutoScanCancel $T if {$Priv(drag,motion)} { $T selection modify $Priv(selection) all $T dragimage configure -visible no TryEvent $T Drag end {} } return -code break } return } # ::TreeCtrl::FileListEdit # # Displays an Entry or Text widget to allow the user to edit the specified # text element. # # Arguments: # T The treectrl widget. # I Item. # C Column. # E Element. proc ::TreeCtrl::FileListEdit {T I C E} { variable Priv array unset Priv editId,$T if {![winfo exists $T]} return set lines [$T item element cget $I $C $E -lines] if {$lines eq ""} { set lines [$T element cget $E -lines] } # Scroll item into view $T see $I ; update # Multi-line edit if {$lines ne "1"} { scan [$T item bbox $I $C] "%d %d %d %d" x1 y1 x2 y2 set S [$T item style set $I $C] set padx [$T style layout $S $E -padx] # FIXME: max of padx or union padding GetPadding $padx padw pade AddUnionPadding $T $S $E padw pade TextExpanderOpen $T $I $C $E [expr {$x2 - $x1 - $padw - $pade}] # Single-line edit } else { EntryExpanderOpen $T $I $C $E } TryEvent $T Edit begin [list I $I C $C E $E] return } proc ::TreeCtrl::GetPadding {pad _padw _pade} { upvar $_padw padw upvar $_pade pade if {[llength $pad] == 2} { lassign $pad padw pade } else { set pade [set padw $pad] } return } # Recursively adds -padx and -ipadx values of other elements in a style that # contain the given element in its -union. proc ::TreeCtrl::AddUnionPadding {T S E _padw _pade} { upvar $_padw padw upvar $_pade pade foreach E2 [$T style elements $S] { set union [$T style layout $S $E2 -union] if {[lsearch -exact $union $E] == -1} continue foreach option {-padx -ipadx} { set pad [$T style layout $S $E2 $option] GetPadding $pad p1 p2 # FIXME: max of padx or union padding incr padw $p1 incr pade $p2 } AddUnionPadding $T $S $E2 padw pade } return } # ::TreeCtrl::FileListEditCancel # # Aborts any scheduled display of the text-edit widget. # # Arguments: # T The treectrl widget. proc ::TreeCtrl::FileListEditCancel {T} { variable Priv if {[info exists Priv(editId,$T)]} { after cancel $Priv(editId,$T) array unset Priv editId,$T } return } # ::TreeCtrl::SetDragImage # # Specifies the list of elements that should be added to the dragimage. # # Arguments: # T The treectrl widget. # listOfLists {{column style element ...} {column style element ...}} proc ::TreeCtrl::SetDragImage {T listOfLists} { variable Priv foreach list $listOfLists { set elements [lassign $list column style] if {[$T column id $column] eq ""} { error "column \"$column\" doesn't exist" } if {[lsearch -exact [$T style names] $style] == -1} { error "style \"$style\" doesn't exist" } foreach element $elements { if {[lsearch -exact [$T element names] $element] == -1} { error "element \"$element\" doesn't exist" } } } set Priv(dragimage,$T) $listOfLists return } # ::TreeCtrl::SetEditable # # Specifies the list of text elements that can be edited. # # Arguments: # T The treectrl widget. # listOfLists {{column style element ...} {column style element ...}} proc ::TreeCtrl::SetEditable {T listOfLists} { variable Priv foreach list $listOfLists { set elements [lassign $list column style] if {[$T column id $column] eq ""} { error "column \"$column\" doesn't exist" } if {[lsearch -exact [$T style names] $style] == -1} { error "style \"$style\" doesn't exist" } foreach element $elements { if {[lsearch -exact [$T element names] $element] == -1} { error "element \"$element\" doesn't exist" } if {[$T element type $element] ne "text"} { error "element \"$element\" is not of type \"text\"" } } } set Priv(edit,$T) $listOfLists return } # ::TreeCtrl::SetSensitive # # Specifies the list of elements that respond to mouse clicks. # # Arguments: # T The treectrl widget. # listOfLists {{column style element ...} {column style element ...}} proc ::TreeCtrl::SetSensitive {T listOfLists} { variable Priv foreach list $listOfLists { set elements [lassign $list column style] if {[$T column id $column] eq ""} { error "column \"$column\" doesn't exist" } if {[lsearch -exact [$T style names] $style] == -1} { error "style \"$style\" doesn't exist" } foreach element $elements { if {[lsearch -exact [$T element names] $element] == -1} { error "element \"$element\" doesn't exist" } } } set Priv(sensitive,$T) $listOfLists return } # ::TreeCtrl::SetSensitiveMarquee # # Specifies the list of elements that are sensitive to the marquee. # If the list is empty then the same list passed to SetSensitive # is used. # # Arguments: # T The treectrl widget. # sensitive Boolean value. proc ::TreeCtrl::SetSensitiveMarquee {T listOfLists} { variable Priv foreach list $listOfLists { set elements [lassign $list column style] if {[$T column id $column] eq ""} { error "column \"$column\" doesn't exist" } if {[lsearch -exact [$T style names] $style] == -1} { error "style \"$style\" doesn't exist" } foreach element $elements { if {[lsearch -exact [$T element names] $element] == -1} { error "element \"$element\" doesn't exist" } } } set Priv(sensitive,marquee,$T) $listOfLists return } # ::TreeCtrl::SetSelectedItemsSensitive # # Specifies whether or not entire items are sensitive to mouse clicks # when they are already selected. # # Arguments: # T The treectrl widget. # sensitive Boolean value. proc ::TreeCtrl::SetSelectedItemsSensitive {T sensitive} { variable Priv if {![string is boolean -strict $sensitive]} { error "expected boolean but got \"$sensitive\"" } set Priv(sensitiveSelected,$T) $sensitive return } # ::TreeCtrl::FileListEmulateWin7 # # Test the flag telling the bindings to use Windows 7 behavior. # # Arguments: # T The treectrl widget. # win7 Boolean value. proc ::TreeCtrl::FileListEmulateWin7 {T args} { variable Priv if {[llength $args]} { set win7 [lindex $args 0] if {![string is boolean -strict $win7]} { error "expected boolean but got \"$win7\"" } set Priv(win7,$T) $win7 return } if {[info exists Priv(win7,$T)]} { return $Priv(win7,$T) } return 0 } # ::TreeCtrl::EntryOpen # # Display a ::tk::entry so the user can edit the specified text element. # # Arguments: # T The treectrl widget. # item Item. # column Column. # element Element. proc ::TreeCtrl::EntryOpen {T item column element} { variable Priv set Priv(entry,$T,item) $item set Priv(entry,$T,column) $column set Priv(entry,$T,element) $element set Priv(entry,$T,focus) [focus] # Get window coords of the Element scan [$T item bbox $item $column $element] "%d %d" x y # Get the font used by the Element set font [$T item element perstate $item $column $element -font] if {$font eq ""} { set font [$T cget -font] } # Get the text used by the Element. Could check master Element too. set text [$T item element cget $item $column $element -text] # Create the Entry widget if needed set e $T.entry if {[winfo exists $e]} { $e delete 0 end } else { $Priv(entryCmd) $e -borderwidth 1 -relief solid -highlightthickness 0 bindtags $e [linsert [bindtags $e] 1 TreeCtrlEntry] } # Pesky MouseWheel $T notify bind $e { TreeCtrl::EditClose %T entry 0 1 } $e configure -font $font $e insert end $text $e selection range 0 end set ebw [$e cget -borderwidth] set ex [expr {$x - $ebw - 1}] place $e -x $ex -y [expr {$y - $ebw - 1}] -bordermode outside # Make the Entry as wide as the text plus "W" but keep it within the # TreeCtrl borders set width [font measure $font ${text}W] set width [expr {$width + ($ebw + 1) * 2}] scan [$T contentbox] "%d %d %d %d" left top right bottom if {$ex + $width > $right} { set width [expr {$right - $ex}] } scan [$T item bbox $item $column] "%d %d %d %d" left top right bottom if {$ex + $width > $right} { set width [expr {$right - $ex}] } place configure $e -width $width focus $e return } # ::TreeCtrl::EntryExpanderOpen # # Display a ::tk::entry so the user can edit the specified text element. # Like EntryOpen, but Entry widget expands/shrinks during typing. # # Arguments: # T The treectrl widget. # item Item. # column Column. # element Element. proc ::TreeCtrl::EntryExpanderOpen {T item column element} { variable Priv set Priv(entry,$T,item) $item set Priv(entry,$T,column) $column set Priv(entry,$T,element) $element set Priv(entry,$T,focus) [focus] # Get window coords of the Element scan [$T item bbox $item $column $element] "%d %d" x y # Get the font used by the Element set font [$T item element perstate $item $column $element -font] if {$font eq ""} { set font [$T cget -font] } set Priv(entry,$T,font) $font # Get the text used by the Element. Could check master Element too. set text [$T item element cget $item $column $element -text] # Create the Entry widget if needed set e $T.entry if {[winfo exists $e]} { $e delete 0 end } else { $Priv(entryCmd) $e -borderwidth 1 -highlightthickness 0 \ -selectborderwidth 0 -relief solid bindtags $e [linsert [bindtags $e] 1 TreeCtrlEntry] # Resize as user types bind $e { after idle [list TreeCtrl::EntryExpanderKeypress [winfo parent %W]] } } # Pesky MouseWheel $T notify bind $e { TreeCtrl::EditClose %T entry 0 1 } $e configure -font $font -background [$T cget -background] $e insert end $text $e selection range 0 end set ebw [$e cget -borderwidth] set ex [expr {$x - $ebw - 1}] place $e -x $ex -y [expr {$y - $ebw - 1}] \ -bordermode outside # Make the Entry as wide as the text plus "W" but keep it within the # TreeCtrl borders set width [font measure $font ${text}W] set width [expr {$width + ($ebw + 1) * 2}] scan [$T contentbox] "%d %d %d %d" left top right bottom if {$ex + $width > $right} { set width [expr {$right - $ex}] } place configure $e -width $width focus $e return } # ::TreeCtrl::EditClose # # Hides the text-edit widget and restores the focus if needed. # Generates and events as needed. # # Arguments: # T The treectrl widget. # type "entry" or "text". # accept 0/1: should an event be generated. # refocus 0/1: should the focus be restored to what it was before editing. proc ::TreeCtrl::EditClose {T type accept {refocus 0}} { variable Priv set w $T.$type # We need the double-idle to get winfo ismapped to report properly # so this don't get the FocusOut following Escape immediately update idletasks place forget $w focus $T update idletasks if {$accept} { if {$type eq "entry"} { set t [$w get] } else { set t [$w get 1.0 end-1c] } TryEvent $T Edit accept \ [list I $Priv($type,$T,item) C $Priv($type,$T,column) \ E $Priv($type,$T,element) t $t] } $T notify unbind $w TryEvent $T Edit end \ [list I $Priv($type,$T,item) C $Priv($type,$T,column) \ E $Priv($type,$T,element)] if {$refocus} { focus $Priv($type,$T,focus) } return } # ::TreeCtrl::EntryExpanderKeypress # # Maintains the width of the text-edit widget during typing. # # Arguments: # T The treectrl widget. proc ::TreeCtrl::EntryExpanderKeypress {T} { variable Priv if {![winfo exists $T]} return set font $Priv(entry,$T,font) set text [$T.entry get] set ebw [$T.entry cget -borderwidth] set ex [winfo x $T.entry] set width [font measure $font ${text}W] set width [expr {$width + ($ebw + 1) * 2}] scan [$T contentbox] "%d %d %d %d" left top right bottom if {$ex + $width > $right} { set width [expr {$right - $ex}] } place configure $T.entry -width $width return } # ::TreeCtrl::TextOpen # # Display a ::tk::text so the user can edit the specified text element. # # Arguments: # T The treectrl widget. # item Item. # column Column. # element Element. # width unused. # height unused. proc ::TreeCtrl::TextOpen {T item column element {width 0} {height 0}} { variable Priv set Priv(text,$T,item) $item set Priv(text,$T,column) $column set Priv(text,$T,element) $element set Priv(text,$T,focus) [focus] # Get window coords of the Element scan [$T item bbox $item $column $element] "%d %d %d %d" x1 y1 x2 y2 # Get the font used by the Element set font [$T item element perstate $item $column $element -font] if {$font eq ""} { set font [$T cget -font] } # Get the text used by the Element. Could check master Element too. set text [$T item element cget $item $column $element -text] set justify [$T element cget $element -justify] if {$justify eq ""} { set justify left } set wrap [$T element cget $element -wrap] if {$wrap eq ""} { set wrap word } # Create the Text widget if needed set w $T.text if {[winfo exists $w]} { $w delete 1.0 end } else { text $w -borderwidth 1 -highlightthickness 0 -relief solid bindtags $w [linsert [bindtags $w] 1 TreeCtrlText] } # Pesky MouseWheel $T notify bind $w { TreeCtrl::EditClose %T text 0 1 } $w tag configure TAG -justify $justify $w configure -font $font -background [$T cget -background] -wrap $wrap $w insert end $text $w tag add sel 1.0 end $w tag add TAG 1.0 end set tbw [$w cget -borderwidth] set tx [expr {$x1 - $tbw - 1}] place $w -x $tx -y [expr {$y1 - $tbw - 1}] \ -width [expr {$x2 - $x1 + ($tbw + 1) * 2}] \ -height [expr {$y2 - $y1 + ($tbw + 1) * 2}] \ -bordermode outside focus $w return } # ::TreeCtrl::TextExpanderOpen # # Display a ::tk::text so the user can edit the specified text element. # Like TextOpen, but Text widget expands/shrinks during typing. # # Arguments: # T The treectrl widget. # item Item. # column Column. # element Element. # width Width of the text element. proc ::TreeCtrl::TextExpanderOpen {T item column element width} { variable Priv set Priv(text,$T,item) $item set Priv(text,$T,column) $column set Priv(text,$T,element) $element set Priv(text,$T,focus) [focus] # Get window coords of the Element scan [$T item bbox $item $column $element] "%d %d %d %d" x1 y1 x2 y2 set Priv(text,$T,center) [expr {$x1 + ($x2 - $x1) / 2}] # Get the font used by the Element set font [$T item element perstate $item $column $element -font] if {$font eq ""} { set font [$T cget -font] } # Get the text used by the Element. Could check master Element too. set text [$T item element cget $item $column $element -text] set justify [$T element cget $element -justify] if {$justify eq ""} { set justify left } set wrap [$T element cget $element -wrap] if {$wrap eq ""} { set wrap word } # Create the Text widget if needed set w $T.text if {[winfo exists $w]} { $w delete 1.0 end } else { text $w -borderwidth 1 -highlightthickness 0 \ -selectborderwidth 0 -relief solid bindtags $w [linsert [bindtags $w] 1 TreeCtrlText] # Resize as user types bind $w { after idle TreeCtrl::TextExpanderKeypress [winfo parent %W] } } # Pesky MouseWheel $T notify bind $w { TreeCtrl::EditClose %T text 0 1 } $w tag configure TAG -justify $justify $w configure -font $font -background [$T cget -background] -wrap $wrap $w insert end $text $w tag add sel 1.0 end $w tag add TAG 1.0 end set Priv(text,$T,font) $font set Priv(text,$T,justify) $justify set Priv(text,$T,width) $width scan [textlayout $font $text -justify $justify -width $width] \ "%d %d" width height set tbw [$w cget -borderwidth] incr tbw place $w -x [expr {$x1 - $tbw}] -y [expr {$y1 - $tbw}] \ -width [expr {$width + $tbw * 2}] \ -height [expr {$height + $tbw * 2}] \ -bordermode outside focus $w return } # ::TreeCtrl::TextExpanderKeypress # # Maintains the size of the text-edit widget during typing. # # Arguments: # T The treectrl widget. proc ::TreeCtrl::TextExpanderKeypress {T} { variable Priv if {![winfo exists $T]} return set font $Priv(text,$T,font) set justify $Priv(text,$T,justify) set width $Priv(text,$T,width) set center $Priv(text,$T,center) set text [$T.text get 1.0 end-1c] scan [textlayout $font $text -justify $justify -width $width] \ "%d %d" width height set tbw [$T.text cget -borderwidth] incr tbw place configure $T.text \ -x [expr {$center - ($width + $tbw * 2) / 2}] \ -width [expr {$width + $tbw * 2}] \ -height [expr {$height + $tbw * 2}] $T.text tag add TAG 1.0 end return } tktreectrl-2.4.1/library/treectrl.tcl0000644000076400010400000015026211565111566020224 0ustar TimAdministrators# Copyright (c) 2002-2011 Tim Baker bind TreeCtrl { TreeCtrl::CursorCheck %W %x %y TreeCtrl::MotionInHeader %W %x %y TreeCtrl::MotionInButtons %W %x %y } bind TreeCtrl { TreeCtrl::CursorCancel %W TreeCtrl::MotionInHeader %W TreeCtrl::MotionInButtons %W } bind TreeCtrl { TreeCtrl::ButtonPress1 %W %x %y } bind TreeCtrl { TreeCtrl::DoubleButton1 %W %x %y } bind TreeCtrl { TreeCtrl::Motion1 %W %x %y } bind TreeCtrl { TreeCtrl::Release1 %W %x %y } bind TreeCtrl { set TreeCtrl::Priv(buttonMode) normal TreeCtrl::BeginExtend %W [%W item id {nearest %x %y}] } # Command-click should provide a discontinuous selection on OSX switch -- [tk windowingsystem] { "aqua" { set modifier Command } default { set modifier Control } } bind TreeCtrl <$modifier-ButtonPress-1> { set TreeCtrl::Priv(buttonMode) normal TreeCtrl::BeginToggle %W [%W item id {nearest %x %y}] } bind TreeCtrl { TreeCtrl::Leave1 %W %x %y } bind TreeCtrl { TreeCtrl::Enter1 %W %x %y } bind TreeCtrl { TreeCtrl::SetActiveItem %W [TreeCtrl::UpDown %W active -1] } bind TreeCtrl { TreeCtrl::Extend %W above } bind TreeCtrl { TreeCtrl::SetActiveItem %W [TreeCtrl::UpDown %W active 1] } bind TreeCtrl { TreeCtrl::Extend %W below } bind TreeCtrl { if {![TreeCtrl::Has2DLayout %W]} { %W item collapse [%W item id active] } else { TreeCtrl::SetActiveItem %W [TreeCtrl::LeftRight %W active -1] } } bind TreeCtrl { TreeCtrl::Extend %W left } bind TreeCtrl { %W xview scroll -1 pages } bind TreeCtrl { if {![TreeCtrl::Has2DLayout %W]} { %W item expand [%W item id active] } else { TreeCtrl::SetActiveItem %W [TreeCtrl::LeftRight %W active 1] } } bind TreeCtrl { TreeCtrl::Extend %W right } bind TreeCtrl { %W xview scroll 1 pages } bind TreeCtrl { %W yview scroll -1 pages if {[%W item id {nearest 0 0}] ne ""} { %W activate {nearest 0 0} } } bind TreeCtrl { %W yview scroll 1 pages if {[%W item id {nearest 0 0}] ne ""} { %W activate {nearest 0 0} } } bind TreeCtrl { %W xview scroll -1 pages } bind TreeCtrl { %W xview scroll 1 pages } bind TreeCtrl { %W xview moveto 0 } bind TreeCtrl { %W xview moveto 1 } bind TreeCtrl { TreeCtrl::SetActiveItem %W [%W item id {first visible state enabled}] } bind TreeCtrl { TreeCtrl::DataExtend %W [%W item id {first visible state enabled}] } bind TreeCtrl { TreeCtrl::SetActiveItem %W [%W item id {last visible state enabled}] } bind TreeCtrl { TreeCtrl::DataExtend %W [%W item id {last visible state enabled}] } bind TreeCtrl <> { if {[string equal [selection own -displayof %W] "%W"]} { clipboard clear -displayof %W clipboard append -displayof %W [selection get -displayof %W] } } bind TreeCtrl { TreeCtrl::BeginSelect %W [%W item id active] } bind TreeCtrl { TreeCtrl::BeginSelect %W [%W item id active] } bind TreeCtrl { TreeCtrl::BeginExtend %W [%W item id active] } bind TreeCtrl { TreeCtrl::BeginExtend %W [%W item id active] } bind TreeCtrl { TreeCtrl::Cancel %W } bind TreeCtrl { TreeCtrl::SelectAll %W } bind TreeCtrl { if {[string compare [%W cget -selectmode] "browse"]} { %W selection clear } } bind TreeCtrl { %W item expand [%W item id active] } bind TreeCtrl { %W item collapse [%W item id active] } bind TreeCtrl { %W item toggle [%W item id active] } # Additional Tk bindings that aren't part of the Motif look and feel: bind TreeCtrl { focus %W TreeCtrl::ScanMark %W %x %y } bind TreeCtrl { TreeCtrl::ScanDrag %W %x %y } if {$tcl_platform(platform) eq "windows"} { bind TreeCtrl { TreeCtrl::ScanMark %W %x %y } bind TreeCtrl { TreeCtrl::ScanDrag %W %x %y } } if {[string equal [tk windowingsystem] "aqua"]} { # Middle mouse on Mac OSX bind TreeCtrl { TreeCtrl::ScanMark %W %x %y } bind TreeCtrl { TreeCtrl::ScanDrag %W %x %y } } # MouseWheel if {[string equal "x11" [tk windowingsystem]]} { # Support for mousewheels on Linux/Unix commonly comes through mapping # the wheel to the extended buttons. If you have a mousewheel, find # Linux configuration info at: # http://www.inria.fr/koala/colas/mouse-wheel-scroll/ bind TreeCtrl <4> { if {!$tk_strictMotif} { %W yview scroll -5 units } } bind TreeCtrl <5> { if {!$tk_strictMotif} { %W yview scroll 5 units } } } elseif {[string equal [tk windowingsystem] "aqua"]} { bind TreeCtrl { %W yview scroll [expr {- (%D)}] units } } else { bind TreeCtrl { %W yview scroll [expr {- (%D / 120) * 4}] units } } namespace eval ::TreeCtrl { variable Priv array set Priv { prev {} } if {[info procs ::lassign] eq ""} { proc lassign {values args} { uplevel 1 [list foreach $args [linsert $values end {}] break] lrange $values [llength $args] end } } } # Retrieve filelist bindings from this dir source [file join [file dirname [info script]] filelist-bindings.tcl] # ::TreeCtrl::ColumnCanResizeLeft -- # # Return 1 if the given column should be resized by the left edge. # # Arguments: # w The treectrl widget. # column The column. proc ::TreeCtrl::ColumnCanResizeLeft {w column} { if {[$w column cget $column -lock] eq "right"} { return 1 } return 0 } # ::TreeCtrl::ColumnCanMoveHere -- # # Return 1 if the given column can be moved before another. # # Arguments: # w The treectrl widget. # column The column. # before The column to place 'column' before. proc ::TreeCtrl::ColumnCanMoveHere {w column before} { if {[$w column compare $column == $before] || ([$w column order $column] == [$w column order $before] - 1)} { return 0 } set lock [$w column cget $column -lock] return [expr {[$w column compare $before >= "first lock $lock"] && [$w column compare $before <= "last lock $lock next"]}] } # ::TreeCtrl::ColumnDragFindBefore -- # # This is called when dragging a column header. The result is 1 if the given # coordinates are near a column header before which the dragged column can # be moved. # # Arguments: # w The treectrl widget. # x Window x-coord. # y Window y-coord. # dragColumn The column being dragged. # indColumn_ Out: what to set -indicatorcolumn to. # indSide_ Out: what to set -indicatorside to. proc ::TreeCtrl::ColumnDragFindBefore {w x y dragColumn indColumn_ indSide_} { upvar $indColumn_ indColumn upvar $indSide_ indSide set lock [$w column cget $dragColumn -lock] scan [$w bbox header.$lock] "%d %d %d %d" minX y1 maxX y2 if {$x < $minX} { set x $minX } if {$x >= $maxX} { set x [expr {$maxX - 1}] } $w identify -array id $x $y if {$id(where) ne "header"} { return 0 } set indColumn $id(column) if {[$w column compare $indColumn == $dragColumn]} { return 0 } # The given $x is either the left edge or the right edge of the column # header that is being dragged depending on which direction the user # is dragging the column. # When dragging to the left, the indicator column is chosen to be the # leftmost column whose mid-way point is greater than the left edge of the # dragged header. # When dragging to the right, the indicator column is chosen to be the # rightmost column whose mid-way point is less than the right edge of the # dragged header. if {[$w column compare $indColumn != "tail"]} { variable Priv scan [$w header bbox $Priv(header) $indColumn] "%d %d %d %d" x1 y1 x2 y2 # Hack - ignore canvaspadx if {[$w column cget $indColumn -lock] eq "none" && [$w column compare $indColumn == "first visible lock none"]} { incr x1 [lindex [$w cget -canvaspadx] 0] } if {[$w column compare $dragColumn < $indColumn]} { if {$x < $x1 + ($x2 - $x1) / 2} { set indColumn [$w column id "$indColumn prev visible"] set indColumn [GetSpanStartColumn $w $Priv(header) $indColumn] } } else { if {$x > $x1 + ($x2 - $x1) / 2} { # Find the column at the start of the next visible span set starts [GetSpanStarts $w $Priv(header)] for {set i [$w column order $indColumn]} {true} {incr i} { if {[$w column compare [lindex $starts $i] > $indColumn]} break } set indColumn [lindex $starts $i] } } } set before $indColumn set prev [$w column id "$dragColumn prev visible"] set next [$w column id "$dragColumn next visible"] if {[$w column compare $indColumn == "tail"]} { set indSide left set indColumn [$w column id "last lock none visible"] set indSide right } elseif {$prev ne "" && [$w column compare $prev == $indColumn]} { set indSide left } elseif {$next ne "" && [$w column compare $next == $indColumn]} { set before [$w column id "$indColumn next visible"] set indSide right } else { scan [$w column bbox $indColumn] "%d %d %d %d" x1 y1 x2 y2 if {$x < $x1 + ($x2 - $x1) / 2} { set indSide left } else { set before [$w column id "$indColumn next visible"] set indSide right } } if {$before eq "" || [$w column compare $before > "last lock $lock next"]} { set before [$w column id "last lock $lock next"] } return [ColumnCanMoveHere $w $dragColumn $before] } # ::TreeCtrl::ListElementWindows -- # # Return a list of Tk windows in window elements in a column header. # # Arguments: # T The treectrl widget. # H Header id # C Column id proc ::TreeCtrl::ListElementWindows {T H C} { set S [$T header style set $H $C] if {$S eq ""} return set result {} foreach E [$T header style elements $H $C] { if {[$T element type $E] eq "window"} { set window [$T header element cget $H $C $E -window] if {$window ne ""} { lappend result $window } } } return $result } # ::TreeCtrl::ColumnDragRestackWindows -- # # Restack windows in window elements so that windows in dragged headers # are above all other windows in undragged headers. # # Arguments: # T The treectrl widget. proc ::TreeCtrl::ColumnDragRestackWindows {T} { variable Priv set C [$T header dragcget -imagecolumn] set lock [$T column cget $C -lock] set span [$T header dragcget -imagespan] set last [$T column id [list $C span $span]] set dragged [$T column id [list range $C $last]] foreach H [$T header id all] { set prev "" set lowest "" foreach C $dragged { foreach win [ListElementWindows $T $H $C] { if {$prev eq ""} { set lowest $win } else { raise $win $prev } set prev $win } } if {$lowest eq ""} continue foreach C [$T column id "lock $lock !tail"] { if {[lsearch -exact $dragged $C] != -1} continue foreach win [ListElementWindows $T $H $C] { lower $win $lowest } } } return } # ::TreeCtrl::CursorAction -- # # If the given point is at the left or right edge of a resizable column # header, the result is "action header-resize header H column C". # If the given point is in a header with -button=TRUE, the result is # "action header-button header H column C". # # Arguments: # w The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::CursorAction {w x y var_} { upvar $var_ var variable Priv $w identify -array id $x $y set var(action) "" if {$id(where) eq "header"} { set var(header) $id(header) set column $id(column) set side $id(side) if {$side eq ""} { if {[scan [$w bbox header.left] "%d %d %d %d" x1 y1 x2 y2] == 4} { if {$x < $x2 + 4 && $x >= $x2} { set column [$w column id "last visible lock left"] set side right } } if {[scan [$w bbox header.right] "%d %d %d %d" x1 y1 x2 y2] == 4} { if {$x >= $x1 - 4 && $x < $x1} { set column [$w column id "first visible lock right"] set side left } } } if {$side eq "left"} { if {[ColumnCanResizeLeft $w $column]} { if {[$w column cget $column -resize]} { array set var [list action "header-resize" column $column] return } } else { # Resize the previous column if {[$w column compare $column == tail]} { set prev [$w column id "last visible lock none"] if {$prev eq ""} { set prev [$w column id "last visible lock left"] } } else { set prev [$w column id "$column prev visible"] } if {$prev ne "" && [$w column cget $prev -resize]} { array set var [list action "header-resize" column $prev] return } } } elseif {$side eq "right"} { # Get the last visible column in the span set span [$w header span $id(header) $column] set last [$w column id "$column span $span"] set columns [$w column id [list range $column $last visible]] set column2 [lindex $columns end] if {[ColumnCanResizeLeft $w $column2]} { # Resize the next column set next [$w column id "$column2 next visible !tail"] if {$next ne "" && [$w column cget $next -resize]} { array set var [list action "header-resize" column $next] return } } else { if {[$w column cget $column2 -resize]} { array set var [list action "header-resize" column $column2] return } } } if {[$w column compare $column == "tail"]} { # Can't -resize or -button the tail column } elseif {[$w header cget $id(header) $column -button]} { array set var [list action "header-button" column $column] return } } return } # ::TreeCtrl::CursorCheck -- # # Sees if the given pointer coordinates are near the edge of a resizable # column in the header. If so and the treectrl's cursor is not already # set to sb_h_double_arrow, then the current cursor is saved and changed # to sb_h_double_arrow, and an [after] callback to CursorCheckAux is # scheduled. # # Arguments: # w The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::CursorCheck {w x y} { variable Priv CursorAction $w $x $y action # If we are in the middle of resizing a column, don't cancel the cursor if {[info exists Priv(buttonMode)] && $Priv(buttonMode) eq "resize"} { array set action {action "header-resize" header XXX column XXX} } if {$action(action) ne "header-resize"} { CursorCancel $w return } set cursor sb_h_double_arrow if {$cursor ne [$w cget -cursor]} { if {![info exists Priv(cursor,$w)]} { set Priv(cursor,$w) [$w cget -cursor] } $w configure -cursor $cursor } if {[info exists Priv(cursor,afterId,$w)]} { after cancel $Priv(cursor,afterId,$w) } set Priv(cursor,afterId,$w) [after 150 [list TreeCtrl::CursorCheckAux $w]] return } # ::TreeCtrl::CursorCheckAux -- # # Get's the location of the pointer and calls CursorCheck if the treectrl's # cursor was previously set to sb_h_double_arrow. # # Arguments: # w The treectrl widget. proc ::TreeCtrl::CursorCheckAux {w} { variable Priv if {![winfo exists $w]} return set x [winfo pointerx $w] set y [winfo pointery $w] if {[info exists Priv(cursor,$w)]} { set x [expr {$x - [winfo rootx $w]}] set y [expr {$y - [winfo rooty $w]}] CursorCheck $w $x $y } return } # ::TreeCtrl::CursorCancel -- # # Restores the treectrl's cursor if it was changed to sb_h_double_arrow. # Cancels any pending [after] callback to CursorCheckAux. # # Arguments: # w The treectrl widget. proc ::TreeCtrl::CursorCancel {w} { variable Priv if {[info exists Priv(cursor,$w)]} { $w configure -cursor $Priv(cursor,$w) unset Priv(cursor,$w) } if {[info exists Priv(cursor,afterId,$w)]} { after cancel $Priv(cursor,afterId,$w) unset Priv(cursor,afterId,$w) } return } # ::TreeCtrl::GetSpanStarts -- # # This procedure returns a list of column ids, one per tree column. # Each column id indicates the column at the start of a span. # # Arguments: # T The treectrl widget. # H Header id proc ::TreeCtrl::GetSpanStarts {T H} { set columns [list] set spans [$T header span $H] if {[lindex [lsort -integer $spans] end] eq 1} { return [$T column list] } for {set index 0} {$index < [$T column count]} {} { set Cspan [$T column id "order $index"] set span [lindex $spans $index] if {![$T column cget $Cspan -visible]} { set span 1 } while {$span > 0 && $index < [$T column count]} { if {[$T column cget "order $index" -lock] ne [$T column cget $Cspan -lock]} break lappend columns $Cspan incr span -1 incr index } } return $columns } # ::TreeCtrl::GetSpanStartColumn -- # # This procedure returns the column at the start of a span which covers the # given column. # # Arguments: # T The treectrl widget. # H Header id # C Column id proc ::TreeCtrl::GetSpanStartColumn {T H C} { set columns [GetSpanStarts $T $H] return [lindex $columns [$T column order $C]] } # ::TreeCtrl::SetHeaderState -- # # This procedure sets the state of a header-column and remembers that # header-column. If a different header-column is passed later the previous # header-column's state is set to 'normal'. # # Arguments: # T The treectrl widget. # H Header id # C Column id # state active|normal|pressed proc ::TreeCtrl::SetHeaderState {T H C state} { variable Priv if {[info exists Priv(inheader,$T)]} { lassign $Priv(inheader,$T) Hprev Cprev } else { if {$H eq "" || $C eq ""} return set Hprev [set Cprev ""] } if {$H ne $Hprev || $C ne $Cprev} { if {$Hprev ne "" && [$T header id $Hprev] ne ""} { if {$Cprev ne "" && [$T column id $Cprev] ne ""} { $T header configure $Hprev $Cprev -state normal TryEvent $T Header state [list H $Hprev C $Cprev s normal] } } } if {$H eq "" || $C eq ""} { unset Priv(inheader,$T) } else { $T header configure $H $C -state $state TryEvent $T Header state [list H $H C $C s $state] set Priv(inheader,$T) [list $H $C] } return } # ::TreeCtrl::ClearHeaderState -- # # If a header-column's state was previously set via SetHeaderState then # that column's state is set to normal and the header-column is forgotten. # # Arguments: # T The treectrl widget. # H Header id # C Column id # state active|normal|pressed proc ::TreeCtrl::ClearHeaderState {T} { SetHeaderState $T "" "" "" return } # ::TreeCtrl::MotionInHeader -- # # This procedure updates the active/normal states of column headers as the # mouse pointer moves in and out of them. Typically this results in visual # feedback by changing the appearance of the headers. # # Arguments: # w The treectrl widget. # args x y coords if the pointer is in the window, or an empty list. proc ::TreeCtrl::MotionInHeader {w args} { variable Priv if {[llength $args]} { set x [lindex $args 0] set y [lindex $args 1] CursorAction $w $x $y action } else { array set action {action ""} } if {[info exists Priv(inheader,$w)]} { lassign $Priv(inheader,$w) headerPrev columnPrev } else { set headerPrev [set columnPrev ""] } set header "" set column "" if {$action(action) eq "header-button"} { set header $action(header) set column $action(column) } elseif {$action(action) eq "header-resize"} { set header $action(header) set column [GetSpanStartColumn $w $header $action(column)] } if {$header ne $headerPrev || $column ne $columnPrev} { if {$column ne ""} { SetHeaderState $w $header $column active } else { ClearHeaderState $w } } return } # ::TreeCtrl::MotionInButtons -- # # This procedure updates the active/normal states of item buttons. # Typically this results in visual feedback by changing the appearance # of the buttons. # # Arguments: # T The treectrl widget. # args x y coords if the pointer is in the window, or an empty list. proc ::TreeCtrl::MotionInButtons {T args} { variable Priv set button "" if {[llength $args]} { set x [lindex $args 0] set y [lindex $args 1] $T identify -array id $x $y if {$id(where) eq "item" && $id(button)} { set button $id(item) } } if {[info exists Priv(inbutton,$T)]} { set prevButton $Priv(inbutton,$T) } else { set prevButton "" } if {$button ne $prevButton} { if {$prevButton ne ""} { if {[$T item id $prevButton] ne ""} { $T item buttonstate $prevButton normal } } if {$button ne ""} { $T item buttonstate $button active set Priv(inbutton,$T) $button } else { unset Priv(inbutton,$T) } } if {[$T notify bind TreeCtrlButtonNotifyScroll] eq ""} { $T notify bind TreeCtrlButtonNotifyScroll { TreeCtrl::ButtonNotifyScroll %T } } return } # ::TreeCtrl::ButtonNotifyScroll -- # # Called when a event occurs and a button is in the active state. # Finds the mouse pointer coords and calls MotionInButtons to update the # state of affected buttons. # # Arguments: # T The treectrl widget. proc ::TreeCtrl::ButtonNotifyScroll {T} { set x [expr {[winfo pointerx $T] - [winfo rootx $T]}] set y [expr {[winfo pointery $T] - [winfo rooty $T]}] MotionInButtons $T $x $y return } # ::TreeCtrl::ButtonPress1 -- # # Handle event. # # Arguments: # w The treectrl widget. # x Window x coord. # y Window y coord. proc ::TreeCtrl::ButtonPress1 {w x y} { variable Priv focus $w $w identify -array id $x $y if {$id(where) eq ""} { return } if {$id(where) eq "item"} { set item $id(item) if {$id(button)} { if {[$w cget -buttontracking]} { $w item buttonstate $item pressed set Priv(buttonMode) buttonTracking set Priv(buttontrack,item) $item } else { $w item toggle $item -animate } return } elseif {$id(line) ne ""} { $w item toggle $id(line) return } } set Priv(buttonMode) "" if {$id(where) eq "header"} { CursorAction $w $x $y action if {$action(action) eq "header-resize"} { set column $action(column) set Priv(buttonMode) resize set Priv(header) $action(header) set Priv(column) $column set Priv(x) $x set Priv(y) $y set Priv(width) [$w column width $column] return } set column $id(column) if {$action(action) eq "header-button"} { set Priv(buttonMode) header SetHeaderState $w $action(header) $column pressed } else { if {[$w column compare $column == "tail"]} return if {![$w header dragcget -enable]} return if {![$w header dragcget $action(header) -enable]} return set Priv(buttonMode) dragColumnWait } set Priv(header) $action(header) set Priv(column) $column set Priv(columnDrag,x) $x set Priv(columnDrag,y) $y return } set item $id(item) if {![$w item enabled $item]} { return } # If the initial mouse-click is in a locked column, restrict scrolling # to the vertical. set count [scan [$w contentbox] "%d %d %d %d" x1 y1 x2 y2] if {$count != -1 && $x >= $x1 && $x < $x2} { set Priv(autoscan,direction,$w) xy } else { set Priv(autoscan,direction,$w) y } set Priv(buttonMode) normal BeginSelect $w $item return } # ::TreeCtrl::DoubleButtonPress1 -- # # Handle event. # # Arguments: # w The treectrl widget. # x Window x coord. # y Window y coord. proc ::TreeCtrl::DoubleButton1 {w x y} { $w identify -array id $x $y if {$id(where) eq ""} { return } if {$id(where) eq "item"} { if {$id(button)} { if {[$w cget -buttontracking]} { # There is no so just toggle it $w item toggle $id(item) -animate } else { $w item toggle $id(item) -animate } return } elseif {$id(line) ne ""} { $w item toggle $id(line) return } } if {$id(where) eq "header"} { CursorAction $w $x $y action # Double-click between columns to set default column width if {$action(action) eq "header-resize"} { set column $action(column) $w column configure $column -width "" CursorCheck $w $x $y MotionInHeader $w $x $y } else { ButtonPress1 $w $x $y } } return } # ::TreeCtrl::Motion1 -- # # Handle event. # # Arguments: # w The treectrl widget. # x Window x coord. # y Window y coord. proc ::TreeCtrl::Motion1 {w x y} { variable Priv if {![info exists Priv(buttonMode)]} return switch $Priv(buttonMode) { header { $w identify -array id $x $y if {$id(where) ne "header" || $id(header) ne $Priv(header) || $id(column) ne $Priv(column)} { if {[$w header cget $Priv(header) $Priv(column) -state] eq "pressed"} { ClearHeaderState $w } } else { if {[$w header cget $Priv(header) $Priv(column) -state] ne "pressed"} { SetHeaderState $w $Priv(header) $Priv(column) pressed } if {[$w header dragcget -enable] && [$w header dragcget $Priv(header) -enable] && (abs($Priv(columnDrag,x) - $x) > 4)} { set Priv(columnDrag,x) $x $w header dragconfigure \ -imagecolumn $Priv(column) \ -imageoffset [expr {$x - $Priv(columnDrag,x)}] \ -imagespan [$w header span $Priv(header) $Priv(column)] ColumnDragRestackWindows $w set Priv(buttonMode) dragColumn TryEvent $w ColumnDrag begin [list H $Priv(header) C $Priv(column)] # Allow binding scripts to cancel the drag if {[$w header dragcget -imagecolumn] eq ""} { set Priv(buttonMode) header } } } } buttonTracking { $w identify -array id $x $y set itemTrack $Priv(buttontrack,item) set exists [expr {[$w item id $itemTrack] ne ""}] set mouseover 0 if {$id(where) eq "item" && $id(button)} { if {$exists && [$w item compare $itemTrack == $id(item)]} { set mouseover 1 } } if {$mouseover} { $w item buttonstate $itemTrack pressed } elseif {$exists} { $w item buttonstate $itemTrack normal } } dragColumnWait { if {(abs($Priv(columnDrag,x) - $x) > 4)} { set Priv(columnDrag,x) $x $w header dragconfigure \ -imagecolumn $Priv(column) \ -imageoffset [expr {$x - $Priv(columnDrag,x)}] \ -imagespan [$w header span $Priv(header) $Priv(column)] ColumnDragRestackWindows $w set Priv(buttonMode) dragColumn TryEvent $w ColumnDrag begin [list H $Priv(header) C $Priv(column)] # Allow binding scripts to cancel the drag if {[$w header dragcget -imagecolumn] eq ""} { unset Priv(buttonMode) } } } dragColumn { scan [$w bbox header] "%d %d %d %d" x1 y1 x2 y2 if {$y < $y1 - 30 || $y >= $y2 + 30} { set inside 0 } else { set inside 1 } if {$inside && ([$w header dragcget -imagecolumn] eq "")} { $w header dragconfigure -imagecolumn $Priv(column) } elseif {!$inside && ([$w header dragcget -imagecolumn] ne "")} { $w header dragconfigure -imagecolumn "" -indicatorcolumn "" } if {$inside} { set offset [expr {$x - $Priv(columnDrag,x)}] $w header dragconfigure -imageoffset $offset # When dragging to the left, use the left edge of the dragged # header to choose the -indicatorcolumn. When dragging to the # right, use the right edge. scan [$w header bbox $Priv(header) $Priv(column)] "%d %d %d %d" x1 y1 x2 y2 if {$offset > 0} { set xEdge [expr {$offset + $x2}] } else { set xEdge [expr {$offset + $x1}] } if {[ColumnDragFindBefore $w $xEdge $Priv(columnDrag,y) $Priv(column) indColumn indSide]} { set prevIndColumn [$w header dragcget -indicatorcolumn] $w header dragconfigure \ -indicatorcolumn $indColumn \ -indicatorside $indSide \ -indicatorspan [$w header span $Priv(header) $indColumn] if {$indColumn != $prevIndColumn} { TryEvent $w ColumnDrag indicator [list H $Priv(header) C $indColumn] } } else { $w header dragconfigure -indicatorcolumn "" } } if {[$w column cget $Priv(column) -lock] eq "none"} { ColumnDragScrollCheck $w $x $y } } normal { set Priv(x) $x set Priv(y) $y SelectionMotion $w [$w item id [list nearest $x $y]] set Priv(autoscan,command,$w) {SelectionMotion %T [%T item id "nearest %x %y"]} AutoScanCheck $w $x $y } resize { if {[ColumnCanResizeLeft $w $Priv(column)]} { set width [expr {$Priv(width) + $Priv(x) - $x}] } else { set width [expr {$Priv(width) + $x - $Priv(x)}] } set minWidth [$w column cget $Priv(column) -minwidth] set maxWidth [$w column cget $Priv(column) -maxwidth] if {$minWidth eq ""} { set minWidth 0 } if {$width < $minWidth} { set width $minWidth } if {($maxWidth ne "") && ($width > $maxWidth)} { set width $maxWidth } if {$width == 0} { incr width } switch -- [$w cget -columnresizemode] { proxy { scan [$w column bbox $Priv(column)] "%d %d %d %d" x1 y1 x2 y2 if {[ColumnCanResizeLeft $w $Priv(column)]} { # Use "ne" because -columnproxy could be "" if {$x2 - $width ne [$w cget -columnproxy]} { $w configure -columnproxy [expr {$x2 - $width}] } } else { if {($x1 + $width - 1) ne [$w cget -columnproxy]} { $w configure -columnproxy [expr {$x1 + $width - 1}] } } } realtime { if {[$w column cget $Priv(column) -width] != $width} { $w column configure $Priv(column) -width $width } } } } } return } # ::TreeCtrl::Leave1 -- # # Handle event. # # Arguments: # w The treectrl widget. # x Window x coord. # y Window y coord. proc ::TreeCtrl::Leave1 {w x y} { variable Priv if {![info exists Priv(buttonMode)]} return switch $Priv(buttonMode) { header { if {[$w header cget $Priv(header) $Priv(column) -state] eq "pressed"} { ClearHeaderState $w } } } return } # ::TreeCtrl::Enter1 -- # # Handle event. # # Arguments: # w The treectrl widget. # x Window x coord. # y Window y coord. proc ::TreeCtrl::Enter1 {w x y} { variable Priv if {![info exists Priv(buttonMode)]} return switch $Priv(buttonMode) { default {} } return } # ::TreeCtrl::Release1 -- # # Handle event. # # Arguments: # w The treectrl widget. # x Window x coord. # y Window y coord. proc ::TreeCtrl::Release1 {w x y} { variable Priv if {![info exists Priv(buttonMode)]} return switch $Priv(buttonMode) { header { if {[$w header cget $Priv(header) $Priv(column) -state] eq "pressed"} { SetHeaderState $w $Priv(header) $Priv(column) active TryEvent $w Header invoke [list H $Priv(header) C $Priv(column)] } CursorCheck $w $x $y MotionInHeader $w $x $y } buttonTracking { $w identify -array id $x $y set itemTrack $Priv(buttontrack,item) set exists [expr {[$w item id $itemTrack] ne ""}] if {$id(where) eq "item" && $id(button)} { if {$exists && [$w item compare $itemTrack == $id(item)]} { $w item buttonstate $id(item) active $w item toggle $itemTrack -animate } } } dragColumn { AutoScanCancel $w ClearHeaderState $w if {[$w header dragcget -imagecolumn] ne ""} { set visible 1 } else { set visible 0 } set column [$w header dragcget -indicatorcolumn] $w header dragconfigure -imagecolumn "" -indicatorcolumn "" if {$visible && ($column ne "")} { # If dragging to the right, drop after the last column in the # span of the indicator column. if {[$w column order $Priv(column)] < [$w column order $column]} { set span [$w header dragcget -indicatorspan] set column [$w column id "$column span $span next"] } set lock [$w column cget $Priv(column) -lock] if {$column eq "" || [$w column compare $column > "last lock $lock next"]} { set column [$w column id "last lock $lock next"] } TryEvent $w ColumnDrag receive [list H $Priv(header) C $Priv(column) b $column] } CursorCheck $w $x $y MotionInHeader $w $x $y TryEvent $w ColumnDrag end [list H $Priv(header) C $Priv(column)] } normal { AutoScanCancel $w set nearest [$w item id [list nearest $x $y]] if {$nearest ne ""} { $w activate $nearest } set Priv(prev) "" } resize { if {[$w cget -columnproxy] ne ""} { scan [$w column bbox $Priv(column)] "%d %d %d %d" x1 y1 x2 y2 if {[ColumnCanResizeLeft $w $Priv(column)]} { set width [expr {$x2 - [$w cget -columnproxy]}] } else { set width [expr {[$w cget -columnproxy] - $x1 + 1}] } $w configure -columnproxy {} $w column configure $Priv(column) -width $width } # Clear buttonMode early so CursorCheck doesn't exit unset Priv(buttonMode) CursorCheck $w $x $y MotionInHeader $w $x $y return } } unset Priv(buttonMode) return } # ::TreeCtrl::BeginSelect -- # # This procedure is typically invoked on button-1 presses. It begins # the process of making a selection in the treectrl. Its exact behavior # depends on the selection mode currently in effect for the treectrl. # # Arguments: # w The treectrl widget. # item The item for the selection operation (typically the # one under the pointer). proc ::TreeCtrl::BeginSelect {w item} { variable Priv if {$item eq ""} return if {[string equal [$w cget -selectmode] "multiple"]} { if {[$w selection includes $item]} { $w selection clear $item } else { $w selection add $item } } else { $w selection anchor $item $w selection modify $item all set Priv(selection) {} set Priv(prev) $item } return } # ::TreeCtrl::SelectionMotion -- # # This procedure is called to process mouse motion events while # button 1 is down. It may move or extend the selection, depending # on the treectrl's selection mode. # # Arguments: # w The treectrl widget. # item- The item under the pointer. proc ::TreeCtrl::SelectionMotion {w item} { variable Priv if {$item eq ""} return set item [$w item id $item] if {$item eq $Priv(prev)} return if {![$w item enabled $item]} return switch [$w cget -selectmode] { browse { $w selection modify $item all set Priv(prev) $item } extended { set i $Priv(prev) set select {} set deselect {} if {$i eq ""} { set i $item lappend select $item set hack [$w item compare $item == anchor] } else { set hack 0 } if {[$w selection includes anchor] || $hack} { set deselect [concat $deselect [$w item range $i $item]] set select [concat $select [$w item range anchor $item]] } else { set deselect [concat $deselect [$w item range $i $item]] set deselect [concat $deselect [$w item range anchor $item]] } if {![info exists Priv(selection)]} { set Priv(selection) [$w selection get] } while {[$w item compare $i < $item] && [$w item compare $i < anchor]} { if {[lsearch $Priv(selection) $i] >= 0} { lappend select $i } set i [$w item id "$i next visible"] } while {[$w item compare $i > $item] && [$w item compare $i > anchor]} { if {[lsearch $Priv(selection) $i] >= 0} { lappend select $i } set i [$w item id "$i prev visible"] } set Priv(prev) $item $w selection modify $select $deselect } } return } # ::TreeCtrl::BeginExtend -- # # This procedure is typically invoked on shift-button-1 presses. It # begins the process of extending a selection in the treectrl. Its # exact behavior depends on the selection mode currently in effect # for the treectrl. # # Arguments: # w The treectrl widget. # item- The item for the selection operation (typically the # one under the pointer). proc ::TreeCtrl::BeginExtend {w item} { if {[string equal [$w cget -selectmode] "extended"]} { if {[$w selection includes anchor]} { SelectionMotion $w $item } else { # No selection yet; simulate the begin-select operation. BeginSelect $w $item } } return } # ::TreeCtrl::BeginToggle -- # # This procedure is typically invoked on control-button-1 presses. It # begins the process of toggling a selection in the treectrl. Its # exact behavior depends on the selection mode currently in effect # for the treectrl. # # Arguments: # w The treectrl widget. # item The item for the selection operation (typically the # one under the pointer). proc ::TreeCtrl::BeginToggle {w item} { variable Priv if {$item eq ""} return if {[string equal [$w cget -selectmode] "extended"]} { set Priv(selection) [$w selection get] set Priv(prev) $item $w selection anchor $item if {[$w selection includes $item]} { $w selection clear $item } else { $w selection add $item } } return } # ::TreeCtrl::AutoScanCheck -- # # Sees if the given pointer coords are outside the content area of the # treectrl (ie, not including borders or column headers) or within # -scrollmargin distance of the edges of the content area. If so and # auto-scanning is not already in progress, then the window is scrolled # and an [after] callback to AutoScanCheckAux is scheduled. # # Arguments: # w The treectrl widget. # x Window x coord. # y Window y coord. proc ::TreeCtrl::AutoScanCheck {w x y} { variable Priv # Could have clicked in locked column if {[scan [$w contentbox] "%d %d %d %d" x1 y1 x2 y2] == -1} { if {[scan [$w bbox left] "%d %d %d %d" x1 y1 x2 y2] == -1} { scan [$w bbox right] "%d %d %d %d" x1 y1 x2 y2 } } set margin [winfo pixels $w [$w cget -scrollmargin]] if {![info exists Priv(autoscan,direction,$w)]} { set Priv(autoscan,direction,$w) xy } set scrollX [string match *x* $Priv(autoscan,direction,$w)] set scrollY [string match *y* $Priv(autoscan,direction,$w)] if {($scrollX && (($x < $x1 + $margin) || ($x >= $x2 - $margin))) || ($scrollY && (($y < $y1 + $margin) || ($y >= $y2 - $margin)))} { if {[info exists Priv(autoscan,afterId,$w)]} return if {$scrollY && $y >= $y2 - $margin} { $w yview scroll 1 units set delay [$w cget -yscrolldelay] } elseif {$scrollY && $y < $y1 + $margin} { $w yview scroll -1 units set delay [$w cget -yscrolldelay] } elseif {$scrollX && $x >= $x2 - $margin} { $w xview scroll 1 units set delay [$w cget -xscrolldelay] } elseif {$scrollX && $x < $x1 + $margin} { $w xview scroll -1 units set delay [$w cget -xscrolldelay] } set count [scan $delay "%d %d" d1 d2] if {[info exists Priv(autoscan,scanning,$w)]} { if {$count == 2} { set delay $d2 } } else { if {$count == 2} { set delay $d1 } set Priv(autoscan,scanning,$w) 1 } if {$Priv(autoscan,command,$w) ne ""} { set command [string map [list %T $w %x $x %y $y] $Priv(autoscan,command,$w)] eval $command } set Priv(autoscan,afterId,$w) [after $delay [list TreeCtrl::AutoScanCheckAux $w]] return } AutoScanCancel $w return } # ::TreeCtrl::AutoScanCheckAux -- # # Gets the location of the pointer and calls AutoScanCheck. # # Arguments: # w The treectrl widget. proc ::TreeCtrl::AutoScanCheckAux {w} { variable Priv if {![winfo exists $w]} return # Not quite sure how this can happen if {![info exists Priv(autoscan,afterId,$w)]} return unset Priv(autoscan,afterId,$w) set x [winfo pointerx $w] set y [winfo pointery $w] set x [expr {$x - [winfo rootx $w]}] set y [expr {$y - [winfo rooty $w]}] AutoScanCheck $w $x $y return } # ::TreeCtrl::AutoScanCancel -- # # Cancels any pending [after] callback to AutoScanCheckAux. # # Arguments: # w The treectrl widget. proc ::TreeCtrl::AutoScanCancel {w} { variable Priv if {[info exists Priv(autoscan,afterId,$w)]} { after cancel $Priv(autoscan,afterId,$w) unset Priv(autoscan,afterId,$w) } unset -nocomplain Priv(autoscan,scanning,$w) return } # ::TreeCtrl::ColumnDragScrollCheck -- # # Sees if the given pointer coords are outside the left or right edges of # the content area of the treectrl (ie, not including borders). If so and # auto-scanning is not already in progress, then the window is scrolled # horizontally and the column drag-image is repositioned, and an [after] # callback to ColumnDragScrollCheckAux is scheduled. # # Arguments: # w The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::ColumnDragScrollCheck {w x y} { variable Priv # When dragging to the left, use the left edge of the dragged # header to choose the -indicatorcolumn. When dragging to the # right, use the right edge. scan [$w header bbox $Priv(header) $Priv(column)] "%d %d %d %d" x1 y1 x2 y2 set offset [$w header dragcget -imageoffset] if {$offset > 0} { set xEdge [expr {$offset + $x2}] } else { set xEdge [expr {$offset + $x1}] } scan [$w bbox header.none] "%d %d %d %d" x1 y1 x2 y2 if {($x < $x1) || ($x >= $x2)} { if {![info exists Priv(autoscan,afterId,$w)]} { set bbox1 [$w column bbox $Priv(column)] if {$xEdge >= $x2} { $w xview scroll 1 units } else { $w xview scroll -1 units } set bbox2 [$w column bbox $Priv(column)] if {[lindex $bbox1 0] != [lindex $bbox2 0]} { incr Priv(columnDrag,x) [expr {[lindex $bbox2 0] - [lindex $bbox1 0]}] $w header dragconfigure -imageoffset [expr {$x - $Priv(columnDrag,x)}] if {[ColumnDragFindBefore $w $xEdge $Priv(columnDrag,y) $Priv(column) indColumn indSide]} { $w header dragconfigure -indicatorcolumn $indColumn \ -indicatorside $indSide } else { $w header dragconfigure -indicatorcolumn "" } } set Priv(autoscan,afterId,$w) [after 50 [list TreeCtrl::ColumnDragScrollCheckAux $w]] } return } AutoScanCancel $w return } # ::TreeCtrl::ColumnDragScrollCheckAux -- # # Gets the location of the pointer and calls ColumnDragScrollCheck. # # Arguments: # w The treectrl widget. proc ::TreeCtrl::ColumnDragScrollCheckAux {w} { variable Priv if {![winfo exists $w]} return # Not quite sure how this can happen if {![info exists Priv(autoscan,afterId,$w)]} return unset Priv(autoscan,afterId,$w) set x [winfo pointerx $w] set y [winfo pointery $w] set x [expr {$x - [winfo rootx $w]}] set y [expr {$y - [winfo rooty $w]}] ColumnDragScrollCheck $w $x $y return } # ::TreeCtrl::Has2DLayout -- # # Determine if items are displayed in a 2-dimensional arrangement. # This is used by the and bindings. # # Arguments: # w The treectrl widget. proc ::TreeCtrl::Has2DLayout {T} { if {[$T cget -orient] ne "vertical" || [$T cget -wrap] ne ""} { return 1 } set item [$T item id "last visible"] if {$item ne ""} { lassign [$T item rnc $item] row column if {$column > 0} { return 1 } } return 0 } # ::TreeCtrl::UpDown -- # # Returns the id of an item above or below the given item that the active # item could be set to. If the given item isn't visible, the first visible # enabled item is returned. An attempt is made to choose an item in the # same column over repeat calls; this gives a better result if some rows # have less items than others. Only enabled items are considered. # # Arguments: # w The treectrl widget. # item Item to move from, typically the active item. # n +1 to move down, -1 to move up. proc ::TreeCtrl::UpDown {w item n} { variable Priv set rnc [$w item rnc $item] if {$rnc eq ""} { return [$w item id {first visible state enabled}] } scan $rnc "%d %d" row col set Priv(keyNav,row,$w) [expr {$row + $n}] if {![info exists Priv(keyNav,rnc,$w)] || $rnc ne $Priv(keyNav,rnc,$w)} { set Priv(keyNav,col,$w) $col } set item2 [$w item id "rnc $Priv(keyNav,row,$w) $Priv(keyNav,col,$w)"] if {[$w item compare $item == $item2]} { set Priv(keyNav,row,$w) $row if {![$w item enabled $item2]} { return "" } } else { set Priv(keyNav,rnc,$w) [$w item rnc $item2] if {![$w item enabled $item2]} { return [UpDown $w $item2 $n] } } return $item2 } # ::TreeCtrl::LeftRight -- # # Returns the id of an item left or right of the given item that the active # item could be set to. If the given item isn't visible, the first visible # enabled item is returned. An attempt is made to choose an item in the # same row over repeat calls; this gives a better result if some columns # have less items than others. Only enabled items are considered. # # Arguments: # w The treectrl widget. # item Item to move from, typically the active item. # n +1 to move right, -1 to move left. proc ::TreeCtrl::LeftRight {w item n} { variable Priv set rnc [$w item rnc $item] if {$rnc eq ""} { return [$w item id {first visible state enabled}] } scan $rnc "%d %d" row col set Priv(keyNav,col,$w) [expr {$col + $n}] if {![info exists Priv(keyNav,rnc,$w)] || $rnc ne $Priv(keyNav,rnc,$w)} { set Priv(keyNav,row,$w) $row } set item2 [$w item id "rnc $Priv(keyNav,row,$w) $Priv(keyNav,col,$w)"] if {[$w item compare $item == $item2]} { set Priv(keyNav,col,$w) $col if {![$w item enabled $item2]} { return "" } } else { set Priv(keyNav,rnc,$w) [$w item rnc $item2] if {![$w item enabled $item2]} { return [LeftRight $w $item2 $n] } } return $item2 } # ::TreeCtrl::SetActiveItem -- # # Sets the active item, scrolls it into view, and makes it the only selected # item. If -selectmode is extended, makes the active item the anchor of any # future extended selection. # # Arguments: # w The treectrl widget. # item The new active item, or "". proc ::TreeCtrl::SetActiveItem {w item} { if {$item eq ""} return $w activate $item $w see active $w selection modify active all switch [$w cget -selectmode] { extended { $w selection anchor active set Priv(prev) [$w item id active] set Priv(selection) {} } } return } # ::TreeCtrl::Extend -- # # Does nothing unless we're in extended selection mode; in this # case it moves the location cursor (active item) up, down, left or # right, and extends the selection to that point. # # Arguments: # w The treectrl widget. # dir up, down, left or right proc ::TreeCtrl::Extend {w dir} { variable Priv if {[string compare [$w cget -selectmode] "extended"]} { return } if {![info exists Priv(selection)]} { $w selection add active set Priv(selection) [$w selection get] } switch -- $dir { above { set item [UpDown $w active -1] } below { set item [UpDown $w active 1] } left { set item [LeftRight $w active -1] } right { set item [LeftRight $w active 1] } } if {$item eq ""} return $w activate $item $w see active SelectionMotion $w [$w item id active] return } # ::TreeCtrl::DataExtend # # This procedure is called for key-presses such as Shift-KEndData. # If the selection mode isn't multiple or extended then it does nothing. # Otherwise it moves the active item and, if we're in # extended mode, extends the selection to that point. # # Arguments: # w The treectrl widget. # item Item to become new active item. proc ::TreeCtrl::DataExtend {w item} { if {$item eq ""} return set mode [$w cget -selectmode] if {[string equal $mode "extended"]} { $w activate $item $w see $item if {[$w selection includes anchor]} { SelectionMotion $w $item } } elseif {[string equal $mode "multiple"]} { $w activate $item $w see $item } return } # ::TreeCtrl::Cancel # # This procedure is invoked to cancel an extended selection in # progress. If there is an extended selection in progress, it # restores all of the items between the active one and the anchor # to their previous selection state. # # Arguments: # w The treectrl widget. proc ::TreeCtrl::Cancel w { variable Priv if {[string compare [$w cget -selectmode] "extended"]} { return } set first [$w item id anchor] set last $Priv(prev) if { [string equal $last ""] } { # Not actually doing any selection right now return } if {[$w item compare $first > $last]} { set tmp $first set first $last set last $tmp } set select {} set deselect {} foreach item [$w item id "range $first $last visible"] { if {[lsearch $Priv(selection) $item] == -1} { lappend deselect $item } else { lappend select $item } } $w selection modify $select $deselect return } # ::TreeCtrl::SelectAll # # This procedure is invoked to handle the "select all" operation. # For single and browse mode, it just selects the active item. # Otherwise it selects everything in the widget. # # Arguments: # w The treectrl widget. proc ::TreeCtrl::SelectAll w { set mode [$w cget -selectmode] if {[string equal $mode "single"] || [string equal $mode "browse"]} { $w selection modify active all } else { $w selection add all } return } # ::TreeCtrl::MarqueeBegin -- # # Shows the selection rectangle at the given coords. # # Arguments: # w The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::MarqueeBegin {w x y} { set x [$w canvasx $x] set y [$w canvasy $y] $w marquee coords $x $y $x $y $w marquee configure -visible yes return } # ::TreeCtrl::MarqueeUpdate -- # # Resizes the selection rectangle. # # Arguments: # w The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::MarqueeUpdate {w x y} { set x [$w canvasx $x] set y [$w canvasy $y] $w marquee corner $x $y return } # ::TreeCtrl::MarqueeEnd -- # # Hides the selection rectangle. # # Arguments: # w The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::MarqueeEnd {w x y} { $w marquee configure -visible no return } # ::TreeCtrl::ScanMark -- # # Marks the start of a possible scan drag operation. # # Arguments: # w The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::ScanMark {w x y} { variable Priv $w scan mark $x $y set Priv(x) $x set Priv(y) $y set Priv(mouseMoved) 0 return } # ::TreeCtrl::ScanDrag -- # # Performs a scan drag if the mouse moved. # # Arguments: # w The treectrl widget. # x Window coord of pointer. # y Window coord of pointer. proc ::TreeCtrl::ScanDrag {w x y} { variable Priv if {![info exists Priv(x)]} { set Priv(x) $x } if {![info exists Priv(y)]} { set Priv(y) $y } if {($x != $Priv(x)) || ($y != $Priv(y))} { set Priv(mouseMoved) 1 } if {[info exists Priv(mouseMoved)] && $Priv(mouseMoved)} { $w scan dragto $x $y } return } # ::TreeCtrl::TryEvent -- # # This procedure is used to cause a treectrl to generate a dynamic event. # If the treectrl doesn't have the event defined (because you didn't call # the [notify install] command) nothing happens. TreeCtrl::PercentsCmd is # used to perform %-substitution on any scripts bound to the event. # # Arguments: # T The treectrl widget. # event Name of event. # detail Name of detail or "". # charMap %-char substitution list (even number of elements). proc ::TreeCtrl::TryEvent {T event detail charMap} { if {[lsearch -exact [$T notify eventnames] $event] == -1} return if {$detail ne ""} { if {[lsearch -exact [$T notify detailnames $event] $detail] == -1} return $T notify generate <$event-$detail> $charMap "::TreeCtrl::PercentsCmd $T" } else { $T notify generate <$event> $charMap "::TreeCtrl::PercentsCmd $T" } return } # ::TreeCtrl::PercentsCmd -- # # This command is passed to [notify generate] to perform %-substitution on # scripts bound to dynamic events. It supports the same set of substitution # characters as the built-in static events (plus any event-specific chars). # # Arguments: # T The treectrl widget. # char %-char to be replaced in bound scripts. # object Same arg passed to [notify bind]. # event Name of event. # detail Name of detail or "". # charMap %-char substitution list (even number of elements). proc ::TreeCtrl::PercentsCmd {T char object event detail charMap} { if {$detail ne ""} { set pattern <$event-$detail> } else { set pattern <$event> } switch -- $char { d { return $detail } e { return $event } P { return $pattern } W { return $object } T { return $T } ? { array set map $charMap array set map [list T $T W $object P $pattern e $event d $detail] return [array get map] } default { array set map [list $char $char] array set map $charMap return $map($char) } } return } namespace eval TreeCtrl { catch { foreach theme [ttk::style theme names] { ttk::style theme settings $theme { ttk::style configure TreeCtrlHeading -relief raised -font TkHeadingFont ttk::style map TreeCtrlHeading -relief { pressed sunken } } } } } tktreectrl-2.4.1/license.terms0000644000076400010400000000414710233773574016732 0ustar TimAdministratorsThis software is copyrighted by Tim Baker and other parties. The following terms apply to all files associated with the software unless explicitly disclaimed in individual files. The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. tktreectrl-2.4.1/macosx/0000755000076400010400000000000011646706171015516 5ustar TimAdministratorstktreectrl-2.4.1/macosx/tkMacOSXTree.c0000644000076400010400000021730211565554043020137 0ustar TimAdministrators/* * tkMacOSXTree.c -- * * Platform-specific parts of TkTreeCtrl for Mac OSX (Cocoa API). * * Copyright (c) 2010-2011 Tim Baker */ #include "tkTreeCtrl.h" #include "tkMacOSXInt.h" #import #ifdef MAC_TK_COCOA #import #endif /* CGFloat is available Mac OS X v10.5 and later. */ #ifndef CGFLOAT_DEFINED # if __LP64__ # define CGFloat double # else # define CGFloat float # endif #endif #define radians(d) ((d) * (M_PI/180.0)) #if MAC_TK_COCOA /*(TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION >= 6)*/ typedef struct { CGContextRef context; } MacContextSetup; #endif /* Tk 8.6 */ #if MAC_TK_CARBON /*(TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 6)*/ typedef struct { CGrafPtr port, savePort; Boolean portChanged; CGContextRef context; } MacContextSetup; #endif /* Tk 8.4 + 8.5 */ MODULE_SCOPE CGContextRef TreeMacOSX_GetContext(TreeCtrl *tree, Drawable pixmap, TreeRectangle tr, MacContextSetup *dc); MODULE_SCOPE void TreeMacOSX_ReleaseContext(TreeCtrl *tree, MacContextSetup *dc); #define BlueFloatFromXPixel(pixel) (float) (((pixel >> 0) & 0xFF)) / 255.0 #define GreenFloatFromXPixel(pixel) (float) (((pixel >> 8) & 0xFF)) / 255.0 #define RedFloatFromXPixel(pixel) (float) (((pixel >> 16) & 0xFF)) / 255.0 /* *---------------------------------------------------------------------- * * Tree_HDotLine -- * * Draws a horizontal 1-pixel-tall dotted line. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_HDotLine( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ int x1, int y1, int x2 /* Left, top and right coordinates. */ ) { int nw; int wx = x1 + tree->drawableXOrigin; int wy = y1 + tree->drawableYOrigin; #if 1 MacDrawable *macDraw = (MacDrawable *) drawable; TreeRectangle tr; MacContextSetup dc; CGContextRef context; CGFloat lengths[1] = {1.0f}; if (!(macDraw->flags & TK_IS_PIXMAP)) { return; } tr.x = x1, tr.y = y1, tr.width = x2-x1, tr.height = 1; context = TreeMacOSX_GetContext(tree, drawable, tr, &dc); if (context == NULL) { return; } CGContextBeginPath(context); CGContextMoveToPoint(context, x1 /*+ 0.5*/, y1 + 0.5); CGContextAddLineToPoint(context, x2 /*- 0.5*/, y1 + 0.5); CGContextSetRGBStrokeColor(context, RedFloatFromXPixel(tree->lineGC[0]->foreground), GreenFloatFromXPixel(tree->lineGC[0]->foreground), BlueFloatFromXPixel(tree->lineGC[0]->foreground), 1.0); CGContextSetLineWidth(context, 0.01); nw = !(wx & 1) == !(wy & 1); CGContextSetLineDash(context, nw ? 0 : 1, lengths, 1); CGContextSetShouldAntialias(context, 0); CGContextStrokePath(context); TreeMacOSX_ReleaseContext(tree, &dc); #else nw = !(wx & 1) == !(wy & 1); for (x1 += !nw; x1 < x2; x1 += 2) { XDrawPoint(tree->display, drawable, gc, x1, y1); } #endif } /* *---------------------------------------------------------------------- * * Tree_VDotLine -- * * Draws a vertical 1-pixel-wide dotted line. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_VDotLine( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ int x1, int y1, int y2) /* Left, top, and bottom coordinates. */ { int nw; int wx = x1 + tree->drawableXOrigin; int wy = y1 + tree->drawableYOrigin; #if 1 MacDrawable *macDraw = (MacDrawable *) drawable; TreeRectangle tr; MacContextSetup dc; CGContextRef context; CGFloat lengths[1] = {1.0f}; if (!(macDraw->flags & TK_IS_PIXMAP)) { return; } tr.x = x1, tr.y = y1, tr.width = x1, tr.height = y2-y1; context = TreeMacOSX_GetContext(tree, drawable, tr, &dc); if (context == NULL) { return; } CGContextBeginPath(context); CGContextMoveToPoint(context, x1 + 0.5, y1 /*+ 0.5*/); CGContextAddLineToPoint(context, x1 + 0.5, y2 - 0.5); CGContextSetRGBStrokeColor(context, RedFloatFromXPixel(tree->lineGC[0]->foreground), GreenFloatFromXPixel(tree->lineGC[0]->foreground), BlueFloatFromXPixel(tree->lineGC[0]->foreground), 1.0); CGContextSetLineWidth(context, 0.01); nw = !(wx & 1) == !(wy & 1); CGContextSetLineDash(context, nw ? 0 : 1, lengths, 1); CGContextSetShouldAntialias(context, 0); CGContextStrokePath(context); TreeMacOSX_ReleaseContext(tree, &dc); #else nw = !(wx & 1) == !(wy & 1); for (y1 += !nw; y1 < y2; y1 += 2) { XDrawPoint(tree->display, drawable, gc, x1, y1); } #endif } /* *---------------------------------------------------------------------- * * Tree_DrawActiveOutline -- * * Draws 0 or more sides of a rectangle, dot-on dot-off, XOR style. * This is used by rectangle Elements to indicate the "active" * item. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_DrawActiveOutline( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ int x, int y, /* Left and top coordinates. */ int width, int height, /* Size of rectangle. */ int open /* RECT_OPEN_x flags */ ) { #if 1 int w = !(open & RECT_OPEN_W); int n = !(open & RECT_OPEN_N); int e = !(open & RECT_OPEN_E); int s = !(open & RECT_OPEN_S); XGCValues gcValues; unsigned long gcMask; GC gc; gcValues.function = GXcopy; gcMask = GCFunction; gc = Tree_GetGC(tree, gcMask, &gcValues); if (w) /* left */ { Tree_VDotLine(tree, drawable, x, y, y + height); } if (n) /* top */ { Tree_HDotLine(tree, drawable, x, y, x + width); } if (e) /* right */ { Tree_VDotLine(tree, drawable, x + width - 1, y, y + height); } if (s) /* bottom */ { Tree_HDotLine(tree, drawable, x, y + height - 1, x + width); } #else int wx = x + tree->drawableXOrigin; int wy = y + tree->drawableYOrigin; int w = !(open & RECT_OPEN_W); int n = !(open & RECT_OPEN_N); int e = !(open & RECT_OPEN_E); int s = !(open & RECT_OPEN_S); int nw, ne, sw, se; int i; XGCValues gcValues; unsigned long gcMask; GC gc; /* Dots on even pixels only */ nw = !(wx & 1) == !(wy & 1); ne = !((wx + width - 1) & 1) == !(wy & 1); sw = !(wx & 1) == !((wy + height - 1) & 1); se = !((wx + width - 1) & 1) == !((wy + height - 1) & 1); gcValues.function = GXcopy; gcMask = GCFunction; gc = Tree_GetGC(tree, gcMask, &gcValues); if (w) /* left */ { for (i = !nw; i < height; i += 2) { XDrawPoint(tree->display, drawable, gc, x, y + i); } } if (n) /* top */ { for (i = nw ? w * 2 : 1; i < width; i += 2) { XDrawPoint(tree->display, drawable, gc, x + i, y); } } if (e) /* right */ { for (i = ne ? n * 2 : 1; i < height; i += 2) { XDrawPoint(tree->display, drawable, gc, x + width - 1, y + i); } } if (s) /* bottom */ { for (i = sw ? w * 2 : 1; i < width - (se && e); i += 2) { XDrawPoint(tree->display, drawable, gc, x + i, y + height - 1); } } #endif } /* * The following structure is used when drawing a number of dotted XOR * rectangles. */ struct DotStatePriv { TreeCtrl *tree; #if 1 MacContextSetup dc; CGContextRef context; #else Drawable drawable; GC gc; TkRegion rgn; #endif }; /* *---------------------------------------------------------------------- * * TreeDotRect_Setup -- * * Prepare a drawable for drawing a series of dotted XOR rectangles. * * Results: * State info is returned to be used by the other TreeDotRect_xxx() * procedures. * * Side effects: * On Win32 and OSX the device context/graphics port is altered * in preparation for drawing. On X11 a new graphics context is * created. * *---------------------------------------------------------------------- */ void TreeDotRect_Setup( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ DotState *p /* Where to save state info. */ ) { #if 1 struct DotStatePriv *dotState = (struct DotStatePriv *) p; MacDrawable *macDraw = (MacDrawable *) drawable; TreeRectangle tr; CGContextRef context; CGRect r; if (sizeof(*dotState) > sizeof(*p)) panic("TreeDotRect_Setup: DotState hack is too small"); dotState->context = NULL; if (!(macDraw->flags & TK_IS_PIXMAP)) { return; } tr.x = 0, tr.y = 0, tr.width = 1, tr.height = 1; context = dotState->context = TreeMacOSX_GetContext(tree, drawable, tr, &dotState->dc); if (context == NULL) { return; } /* Keep drawing inside the contentbox. */ CGContextBeginPath(context); r = CGRectMake(Tree_ContentLeft(tree), Tree_ContentTop(tree), Tree_ContentWidth(tree), Tree_ContentHeight(tree)); CGContextAddRect(context, r); CGContextClip(context); #else struct DotStatePriv *dotState = (struct DotStatePriv *) p; XGCValues gcValues; unsigned long mask; XRectangle xrect; if (sizeof(*dotState) > sizeof(*p)) panic("TreeDotRect_Setup: DotState hack is too small"); dotState->tree = tree; dotState->drawable = drawable; gcValues.line_style = LineOnOffDash; gcValues.line_width = 1; gcValues.dash_offset = 0; gcValues.dashes = 1; /* Can't get a 1-pixel dash pattern when antialiasing is used. */ /* See ::tk::mac::CGAntialiasLimit".*/ gcValues.dashes = 2; gcValues.function = GXcopy; gcValues.cap_style = CapButt; /* doesn't affect display */ mask = GCLineWidth | GCLineStyle | GCDashList | GCDashOffset | GCFunction | GCCapStyle; dotState->gc = Tk_GetGC(tree->tkwin, mask, &gcValues); /* Keep drawing inside the contentbox. */ dotState->rgn = Tree_GetRegion(tree); xrect.x = Tree_ContentLeft(tree); xrect.y = Tree_ContentTop(tree); xrect.width = Tree_ContentRight(tree) - xrect.x; xrect.height = Tree_ContentBottom(tree) - xrect.y; TkUnionRectWithRegion(&xrect, dotState->rgn, dotState->rgn); TkSetRegion(tree->display, dotState->gc, dotState->rgn); #endif } /* *---------------------------------------------------------------------- * * TreeDotRect_Draw -- * * Draw a dotted XOR rectangle. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void TreeDotRect_Draw( DotState *p, /* Info returned by TreeDotRect_Setup(). */ int x, int y, /* Left and top coordinates. */ int width, int height /* Size of rectangle. */ ) { struct DotStatePriv *dotState = (struct DotStatePriv *) p; #if 1 CGContextRef context = dotState->context; CGRect r = CGRectMake(x, y, width, height); if (dotState->context == NULL) return; CGContextAddRect(context, r); #else XDrawRectangle(dotState->tree->display, dotState->drawable, dotState->gc, x, y, width - 1, height - 1); #endif } /* *---------------------------------------------------------------------- * * TreeDotRect_Restore -- * * Restore the drawing environment. * * Results: * None. * * Side effects: * On Win32 and OSX the device context/graphics port is restored. * On X11 a new graphics context is freed. * *---------------------------------------------------------------------- */ void TreeDotRect_Restore( DotState *p /* Info returned by TreeDotRect_Setup(). */ ) { struct DotStatePriv *dotState = (struct DotStatePriv *) p; #if 1 CGContextRef context = dotState->context; CGFloat lengths[1] = {1.0f}; if (dotState->context == NULL) return; CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0); CGContextSetLineWidth(context, 0.01); CGContextSetLineDash(context, 0, lengths, 1); CGContextSetShouldAntialias(context, 0); CGContextStrokePath(context); TreeMacOSX_ReleaseContext(dotState->tree, &dotState->dc); #else XSetClipMask(dotState->tree->display, dotState->gc, None); Tree_FreeRegion(dotState->tree, dotState->rgn); Tk_FreeGC(dotState->tree->display, dotState->gc); #endif } /* *---------------------------------------------------------------------- * * Tree_FillRegion -- * * Paint a region with the foreground color of a graphics context. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_FillRegion( Display *display, /* Display. */ Drawable drawable, /* Where to draw. */ GC gc, /* Foreground color. */ TkRegion rgn /* Region to paint. */ ) { XRectangle box; TkClipBox(rgn, &box); TkSetRegion(display, gc, rgn); XFillRectangle(display, drawable, gc, box.x, box.y, box.width, box.height); XSetClipMask(display, gc, None); } /* *---------------------------------------------------------------------- * * Tree_OffsetRegion -- * * Offset a region. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_OffsetRegion( TkRegion region, /* Region to modify. */ int xOffset, int yOffset /* Horizontal and vertical offsets. */ ) { HIShapeOffset((HIMutableShapeRef) region, xOffset, yOffset); } /* *---------------------------------------------------------------------- * * Tree_UnionRegion -- * * Compute the union of 2 regions. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_UnionRegion( TkRegion rgnA, TkRegion rgnB, TkRegion rgnOut) { HIShapeUnion((HIShapeRef) rgnA, (HIShapeRef) rgnB, (HIMutableShapeRef) rgnOut); } /* *---------------------------------------------------------------------- * * Tree_ScrollWindow -- * * Wrapper around TkScrollWindow() to fix an apparent bug with the * Mac/OSX versions. * * Results: * None. * * Side effects: * Stuff is scrolled in a drawable. * *---------------------------------------------------------------------- */ int Tree_ScrollWindow( TreeCtrl *tree, /* Widget info. */ GC gc, /* Arg to TkScrollWindow(). */ int x, int y, /* Arg to TkScrollWindow(). */ int width, int height, /* Arg to TkScrollWindow(). */ int dx, int dy, /* Arg to TkScrollWindow(). */ TkRegion damageRgn /* Arg to TkScrollWindow(). */ ) { int result = TkScrollWindow(tree->tkwin, gc, x, y, width, height, dx, dy, damageRgn); #if (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 6) { MacDrawable *macWin = (MacDrawable *) Tk_WindowId(tree->tkwin); /* BUG IN TK? */ Tree_OffsetRegion(damageRgn, -macWin->xOff, -macWin->yOff); } #endif return result; } /* *---------------------------------------------------------------------- * * Tree_UnsetClipMask -- * * Wrapper around XSetClipMask(). On Win32 Tk_DrawChars() does * not clear the clipping region. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_UnsetClipMask( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ GC gc /* Graphics context to modify. */ ) { XSetClipMask(tree->display, gc, None); } /* *---------------------------------------------------------------------- * * Tree_DrawBitmapWithGC -- * * Draw part of a bitmap. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_DrawBitmapWithGC( TreeCtrl *tree, /* Widget info. */ Pixmap bitmap, /* Bitmap to draw. */ Drawable drawable, /* Where to draw. */ GC gc, /* Graphics context. */ int src_x, int src_y, /* Left and top of part of bitmap to copy. */ int width, int height, /* Width and height of part of bitmap to * copy. */ int dest_x, int dest_y /* Left and top coordinates to copy part of * the bitmap to. */ ) { XSetClipOrigin(tree->display, gc, dest_x, dest_y); XCopyPlane(tree->display, bitmap, drawable, gc, src_x, src_y, (unsigned int) width, (unsigned int) height, dest_x, dest_y, 1); XSetClipOrigin(tree->display, gc, 0, 0); } /* * TIP #116 altered Tk_PhotoPutBlock API to add interp arg. * We need to remove that for compiling with 8.4. */ #if (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 5) #define TK_PHOTOPUTBLOCK(interp, hdl, blk, x, y, w, h, cr) \ Tk_PhotoPutBlock(hdl, blk, x, y, w, h, cr) #define TK_PHOTOPUTZOOMEDBLOCK(interp, hdl, blk, x, y, w, h, \ zx, zy, sx, sy, cr) \ Tk_PhotoPutZoomedBlock(hdl, blk, x, y, w, h, \ zx, zy, sx, sy, cr) #else #define TK_PHOTOPUTBLOCK Tk_PhotoPutBlock #define TK_PHOTOPUTZOOMEDBLOCK Tk_PhotoPutZoomedBlock #endif /* *---------------------------------------------------------------------- * * Tree_XImage2Photo -- * * Copy pixels from an XImage to a Tk photo image. * * Results: * None. * * Side effects: * The given photo image is blanked and all the pixels from the * XImage are put into the photo image. * *---------------------------------------------------------------------- */ void Tree_XImage2Photo( Tcl_Interp *interp, /* Current interpreter. */ Tk_PhotoHandle photoH, /* Existing photo image. */ XImage *ximage, /* XImage to copy pixels from. */ unsigned long trans, /* Pixel value in ximage that should be * considered transparent. */ int alpha /* Desired transparency of photo image.*/ ) { Tk_PhotoImageBlock photoBlock; unsigned char *pixelPtr; int x, y, w = ximage->width, h = ximage->height; unsigned long red_shift, green_shift, blue_shift; Tk_PhotoBlank(photoH); /* See TkPoscriptImage */ red_shift = green_shift = blue_shift = 0; while ((0x0001 & (ximage->red_mask >> red_shift)) == 0) red_shift++; while ((0x0001 & (ximage->green_mask >> green_shift)) == 0) green_shift++; while ((0x0001 & (ximage->blue_mask >> blue_shift)) == 0) blue_shift++; pixelPtr = (unsigned char *) Tcl_Alloc(ximage->width * ximage->height * 4); photoBlock.pixelPtr = pixelPtr; photoBlock.width = ximage->width; photoBlock.height = ximage->height; photoBlock.pitch = ximage->width * 4; photoBlock.pixelSize = 4; photoBlock.offset[0] = 0; photoBlock.offset[1] = 1; photoBlock.offset[2] = 2; photoBlock.offset[3] = 3; for (y = 0; y < ximage->height; y++) { for (x = 0; x < ximage->width; x++) { int r, g, b; unsigned long pixel; /* FIXME: I think this blows up on classic Mac??? */ pixel = XGetPixel(ximage, x, y); /* Set alpha=0 for transparent pixel in the source XImage */ if (trans != 0 && pixel == trans) { pixelPtr[y * photoBlock.pitch + x * 4 + 3] = 0; continue; } r = (pixel & ximage->red_mask) >> red_shift; g = (pixel & ximage->green_mask) >> green_shift; b = (pixel & ximage->blue_mask) >> blue_shift; pixelPtr[y * photoBlock.pitch + x * 4 + 0] = r; pixelPtr[y * photoBlock.pitch + x * 4 + 1] = g; pixelPtr[y * photoBlock.pitch + x * 4 + 2] = b; pixelPtr[y * photoBlock.pitch + x * 4 + 3] = alpha; } } TK_PHOTOPUTBLOCK(interp, photoH, &photoBlock, 0, 0, w, h, TK_PHOTO_COMPOSITE_SET); Tcl_Free((char *) pixelPtr); } typedef struct { TreeCtrl *tree; TreeClip *clip; GC gc; TkRegion region; } TreeClipStateGC; static void TreeClip_ToGC( TreeCtrl *tree, /* Widget info. */ TreeClip *clip, /* Clipping area or NULL. */ GC gc, /* Graphics context. */ TreeClipStateGC *state ) { state->tree = tree; state->clip = clip; state->gc = gc; state->region = None; if (clip && clip->type == TREE_CLIP_RECT) { state->region = Tree_GetRegion(tree); Tree_SetRectRegion(state->region, &clip->tr); TkSetRegion(tree->display, gc, state->region); } if (clip && clip->type == TREE_CLIP_AREA) { TreeRectangle tr; if (Tree_AreaBbox(tree, clip->area, &tr) == 0) return; state->region = Tree_GetRectRegion(tree, &tr); TkSetRegion(tree->display, gc, state->region); } if (clip && clip->type == TREE_CLIP_REGION) { TkSetRegion(tree->display, gc, clip->region); } } static void TreeClip_FinishGC( TreeClipStateGC *state ) { XSetClipMask(state->tree->display, state->gc, None); if (state->region != None) Tree_FreeRegion(state->tree, state->region); } /* *---------------------------------------------------------------------- * * Tree_FillRectangle -- * * Wrapper around XFillRectangle() because the clip region is * ignored on Win32. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ void Tree_FillRectangle( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ GC gc, /* Graphics context. */ TreeRectangle tr /* Rectangle to paint. */ ) { TreeClipStateGC clipState; TreeClip_ToGC(tree, clip, gc, &clipState); XFillRectangle(tree->display, td.drawable, gc, tr.x, tr.y, tr.width, tr.height); TreeClip_FinishGC(&clipState); } /*** Themes ***/ struct TreeThemeData_ { TreeItem animButtonItem; Tcl_TimerToken animButtonTimer; int animButtonAngle; }; static HIThemeButtonDrawInfo GetThemeButtonDrawInfo( TreeCtrl *tree, int state, int arrow ) { HIThemeButtonDrawInfo info; info.version = 0; switch (state) { case COLUMN_STATE_ACTIVE: info.state = kThemeStateActive /* kThemeStateRollover */; break; case COLUMN_STATE_PRESSED: info.state = kThemeStatePressed; break; default: info.state = kThemeStateActive; break; } /* Background window */ if (!tree->isActive) info.state = kThemeStateInactive; info.kind = kThemeListHeaderButton; info.value = (arrow != COLUMN_ARROW_NONE) ? kThemeButtonOn : kThemeButtonOff; switch (arrow) { case COLUMN_ARROW_NONE: info.adornment = kThemeAdornmentHeaderButtonNoSortArrow; break; case COLUMN_ARROW_UP: info.adornment = kThemeAdornmentHeaderButtonSortUp; break; case COLUMN_ARROW_DOWN: default: info.adornment = kThemeAdornmentDefault; break; } return info; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawHeaderItem -- * * Draws the background of a single column header. On Mac OS X * this also draws the sort arrow, if any. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawHeaderItem( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ int state, /* COLUMN_STATE_xxx flags. */ int arrow, /* COLUMN_ARROW_xxx flags. */ int visIndex, /* 0-based index in list of visible columns. */ int x, int y, /* Bounds of the header. */ int width, int height /* Bounds of the header. */ ) { MacDrawable *macDraw = (MacDrawable *) td.drawable; CGRect bounds; HIThemeButtonDrawInfo info; MacContextSetup dc; CGContextRef context; HIShapeRef boundsRgn; int leftEdgeOffset; TreeRectangle tr; if (!(macDraw->flags & TK_IS_PIXMAP)) return TCL_ERROR; info = GetThemeButtonDrawInfo(tree, state, arrow); tr.x = x, tr.y = y, tr.width = width, tr.height = height; context = TreeMacOSX_GetContext(tree, td.drawable, tr, &dc); if (context == NULL) return TCL_ERROR; /* See SF patch 'aqua header drawing - ID: 1356447' */ /* The left edge overlaps the right edge of the previous column. */ /* Only show the left edge if this is the first column or the * "blue" column (with a sort arrow). */ if (visIndex == 0 || arrow == COLUMN_ARROW_NONE) leftEdgeOffset = 0; else leftEdgeOffset = -1; /* Create a clipping region as big as the header. */ bounds.origin.x = macDraw->xOff + x + leftEdgeOffset; bounds.origin.y = macDraw->yOff + y; bounds.size.width = width - leftEdgeOffset; bounds.size.height = height; boundsRgn = HIShapeCreateWithRect(&bounds); /* Set the clipping region */ HIShapeReplacePathInCGContext(boundsRgn, context); CGContextEOClip(context); /* See SF patch 'aqua header drawing - ID: 1356447' */ if (visIndex == 0) leftEdgeOffset = 0; else leftEdgeOffset = -1; bounds.origin.x = macDraw->xOff + x + leftEdgeOffset; bounds.size.width = width - leftEdgeOffset; (void) HIThemeDrawButton(&bounds, &info, context, kHIThemeOrientationNormal, NULL); TreeMacOSX_ReleaseContext(tree, &dc); CFRelease(boundsRgn); return TCL_OK; } /* List headers are a fixed height on Aqua */ int TreeTheme_GetHeaderFixedHeight( TreeCtrl *tree, int *heightPtr ) { SInt32 metric; GetThemeMetric(kThemeMetricListHeaderHeight, &metric); *heightPtr = metric; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_GetHeaderContentMargins -- * * Returns the padding inside the column header borders where * text etc may be displayed. * * Results: * TCL_OK if 'bounds' was set, TCL_ERROR otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetHeaderContentMargins( TreeCtrl *tree, /* Widget info. */ int state, /* COLUMN_STATE_xxx flags. */ int arrow, /* COLUMN_ARROW_xxx flags. */ int bounds[4] /* Returned left-top-right-bottom padding. */ ) { #if 1 /* HIThemeGetButtonContentBounds() returns a weird result. * The output rectangle starts 12 pixels from the *left* of the * input rectangle whereas I expected it end 12 from the right - where * the sort arrow is displayed. Also, it returns the same result * regardless of the arrow being displayed or not. * * Eyeballing the sort arrow shows a 5-pixel gap on the right and a * 7-pixel arrow. */ bounds[0] = 0; bounds[1] = 0; bounds[2] = (arrow != COLUMN_ARROW_NONE) ? 12 : 0; bounds[3] = 0; #else CGRect inBounds, outBounds; HIThemeButtonDrawInfo info; SInt32 metric; inBounds.origin.x = 0; inBounds.origin.y = 0; inBounds.size.width = 100; GetThemeMetric(kThemeMetricListHeaderHeight, &metric); inBounds.size.height = metric; info = GetThemeButtonDrawInfo(tree, state, arrow); (void) HIThemeGetButtonContentBounds( &inBounds, &info, &outBounds); bounds[0] = CGRectGetMinX(outBounds) - CGRectGetMinX(inBounds); bounds[1] = CGRectGetMinY(outBounds) - CGRectGetMinY(inBounds); bounds[2] = CGRectGetMaxX(inBounds) - CGRectGetMaxX(outBounds); bounds[3] = CGRectGetMaxY(inBounds) - CGRectGetMaxY(outBounds); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawHeaderArrow -- * * Draws the sort arrow in a column header. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawHeaderArrow( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ int state, /* COLUMN_STATE_xxx flags. */ int up, /* TRUE if up arrow, FALSE otherwise. */ int x, int y, /* Bounds of arrow. Width and */ int width, int height /* height are the same as that returned */ /* by TreeTheme_GetArrowSize(). */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawButton -- * * Draws a single expand/collapse item button. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawButton( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeItem item, /* Needed for animating. */ int state, /* STATE_xxx | BUTTON_STATE_xxx flags. */ int x, int y, /* Bounds of the button. Width and height */ int width, int height /* are the same as that returned by */ /* TreeTheme_GetButtonSize(). */ ) { int open = (state & STATE_ITEM_OPEN) != 0; int pressed = (state & BUTTON_STATE_PRESSED) != 0; MacDrawable *macDraw = (MacDrawable *) td.drawable; CGRect bounds; HIThemeButtonDrawInfo info; MacContextSetup dc; CGContextRef context; HIShapeRef clipRgn; TreeRectangle tr; if (!(macDraw->flags & TK_IS_PIXMAP)) return TCL_ERROR; bounds.origin.x = macDraw->xOff + x; bounds.origin.y = macDraw->yOff + y; bounds.size.width = width; bounds.size.height = height; info.version = 0; info.state = pressed ? kThemeStatePressed : kThemeStateActive; info.kind = kThemeDisclosureButton; info.value = open ? kThemeDisclosureDown : kThemeDisclosureRight; info.adornment = kThemeAdornmentDrawIndicatorOnly; tr.x = x, tr.y = y, tr.width = width, tr.height = height; context = TreeMacOSX_GetContext(tree, td.drawable, tr, &dc); if (context == NULL) return TCL_ERROR; /* This is how the rotated button is drawn. */ if (item == tree->themeData->animButtonItem) { int angle = tree->themeData->animButtonAngle * (open ? -1 : 1); CGContextTranslateCTM(context, x + width/2.0, y + height/2.0); CGContextRotateCTM(context, radians(angle)); CGContextTranslateCTM(context, -(x + width/2.0), -(y + height/2.0)); info.state = kThemeStatePressed; } /* Set the clipping region */ clipRgn = HIShapeCreateWithRect(&bounds); HIShapeReplacePathInCGContext(clipRgn, context); CGContextEOClip(context); (void) HIThemeDrawButton(&bounds, &info, context, kHIThemeOrientationNormal, NULL); TreeMacOSX_ReleaseContext(tree, &dc); CFRelease(clipRgn); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_GetButtonSize -- * * Returns the width and height of an expand/collapse item button. * * Results: * TCL_OK if *widthPtr and *heightPtr were set, TCL_ERROR * if themed buttons can't be drawn. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetButtonSize( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Needed on MS Windows. */ int open, /* TRUE if expanded button. */ int *widthPtr, /* Returned width of button. */ int *heightPtr /* Returned height of button. */ ) { SInt32 metric; (void) GetThemeMetric( kThemeMetricDisclosureTriangleWidth, &metric); *widthPtr = metric; (void) GetThemeMetric( kThemeMetricDisclosureTriangleHeight, &metric); *heightPtr = metric; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_GetArrowSize -- * * Returns the width and height of a column header sort arrow. * * Results: * TCL_OK if *widthPtr and *heightPtr were set, TCL_ERROR * if themed sort arrows can't be drawn. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetArrowSize( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Needed on MS Windows. */ int up, /* TRUE if up arrow. */ int *widthPtr, /* Returned width of arrow. */ int *heightPtr /* Returned height of arrow. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_SetBorders -- * * Sets the TreeCtrl.inset pad values according to the needs of * the system theme. * * Results: * TCL_OK if the inset was set, TCL_ERROR if the -highlightthickness * and -borderwidth values should be used. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_SetBorders( TreeCtrl *tree /* Widget info. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawBorders -- * * Draws themed borders around the edges of the treectrl. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the Tk focus rectangle * and 3D border should be drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawBorders( TreeCtrl *tree, /* Widget info. */ Drawable drawable /* Where to draw. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_GetHeaderTextColor -- * * Returns the text fill color to display a column title with. * * Results: * TCL_OK if the *colorPtrPtr was set, TCL_ERROR if a non-theme * color should be used. * * Side effects: * May allocate a new XColor. * *---------------------------------------------------------------------- */ int TreeTheme_GetHeaderTextColor( TreeCtrl *tree, /* Widget info. */ int columnState, /* COLUMN_STATE_xxx flags. */ XColor **colorPtrPtr /* Returned text color. */ ) { return TCL_ERROR; } #define ANIM_BUTTON_INTERVAL 50 /* guestimate */ static void AnimButtonTimerProc( ClientData clientData ) { TreeCtrl *tree = clientData; TreeItem item = tree->themeData->animButtonItem; if (tree->themeData->animButtonAngle >= 90) { tree->themeData->animButtonTimer = NULL; tree->themeData->animButtonItem = NULL; TreeItem_OpenClose(tree, item, -1); #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif } else { int interval = ANIM_BUTTON_INTERVAL; tree->themeData->animButtonAngle += 30; if (tree->themeData->animButtonAngle >= 90) { interval = 10; } tree->themeData->animButtonTimer = Tcl_CreateTimerHandler( interval, AnimButtonTimerProc, tree); Tree_InvalidateItemDInfo(tree, tree->columnTree, item, NULL); } } /* *---------------------------------------------------------------------- * * TreeTheme_AnimateButtonStart -- * * Starts an expand/collapse item button animating from open to * closed or vice versa. * * Results: * TCL_OK. * * Side effects: * May create a new Tcl_TimerToken. * *---------------------------------------------------------------------- */ int TreeTheme_AnimateButtonStart( TreeCtrl *tree, /* Widget info. */ TreeItem item /* The item whose button should animate. */ ) { if (tree->themeData->animButtonTimer != NULL) Tcl_DeleteTimerHandler(tree->themeData->animButtonTimer); tree->themeData->animButtonItem = item; tree->themeData->animButtonTimer = Tcl_CreateTimerHandler( ANIM_BUTTON_INTERVAL, AnimButtonTimerProc, tree); tree->themeData->animButtonAngle = 30; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_ItemDeleted -- * * Cancels any item-button animation in progress. * * Results: * TCL_OK. * * Side effects: * May delete a TCL_TimerToken. * *---------------------------------------------------------------------- */ int TreeTheme_ItemDeleted( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item being deleted. */ ) { if (item != tree->themeData->animButtonItem) return TCL_OK; if (tree->themeData->animButtonTimer != NULL) { Tcl_DeleteTimerHandler(tree->themeData->animButtonTimer); tree->themeData->animButtonTimer = NULL; tree->themeData->animButtonItem = NULL; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_Relayout -- * * This gets called when certain config options change and when * the size of the widget changes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeTheme_Relayout( TreeCtrl *tree /* Widget info. */ ) { } /* *---------------------------------------------------------------------- * * TreeTheme_IsDesktopComposited -- * * Determine if the OS windowing system is composited AKA * double-buffered. * * Results: * FALSE FALSE FALSE. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_IsDesktopComposited( TreeCtrl *tree /* Widget info. */ ) { #if 1 /* with gradient marquee, can't draw into window, need a pixmap */ return FALSE; #else return TRUE; #endif } /* *---------------------------------------------------------------------- * * TreeTheme_ThemeChanged -- * * Called after the system theme changes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeTheme_ThemeChanged( TreeCtrl *tree /* Widget info. */ ) { } /* *---------------------------------------------------------------------- * * TreeTheme_InitWidget -- * * Performs theme-related initialization when a treectrl is * created. * * Results: * TCL_OK or TCL_ERROR, but result is ignored. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_InitWidget( TreeCtrl *tree /* Widget info. */ ) { tree->themeData = (TreeThemeData) ckalloc(sizeof(struct TreeThemeData_)); tree->themeData->animButtonTimer = NULL; tree->themeData->animButtonAngle = 0; (void) TreeTheme_GetHeaderFixedHeight(tree, &tree->themeHeaderHeight); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_FreeWidget -- * * Performs theme-related cleanup a when a treectrl is destroyed. * * Results: * None. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { if (tree->themeData != NULL) { ckfree((char *) tree->themeData); tree->themeData = NULL; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_InitInterp -- * * Performs theme-related initialization when the TkTreeCtrl * package is loaded into an interpreter. * * Results: * TCL_OK or TCL_ERROR, but result is ignored. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_InitInterp( Tcl_Interp *interp /* Interp that loaded TkTreeCtrl pkg. */ ) { return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_SetOptionDefault -- * * Sets the default value for an option. * * Results: * Sets the defValue field if it wasn't done already. * * Side effects: * Changes an existing option table. * *---------------------------------------------------------------------- */ void TreeTheme_SetOptionDefault( Tk_OptionSpec *specPtr ) { #ifdef TREECTRL_DEBUG if (specPtr == NULL) panic("TreeTheme_SetOptionDefault specPtr == NULL"); #endif /* Only set the default value once per-application. */ if (specPtr->defValue != NULL) return; if (!strcmp(specPtr->optionName, "-buttontracking")) specPtr->defValue = "1"; else if (!strcmp(specPtr->optionName, "-showlines")) specPtr->defValue = "0"; #ifdef TREECTRL_DEBUG else panic("TreeTheme_SetOptionDefault unhandled option \"%s\"", specPtr->optionName ? specPtr->optionName : "NULL"); #endif } int TreeThemeCmd( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tcl_Interp *interp = tree->interp; static CONST char *commandName[] = { "platform", (char *) NULL }; enum { COMMAND_PLATFORM }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandName, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { /* T theme platform */ case COMMAND_PLATFORM: { char *platform = "aqua"; Tcl_SetObjResult(interp, Tcl_NewStringObj(platform, -1)); break; } } return TCL_OK; } /*** Gradients ***/ #if MAC_TK_COCOA /*(TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION >= 6)*/ /* * THIS WON'T WORK FOR DRAWING IN A WINDOW. */ CGContextRef TreeMacOSX_GetContext( TreeCtrl *tree, Drawable d, TreeRectangle tr, MacContextSetup *dc ) { MacDrawable *macDraw = (MacDrawable *) d; CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, .ty = macDraw->size.height}; if ((macDraw->flags & TK_IS_PIXMAP) && !macDraw->context) { GC gc = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC); XFillRectangle(tree->display, d, gc, tr.x, tr.y, tr.width, tr.height); } dc->context = macDraw->context; if (dc->context) { CGContextSaveGState(dc->context); CGContextConcatCTM(dc->context, t); } return dc->context; } void TreeMacOSX_ReleaseContext( TreeCtrl *tree, MacContextSetup *dc ) { if (dc->context != NULL) { CGContextSynchronize(dc->context); /* does nothing, expects window context */ CGContextRestoreGState(dc->context); } } #endif /* Tk 8.6 */ #if MAC_TK_CARBON /*(TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 6)*/ /* * THIS WON'T WORK FOR DRAWING IN A WINDOW. */ CGContextRef TreeMacOSX_GetContext( TreeCtrl *tree, Drawable d, TreeRectangle tr, MacContextSetup *dc ) { MacDrawable *macDraw = (MacDrawable *) d; CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, .ty = macDraw->size.height}; dc->port = TkMacOSXGetDrawablePort(d); dc->context = NULL; dc->portChanged = False; if (dc->port) { dc->portChanged = QDSwapPort(dc->port, &dc->savePort); if (QDBeginCGContext(dc->port, &dc->context) == noErr) { SyncCGContextOriginWithPort(dc->context, dc->port); CGContextSaveGState(dc->context); CGContextConcatCTM(dc->context, t); } } return dc->context; } void TreeMacOSX_ReleaseContext( TreeCtrl *tree, MacContextSetup *dc ) { if (dc->context != NULL) { CGContextSynchronize(dc->context); /* does nothing, expects window context */ CGContextRestoreGState(dc->context); if (dc->port) { QDEndCGContext(dc->port, &dc->context); } } if (dc->portChanged) { QDSwapPort(dc->savePort, NULL); } } #endif /* Tk 8.4 and 8.5 */ /* *---------------------------------------------------------------------- * * Tree_HasNativeGradients -- * * Determine if this platform supports gradients natively. * * Results: * 1. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tree_HasNativeGradients( TreeCtrl *tree) { return 1; } /* Copy-and-paste from TkPath */ const float kValidDomain[2] = {0, 1}; const float kValidRange[8] = {0, 1, 0, 1, 0, 1, 0, 1}; /* Seems to work for both Endians. */ #define BlueFloatFromXColorPtr(xc) (float) ((((xc)->pixel >> 0) & 0xFF)) / 255.0 #define GreenFloatFromXColorPtr(xc) (float) ((((xc)->pixel >> 8) & 0xFF)) / 255.0 #define RedFloatFromXColorPtr(xc) (float) ((((xc)->pixel >> 16) & 0xFF)) / 255.0 #if 0 typedef struct ShadeData { int nstops; unsigned short red[50], green[50], blue[50]; float offset[50]; float opacity[50]; } ShadeData; static void ShadeEvaluate( void *info, const float *in, float *out) { ShadeData *data = info; int nstops = data->nstops; int iStop1, iStop2; float offset1, offset2; float opacity1, opacity2; int i = 0; float par = *in; float f1, f2; /* Find the two stops for this point. Tricky! */ while ((i < nstops) && (data->offset[i] < par)) { i++; } if (i == 0) { /* First stop > 0. */ iStop1 = iStop2 = 0; } else if (i == nstops) { /* We have stepped beyond the last stop; step back! */ iStop1 = iStop2 = nstops - 1; } else { iStop1 = i-1, iStop2 = i; } opacity1 = data->opacity[iStop1]; opacity2 = data->opacity[iStop2]; offset1 = data->offset[iStop1]; offset2 = data->offset[iStop2]; /* Interpolate between the two stops. * "If two gradient stops have the same offset value, * then the latter gradient stop controls the color value at the * overlap point." */ if (fabs(offset2 - offset1) < 1e-6) { *out++ = data->red[iStop2]; *out++ = data->green[iStop2]; *out++ = data->blue[iStop2]; *out++ = opacity2; } else { int range, increment; float factor = (par - offset1)/(offset2 - offset1); range = (data->red[iStop2] - data->red[iStop1]); increment = (int)(range * factor); *out++ = CLAMP(data->red[iStop1] + increment,0,USHRT_MAX)/((float)USHRT_MAX); range = (data->green[iStop2] - data->green[iStop1]); increment = (int)(range * factor); *out++ = CLAMP(data->green[iStop1] + increment,0,USHRT_MAX)/((float)USHRT_MAX); range = (data->blue[iStop2] - data->blue[iStop1]); increment = (int)(range * factor); *out++ = CLAMP(data->blue[iStop1] + increment,0,USHRT_MAX)/((float)USHRT_MAX); *out++ = 1.0f /*f1 * opacity1 + f2 * opacity2*/; } } #elif 1 typedef struct ShadeData { int nstops; float red[50], green[50], blue[50]; float offset[50]; float opacity[50]; } ShadeData; static void ShadeEvaluate( void *info, const float *in, float *out) { ShadeData *data = info; int nstops = data->nstops; int iStop1, iStop2; float offset1, offset2; float opacity1, opacity2; int i = 0; float par = *in; float f1, f2; /* For a repeating pattern, clamp *in to 0-1 */ par = par - floor(par); /* Find the two stops for this point. Tricky! */ while ((i < nstops) && (data->offset[i] < par)) { i++; } if (i == 0) { /* First stop > 0. */ iStop1 = iStop2 = 0; } else if (i == nstops) { /* We have stepped beyond the last stop; step back! */ iStop1 = iStop2 = nstops - 1; } else { iStop1 = i-1, iStop2 = i; } opacity1 = data->opacity[iStop1]; opacity2 = data->opacity[iStop2]; offset1 = data->offset[iStop1]; offset2 = data->offset[iStop2]; /* Interpolate between the two stops. * "If two gradient stops have the same offset value, * then the latter gradient stop controls the color value at the * overlap point." */ if (fabs(offset2 - offset1) < 1e-6) { *out++ = data->red[iStop2]; *out++ = data->green[iStop2]; *out++ = data->blue[iStop2]; *out++ = opacity2; } else { f1 = (offset2 - par)/(offset2 - offset1); f2 = (par - offset1)/(offset2 - offset1); *out++ = f1 * data->red[iStop1] + f2 * data->red[iStop2]; *out++ = f1 * data->green[iStop1] + f2 * data->green[iStop2]; *out++ = f1 * data->blue[iStop1] + f2 * data->blue[iStop2]; *out++ = f1 * opacity1 + f2 * opacity2; } } #else static void ShadeEvaluate( void *info, const float *in, float *out) { TreeGradient gradient = info; GradientStopArray *stopArrPtr = gradient->stopArrPtr; GradientStop **stopPtrPtr = stopArrPtr->stops; GradientStop *stop1 = NULL, *stop2 = NULL; int nstops = stopArrPtr->nstops; int i = 0; float par = *in; float f1, f2; /* Find the two stops for this point. Tricky! */ while ((i < nstops) && ((*stopPtrPtr)->offset < par)) { stopPtrPtr++, i++; } if (i == 0) { /* First stop > 0. */ stop1 = *stopPtrPtr; stop2 = stop1; } else if (i == nstops) { /* We have stepped beyond the last stop; step back! */ stop1 = *(stopPtrPtr - 1); stop2 = stop1; } else { stop1 = *(stopPtrPtr - 1); stop2 = *stopPtrPtr; } /* Interpolate between the two stops. * "If two gradient stops have the same offset value, * then the latter gradient stop controls the color value at the * overlap point." */ if (fabs(stop2->offset - stop1->offset) < 1e-6) { *out++ = RedFloatFromXColorPtr(stop2->color); *out++ = GreenFloatFromXColorPtr(stop2->color); *out++ = BlueFloatFromXColorPtr(stop2->color); *out++ = stop2->opacity; } else { f1 = (stop2->offset - par)/(stop2->offset - stop1->offset); f2 = (par - stop1->offset)/(stop2->offset - stop1->offset); *out++ = f1 * RedFloatFromXColorPtr(stop1->color) + f2 * RedFloatFromXColorPtr(stop2->color); *out++ = f1 * GreenFloatFromXColorPtr(stop1->color) + f2 * GreenFloatFromXColorPtr(stop2->color); *out++ = f1 * BlueFloatFromXColorPtr(stop1->color) + f2 * BlueFloatFromXColorPtr(stop2->color); *out++ = f1 * stop1->opacity + f2 * stop2->opacity; } } #endif static void ShadeRelease(void *info) { /* Not sure if anything to do here. */ } #if 0 /* Get the colorspace used by the monitor. */ /* FIXME: 8.4+ only */ CGColorSpaceRef CreateSystemColorSpace() { CMProfileRef sysprof = NULL; CGColorSpaceRef dispColorSpace = NULL; if (CMGetSystemProfile(&sysprof) == noErr) { dispColorSpace = CGColorSpaceCreateWithPlatformColorSpace(sysprof); CMCloseProfile(sysprof); } return dispColorSpace; } #endif typedef struct { CGFunctionRef function; CGColorSpaceRef colorSpaceRef; CGShadingRef shading; ShadeData data; } MacShading; static CGShadingRef MakeLinearGradientShading( CGContextRef context, TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to paint. */ MacShading *ms ) { int i; CGFunctionCallbacks callbacks; CGPoint start, end; CGFloat input_value_range[2] = {0.f, 1.f}; ms->data.nstops = gradient->stopArrPtr->nstops; for (i = 0; i < gradient->stopArrPtr->nstops; i++) { GradientStop *stop = gradient->stopArrPtr->stops[i]; #if 0 ms->data.red[i] = stop->color->red; ms->data.green[i] = stop->color->green; ms->data.blue[i] = stop->color->blue; #else ms->data.red[i] = RedFloatFromXColorPtr(stop->color); ms->data.green[i] = GreenFloatFromXColorPtr(stop->color); ms->data.blue[i] = BlueFloatFromXColorPtr(stop->color); #endif ms->data.offset[i] = stop->offset; ms->data.opacity[i] = stop->opacity; } /* colorSpaceRef = CGColorSpaceCreateDeviceRGB();*/ /* colorSpaceRef = CreateSystemColorSpace();*/ /* colorSpaceRef = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);*/ ms->colorSpaceRef = CGBitmapContextGetColorSpace(context); CGColorSpaceRetain(ms->colorSpaceRef); if (gradient->vertical) { start = CGPointMake(trBrush.x, trBrush.y); end = CGPointMake(trBrush.x, trBrush.y + trBrush.height); } else { start = CGPointMake(trBrush.x, trBrush.y); end = CGPointMake(trBrush.x + trBrush.width, trBrush.y); } /* Repeating pattern */ if (gradient->vertical) { CGFloat dy = trBrush.height; input_value_range[0] = MIN((tr.y - trBrush.y) / dy, 0.0f); input_value_range[1] = MAX(((tr.y + tr.height) - trBrush.y) / dy, 1.0f); end.y = start.y + dy * input_value_range[1]; start.y += dy * input_value_range[0]; } else { CGFloat dx = trBrush.width; input_value_range[0] = MIN((tr.x - trBrush.x) / dx, 0.0f); input_value_range[1] = MAX(((tr.x + tr.width) - trBrush.x) / dx, 1.0f); end.x = start.x + dx * input_value_range[1]; start.x += dx * input_value_range[0]; } callbacks.version = 0; callbacks.evaluate = ShadeEvaluate; callbacks.releaseInfo = ShadeRelease; ms->function = CGFunctionCreate((void *) &ms->data, 1, input_value_range/*kValidDomain*/, 4, kValidRange, &callbacks); ms->shading = CGShadingCreateAxial(ms->colorSpaceRef, start, end, ms->function, 1, 1); return ms->shading; } static void ReleaseLinearGradientShading( MacShading *ms ) { CGShadingRelease(ms->shading); CGFunctionRelease(ms->function); CGColorSpaceRelease(ms->colorSpaceRef); } /* *---------------------------------------------------------------------- * * TreeGradient_FillRect -- * * Paint a rectangle with a gradient. * * Results: * If the gradient has <2 stops then nothing is drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ void TreeGradient_FillRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr /* Rectangle to paint. */ ) { MacDrawable *macDraw = (MacDrawable *) td.drawable; MacContextSetup dc; MacShading ms; CGContextRef context; CGShadingRef shading; CGRect r; if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (!(macDraw->flags & TK_IS_PIXMAP) || !tree->nativeGradients) { TreeGradient_FillRectX11(tree, td, clip, gradient, trBrush, tr); return; } context = TreeMacOSX_GetContext(tree, td.drawable, tr, &dc); if (context == NULL) { TreeGradient_FillRectX11(tree, td, clip, gradient, trBrush, tr); return; } shading = MakeLinearGradientShading(context, gradient, trBrush, tr, &ms); if (shading) { /* Must clip to the area to be painted otherwise the entire context * is filled with the gradient. */ CGContextBeginPath(context); r = CGRectMake(tr.x, tr.y, tr.width, tr.height); CGContextAddRect(context, r); CGContextClip(context); CGContextDrawShading(context, shading); ReleaseLinearGradientShading(&ms); } TreeMacOSX_ReleaseContext(tree, &dc); } static CGMutablePathRef MakeRectPath_OutlineFilled( TreeRectangle tr, /* Where to draw. */ int outlineWidth, /* Thickness of the outline. */ int open /* RECT_OPEN_x flags */ ) { CGFloat x = tr.x, y = tr.y, w = tr.width, h = tr.height; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; CGMutablePathRef p = CGPathCreateMutable(); CGRect r; if (drawN) { r = CGRectMake(x, y, w, outlineWidth); CGPathAddRect(p, NULL, r); } if (drawE) { r = CGRectMake(x + w - outlineWidth, y, outlineWidth, h); CGPathAddRect(p, NULL, r); } if (drawS) { r = CGRectMake(x, y + h - outlineWidth, w, outlineWidth); CGPathAddRect(p, NULL, r); } if (drawW) { r = CGRectMake(x, y, outlineWidth, h); CGPathAddRect(p, NULL, r); } return p; } void TreeGradient_DrawRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to draw. */ int outlineWidth, /* Width of outline. */ int open /* RECT_OPEN_x flags */ ) { MacDrawable *macDraw = (MacDrawable *) td.drawable; MacContextSetup dc; MacShading ms; CGContextRef context; CGShadingRef shading; CGMutablePathRef p; if (!(macDraw->flags & TK_IS_PIXMAP) || !tree->nativeGradients) { errorExit: TreeGradient_DrawRectX11(tree, td, clip, gradient, trBrush, tr, outlineWidth, open); return; } context = TreeMacOSX_GetContext(tree, td.drawable, tr, &dc); if (context == NULL) { goto errorExit; } shading = MakeLinearGradientShading(context, gradient, trBrush, tr, &ms); if (shading) { p = MakeRectPath_OutlineFilled(tr, outlineWidth, open); if (p) { CGContextAddPath(context, p); CGPathRelease(p); CGContextClip(context); CGContextDrawShading(context, shading); } ReleaseLinearGradientShading(&ms); } TreeMacOSX_ReleaseContext(tree, &dc); } static void AddArcToPath( CGMutablePathRef p, CGAffineTransform *t, CGAffineTransform *it, CGFloat x, CGFloat y, CGFloat radius, int startAngle, int endAngle ) { if (t) { CGPoint c = CGPointMake(x, y); c = CGPointApplyAffineTransform(c, *it); CGPathAddArc(p, t, c.x, c.y, radius, radians(startAngle), radians(endAngle), 0); } else { CGPathAddArc(p, NULL, x, y, radius, radians(startAngle), radians(endAngle), 0); } } static CGMutablePathRef MakeRoundRectPath_Fill( TreeRectangle tr, /* Where to draw. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { CGFloat x = tr.x, y = tr.y, width = tr.width, height = tr.height; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; CGMutablePathRef p = CGPathCreateMutable(); CGAffineTransform t, it, *tp, *itp; if (rx == ry) { itp = tp = NULL; } else { t = CGAffineTransformMakeScale(1.0, ry / (float)rx); it = CGAffineTransformInvert(t); tp = &t; itp = ⁢ } /* Simple case: draw all 4 corners and 4 edges */ if (!open) { AddArcToPath(p, tp, itp, x + rx, y + ry, rx, 180, 270); /* top-left */ AddArcToPath(p, tp, itp, x + width - rx, y + ry, rx, 270, 0); /* top-right */ AddArcToPath(p, tp, itp, x + width - rx, y + height - ry, rx, 0, 90); /* bottom-right */ AddArcToPath(p, tp, itp, x + rx, y + height - ry, rx, 90, 180); /* bottom-left */ /* Complicated case: some edges are "open" */ } else { CGPoint start[4], end[4]; /* start and end points of line segments*/ start[0] = CGPointMake(x, y); end[3] = start[0]; if (drawW && drawN) { start[0].x += rx; end[3].y += ry; } end[0] = CGPointMake(x + width, y); start[1]= end[0]; if (drawE && drawN) { end[0].x -= rx; start[1].y += ry; } end[1] = CGPointMake(x + width, y + height); start[2] = end[1]; if (drawE && drawS) { end[1].y -= ry; start[2].x -= rx; } end[2] = CGPointMake(x, y + height); start[3] = end[2]; if (drawW && drawS) { end[2].x += rx; start[3].y -= ry; } if (drawW && drawN) { AddArcToPath(p, tp, itp, x + rx, y + ry, rx, 180, 270); /* top-left */ } else { CGPathMoveToPoint(p, NULL, start[0].x, start[0].y); } CGPathAddLineToPoint(p, NULL, end[0].x, end[0].y); if (drawE && drawN) AddArcToPath(p, tp, itp, x + width - rx, y + ry, rx, 270, 0); /* top-right */ /*else CGPathMoveToPoint(p, NULL, start[1].x, start[1].y);*/ CGPathAddLineToPoint(p, NULL, end[1].x, end[1].y); if (drawE && drawS) AddArcToPath(p, tp, itp, x + width - rx, y + height - ry, rx, 0, 90); /* bottom-right */ /*else CGPathMoveToPoint(p, NULL, start[2].x, start[2].y);*/ CGPathAddLineToPoint(p, NULL, end[2].x, end[2].y); if (drawW && drawS) AddArcToPath(p, tp, itp, x + rx, y + height - ry, rx, 90, 180); /* bottom-left */ /*else CGPathMoveToPoint(p, NULL, start[3].x, start[3].y);*/ CGPathAddLineToPoint(p, NULL, end[3].x, end[3].y); } return p; } void TreeGradient_FillRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Where to draw. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { MacDrawable *macDraw = (MacDrawable *) td.drawable; MacContextSetup dc; MacShading ms; CGContextRef context; CGShadingRef shading; if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (!(macDraw->flags & TK_IS_PIXMAP) || !tree->nativeGradients) { TreeGradient_FillRoundRectX11(tree, td, clip, gradient, trBrush, tr, rx, ry, open); return; } context = TreeMacOSX_GetContext(tree, td.drawable, tr, &dc); if (context == NULL) { TreeGradient_FillRoundRectX11(tree, td, clip, gradient, trBrush, tr, rx, ry, open); return; } shading = MakeLinearGradientShading(context, gradient, trBrush, tr, &ms); if (shading) { CGContextBeginPath(context); if (rx == ry && !open) { CGContextAddArc(context, tr.x + rx, tr.y + ry, rx, radians(180), radians(270), 0); /* top-left */ CGContextAddArc(context, tr.x + tr.width - rx, tr.y + ry, rx, radians(270), radians(0), 0); /* top-right */ CGContextAddArc(context, tr.x + tr.width - rx, tr.y + tr.height - ry, rx, radians(0), radians(90), 0); /* bottom-right */ CGContextAddArc(context, tr.x + rx, tr.y + tr.height - ry, rx, radians(90), radians(180), 0); /* bottom-left */ } else { CGMutablePathRef p = MakeRoundRectPath_Fill(tr, rx, ry, open); if (p) { CGContextAddPath(context, p); CGPathRelease(p); } } /* Must clip to the area to be painted otherwise the entire context * is filled with the gradient. */ CGContextClip(context); CGContextDrawShading(context, shading); ReleaseLinearGradientShading(&ms); } TreeMacOSX_ReleaseContext(tree, &dc); } static CGMutablePathRef MakeRoundRectPath_Stroke( TreeRectangle tr, /* Where to draw. */ int outlineWidth, /* Thickness of the outline. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { CGFloat x = tr.x, y = tr.y, width = tr.width, height = tr.height; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; CGMutablePathRef p = CGPathCreateMutable(); CGAffineTransform t, it, *tp, *itp; if (rx == ry) { itp = tp = NULL; } else { t = CGAffineTransformMakeScale(1.0, ry / (float)rx); it = CGAffineTransformInvert(t); tp = &t; itp = ⁢ } x += outlineWidth / 2.0, y += outlineWidth / 2.0; width -= outlineWidth, height -= outlineWidth; /* Simple case: draw all 4 corners and 4 edges */ if (!open) { AddArcToPath(p, tp, itp, x + rx, y + ry, rx, 180, 270); /* top-left */ AddArcToPath(p, tp, itp, x + width - rx, y + ry, rx, 270, 0); /* top-right */ AddArcToPath(p, tp, itp, x + width - rx, y + height - ry, rx, 0, 90); /* bottom-right */ AddArcToPath(p, tp, itp, x + rx, y + height - ry, rx, 90, 180); /* bottom-left */ CGPathCloseSubpath(p); /* Complicated case: some edges are "open" */ } else { CGPoint start[4], end[4]; /* start and end points of line segments*/ start[0] = CGPointMake(x, y); end[3] = start[0]; if (drawW && drawN) { start[0].x += rx; end[3].y += ry; } end[0] = CGPointMake(x + width, y); start[1]= end[0]; if (drawE && drawN) { end[0].x -= rx; start[1].y += ry; } end[1] = CGPointMake(x + width, y + height); start[2] = end[1]; if (drawE && drawS) { end[1].y -= ry; start[2].x -= rx; } end[2] = CGPointMake(x, y + height); start[3] = end[2]; if (drawW && drawS) { end[2].x += rx; start[3].y -= ry; } if (drawW && drawN) { AddArcToPath(p, tp, itp, x + rx, y + ry, rx, 180, 270); /* top-left */ } else if (drawN) { CGPathMoveToPoint(p, NULL, start[0].x, start[0].y); } if (drawN) CGPathAddLineToPoint(p, NULL, end[0].x, end[0].y); if (drawE && drawN) AddArcToPath(p, tp, itp, x + width - rx, y + ry, rx, 270, 0); /* top-right */ else if (!drawN && drawE) CGPathMoveToPoint(p, NULL, start[1].x, start[1].y); if (drawE) CGPathAddLineToPoint(p, NULL, end[1].x, end[1].y); if (drawE && drawS) AddArcToPath(p, tp, itp, x + width - rx, y + height - ry, rx, 0, 90); /* bottom-right */ else if (!drawE && drawS) CGPathMoveToPoint(p, NULL, start[2].x, start[2].y); if (drawS) CGPathAddLineToPoint(p, NULL, end[2].x, end[2].y); if (drawW && drawS) AddArcToPath(p, tp, itp, x + rx, y + height - ry, rx, 90, 180); /* bottom-left */ else if (!drawS && drawW) CGPathMoveToPoint(p, NULL, start[3].x, start[3].y); if (drawW) CGPathAddLineToPoint(p, NULL, end[3].x, end[3].y); } return p; } void Tree_DrawRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ XColor *xcolor, /* Color. */ TreeRectangle tr, /* Where to draw. */ int outlineWidth, /* Thickness of the outline. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { MacDrawable *macDraw = (MacDrawable *) td.drawable; MacContextSetup dc; CGContextRef context; int antialias = !open; /* the arcs can be antialiased, but not the line ends! */ #if 0 RGBColor c; #endif if (!(macDraw->flags & TK_IS_PIXMAP) || !tree->nativeGradients) { GC gc = Tk_GCForColor(xcolor, Tk_WindowId(tree->tkwin)); Tree_DrawRoundRectX11(tree, td, clip, gc, tr, outlineWidth, rx, ry, open); return; } context = TreeMacOSX_GetContext(tree, td.drawable, tr, &dc); if (context == NULL) { GC gc = Tk_GCForColor(xcolor, Tk_WindowId(tree->tkwin)); Tree_DrawRoundRectX11(tree, td, clip, gc, tr, outlineWidth, rx, ry, open); return; } CGContextBeginPath(context); if (rx == ry && !open) { CGFloat x = tr.x, y = tr.y, width = tr.width, height = tr.height; x += outlineWidth / 2.0, y += outlineWidth / 2.0, width -= outlineWidth, height -= outlineWidth; CGContextAddArc(context, x + rx, y + ry, rx, radians(180), radians(270), 0); /* top-left */ CGContextAddArc(context, x + width - rx, y + ry, rx, radians(270), radians(0), 0); /* top-right */ CGContextAddArc(context, x + width - rx, y + height - ry, rx, radians(0), radians(90), 0); /* bottom-right */ CGContextAddArc(context, x + rx, y + height - ry, rx, radians(90), radians(180), 0); /* bottom-left */ CGContextClosePath(context); } else { CGMutablePathRef p = MakeRoundRectPath_Stroke(tr, outlineWidth, rx, ry, open); if (p) { CGContextAddPath(context, p); CGPathRelease(p); } } CGContextSetLineWidth(context, outlineWidth - (antialias ? 0 : 0.99) /*0.01*/); CGContextSetLineCap(context, kCGLineCapSquare); CGContextSetShouldAntialias(context, antialias); /* FIXME: the colors don't match the non-native version */ #if 0 dbwin("%#0X", (int)xcolor->pixel); c.red = (xcolor->pixel >> 16) & 0xff; c.green = (xcolor->pixel >> 8) & 0xff; c.blue = (xcolor->pixel) & 0xff; c.red |= c.red << 8; c.green |= c.green << 8; c.blue |= c.blue << 8; CGContextSetRGBStrokeColor/*WithColor*/(context, c.red / 65535.0f, c.green / 65535.0f, c.blue / 65535.0f, 1.0f); #else CGContextSetRGBStrokeColor/*WithColor*/(context, RedFloatFromXColorPtr(xcolor), GreenFloatFromXColorPtr(xcolor), BlueFloatFromXColorPtr(xcolor), 1.0f); #endif CGContextStrokePath(context); TreeMacOSX_ReleaseContext(tree, &dc); } static CGMutablePathRef MakeRoundRectPath_OutlineFilled( TreeRectangle tr, /* Where to draw. */ int outlineWidth, /* Thickness of the outline. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { CGFloat x = tr.x, y = tr.y, w = tr.width, h = tr.height; CGFloat ow = outlineWidth, yow = ow; CGFloat rOut = rx /*+ ow / 2*/, rIn = rx /*- ow / 2*/; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; CGMutablePathRef p = CGPathCreateMutable(); CGRect r; CGAffineTransform t, it = {0}, *tp, *itp; if (rx == ry) { itp = tp = NULL; } else { t = CGAffineTransformMakeScale(1.0, ry / (float)rx); it = CGAffineTransformInvert(t); tp = &t; itp = ⁢ } #if 1 /* Place the edges with gaps at the corners. */ if (drawN) { r = CGRectMake(x + drawW * rx, y, w - (drawW + drawE) * rx, ow); CGPathAddRect(p, NULL, r); } if (drawE) { r = CGRectMake(x + w - ow, y + drawN * ry, ow, h - (drawN + drawS) * ry); CGPathAddRect(p, NULL, r); } if (drawS) { r = CGRectMake(x + drawW * rx, y + h - ow, w - (drawW + drawE) * rx, ow); CGPathAddRect(p, NULL, r); } if (drawW) { r = CGRectMake(x, y + drawN * ry, ow, h - (drawN + drawS) * ry); CGPathAddRect(p, NULL, r); } #endif if (rx != ry) { ry = rx; h = CGPointApplyAffineTransform(CGPointMake(0, h), it).y; yow = CGPointApplyAffineTransform(CGPointMake(0, yow), it).y; } if (drawW && drawN) { CGPathMoveToPoint(p, tp, x + ow, y + yow + ry); CGPathAddLineToPoint(p, tp, x, y + yow + ry); CGPathAddArcToPoint(p, tp, x, y, x + ow + rx, y, rOut); CGPathAddLineToPoint(p, tp, x + ow + rx, y + yow); CGPathAddArcToPoint(p, tp, x + ow, y + yow, x + ow, y + yow + ry, rIn); } if (drawE && drawN) { CGPathMoveToPoint(p, tp, x + w - ow - rx, y + yow); CGPathAddLineToPoint(p, tp, x + w - ow - rx, y); CGPathAddArcToPoint(p, tp, x + w, y, x + w, y + ry + yow, rOut); CGPathAddLineToPoint(p, tp, x + w - ow, y + ry + yow); CGPathAddArcToPoint(p, tp, x + w - ow, y + yow, x + w - ow - rx, y + yow, rIn); } if (drawE && drawS) { CGPathMoveToPoint(p, tp, x + w - ow, y + h - ry - yow); CGPathAddLineToPoint(p, tp, x + w, y + h - ry - yow); CGPathAddArcToPoint(p, tp, x + w, y + h, x + w - rx - ow, y + h, rOut); CGPathAddLineToPoint(p, tp, x + w - rx - ow, y + h - yow); CGPathAddArcToPoint(p, tp, x + w - ow, y + h - yow, x + w - ow, y + h - ry - yow, rIn); } if (drawW && drawS) { CGPathMoveToPoint(p, tp, x + rx + ow, y + h - yow); CGPathAddLineToPoint(p, tp, x + rx + ow, y + h); CGPathAddArcToPoint(p, tp, x, y + h, x, y + h - ry - yow, rOut); CGPathAddLineToPoint(p, tp, x + ow, y + h - ry - yow); CGPathAddArcToPoint(p, tp, x + ow, y + h - yow, x + rx + ow, y + h - yow, rIn); } return p; } void TreeGradient_DrawRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to draw. */ int outlineWidth, /* Width of outline. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { MacDrawable *macDraw = (MacDrawable *) td.drawable; MacContextSetup dc; CGContextRef context; int antialias = 1; /* the arcs can be antialiased, but not the line ends! */ MacShading ms; CGShadingRef shading; if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (!(macDraw->flags & TK_IS_PIXMAP) || !tree->nativeGradients) { XColor *xcolor = gradient->stopArrPtr->stops[0]->color; /* Use the first stop color */ GC gc = Tk_GCForColor(xcolor, Tk_WindowId(tree->tkwin)); Tree_DrawRoundRectX11(tree, td, clip, gc, tr, outlineWidth, rx, ry, open); return; } context = TreeMacOSX_GetContext(tree, td.drawable, tr, &dc); if (context == NULL) { XColor *xcolor = gradient->stopArrPtr->stops[0]->color; /* Use the first stop color */ GC gc = Tk_GCForColor(xcolor, Tk_WindowId(tree->tkwin)); Tree_DrawRoundRectX11(tree, td, clip, gc, tr, outlineWidth, rx, ry, open); return; } shading = MakeLinearGradientShading(context, gradient, trBrush, tr, &ms); if (shading) { CGMutablePathRef p; CGContextBeginPath(context); p = MakeRoundRectPath_OutlineFilled(tr, outlineWidth, rx, ry, open); if (p) { CGContextAddPath(context, p); CGPathRelease(p); CGContextSetShouldAntialias(context, antialias); /* Must clip to the area to be painted otherwise the entire context * is filled with the gradient. */ CGContextClip(context); CGContextDrawShading(context, shading); } ReleaseLinearGradientShading(&ms); } TreeMacOSX_ReleaseContext(tree, &dc); } void Tree_FillRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ XColor *xcolor, /* Color. */ TreeRectangle tr, /* Where to draw. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { GC gc = Tk_GCForColor(xcolor, Tk_WindowId(tree->tkwin)); Tree_FillRoundRectX11(tree, td, clip, gc, tr, rx, ry, open); } int TreeDraw_InitInterp( Tcl_Interp *interp ) { return TCL_OK; } tktreectrl-2.4.1/Makefile.in0000644000076400010400000005101211571517011016256 0ustar TimAdministrators# Makefile.in -- # # This file is a Makefile for Sample TEA Extension. If it has the name # "Makefile.in" then it is a template for a Makefile; to generate the # actual Makefile, run "./configure", which is a configuration script # generated by the "autoconf" program (constructs like "@foo@" will get # replaced in the actual Makefile. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 2002 ActiveState SRL. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. #======================================================================== # Edit the following few lines when writing a new extension #======================================================================== #======================================================================== # Nothing of the variables below this line need to be changed. Please # check the TARGETS section below to make sure the make targets are # correct. #======================================================================== #======================================================================== # The names of the source files is defined in the configure script. # The object files are used for linking into the final library. # This will be used when a dist target is added to the Makefile. # It is not important to specify the directory, as long as it is the # $(srcdir) or in the generic, win or unix subdirectory. #======================================================================== PKG_SOURCES = @PKG_SOURCES@ PKG_OBJECTS = @PKG_OBJECTS@ #======================================================================== # PKG_TCL_SOURCES identifies Tcl runtime files that are associated with # this package that need to be installed, if any. #======================================================================== PKG_TCL_SOURCES = @PKG_TCL_SOURCES@ #======================================================================== # This is a list of public header files to be installed, if any. #======================================================================== PKG_HEADERS = @PKG_HEADERS@ PKG_EXTRA_FILES = PKG_MAN_PAGES = PKG_MANIFEST = @PKG_MANIFEST@ #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== PKG_LIB_FILE = @PKG_LIB_FILE@ PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ lib_BINARIES = $(PKG_LIB_FILE) BINARIES = $(lib_BINARIES) pkgIndex.tcl SHELL = @SHELL@ srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ datadir = @datadir@ datarootdir = @datarootdir@ mandir = @mandir@ includedir = @includedir@ DESTDIR = PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_PATCHLEVEL) pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(libdir)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) top_builddir = . INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PACKAGE_PATCHLEVEL = @PACKAGE_PATCHLEVEL@ CC = @CC@ CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ CFLAGS_WARNING = @CFLAGS_WARNING@ CC_OBJNAME = @CC_OBJNAME@ CLEANFILES = @CLEANFILES@ EXEEXT = @EXEEXT@ LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ MAKE_LIB = @MAKE_LIB@ MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ MAKE_STUB_LIB = @MAKE_STUB_LIB@ OBJEXT = @OBJEXT@ RANLIB = @RANLIB@ RANLIB_STUB = @RANLIB_STUB@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ SHLIB_LD = @SHLIB_LD@ SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ STLIB_LD = @STLIB_LD@ TCL_DEFS = @TCL_DEFS@ TCL_SRC_DIR = @TCL_SRC_DIR@ TCL_BIN_DIR = @TCL_BIN_DIR@ TK_SRC_DIR = @TK_SRC_DIR@ TK_BIN_DIR = @TK_BIN_DIR@ # Not used, but retained for reference of what libs Tcl required TCL_LIBS = @TCL_LIBS@ TK_LIBS = @TK_LIBS@ #======================================================================== # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our # package without installing. The other environment variables allow us # to test against an uninstalled Tcl. Add special env vars that you # require for testing here (like TCLX_LIBRARY). #======================================================================== EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR) TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \ TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` \ TREECTRL_LIBRARY=`@CYGPATH@ $(srcdir)/library` \ @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ PATH="$(EXTRA_PATH):$(PATH)" \ TCLLIBPATH="$(top_builddir)" TCLSH_PROG = @TCLSH_PROG@ WISH_PROG = @WISH_PROG@ TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) WISH = $(TCLSH_ENV) $(WISH_PROG) # The local includes must come first, because the TK_XINCLUDES can be # just a comment INCLUDES = @PKG_INCLUDES@ \ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ PKG_CFLAGS = @PKG_CFLAGS@ DEFS = @DEFS@ $(PKG_CFLAGS) CONFIG_CLEAN_FILES = Makefile $(PKG_MANIFEST) CPPFLAGS = @CPPFLAGS@ LIBS = @PKG_LIBS@ @LIBS@ AR = @AR@ CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #======================================================================== # Start of user-definable TARGETS section #======================================================================== #======================================================================== # TEA TARGETS. Please note that the "libraries:" target refers to platform # independent files, and the "binaries:" target inclues executable programs and # platform-dependent libraries. Modify these targets so that they install # the various pieces of your package. The make and install rules # for the BINARIES that you specified above have already been done. #======================================================================== all: binaries libraries doc #======================================================================== # The binaries target builds executable programs, Windows .dll's, unix # shared/static libraries, and any other platform-dependent files. # The list of targets to build for "binaries:" is specified at the top # of the Makefile, in the "BINARIES" variable. #======================================================================== binaries: $(BINARIES) libraries: doc-x: @echo "If you have documentation to create, place the commands to" @echo "build the docs in the 'doc:' target. For example:" @echo " xml2nroff sample.xml > sample.n" @echo " xml2html sample.xml > sample.html" doc: @echo "No docs to build" install: all install-binaries install-libraries install-doc install-binaries: binaries install-lib-binaries install-bin-binaries @mkdir -p $(DESTDIR)$(pkglibdir) $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir) @list='$(PKG_EXTRA_FILES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`; \ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ fi; \ done #======================================================================== # This rule installs platform-independent files, such as header files. #======================================================================== install-libraries: libraries #======================================================================== # Install documentation. Unix manpages should go in the $(mandir) # directory. #======================================================================== install-doc-x: @mkdir -p $(DESTDIR)$(mandir)/mann @echo "Installing documentation in $(DESTDIR)$(mandir)" @for i in $(srcdir)/doc/*.n; do \ echo "Installing $$i"; \ rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \ $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ done install-doc: install-doc-x mkdir -p $(DESTDIR)$(pkglibdir)/htmldoc cp $(srcdir)/doc/*.html $(DESTDIR)$(pkglibdir)/htmldoc test: binaries libraries @$(WISH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) | cat shell: binaries libraries @$(WISH) $(SCRIPT) demo: binaries libraries @$(WISH) `@CYGPATH@ $(srcdir)/demos/demo.tcl` | cat gdb: @$(TCLSH_ENV) gdb --silent --args $(WISH_PROG) $(srcdir)/demos/demo.tcl VALGRINDARGS=--tool=memcheck --num-callers=8 --leak-resolution=high --leak-check=yes --show-reachable=yes -v valgrind: binaries libraries $(TCLSH_ENV) valgrind $(VALGRINDARGS) $(TCLSH_PROG) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) | cat valgrindshell: binaries libraries $(TCLSH_ENV) valgrind $(VALGRINDARGS) $(WISH_PROG) $(SCRIPT) valgrinddemo: binaries libraries $(TCLSH_ENV) valgrind $(VALGRINDARGS) $(WISH_PROG) $(srcdir)/demos/demo.tcl # Type 'make vcexpress' from MSYS to launch the proper wish.exe in the Visual C++ # 2008 Express Edition debugger. Start the debugger then type 'source $env(DEMO)' # in the wish console to run the treectrl demo. VCEXPRESS = C:/Program Files (x86)/Microsoft Visual Studio 9.0/Common7/IDE/VCExpress.exe vcexpress: $(TCLSH_ENV) DEMO="$(srcdir)/demos/demo.tcl" "$(VCEXPRESS)" //DebugExe $(WISH_PROG) & depend: #======================================================================== # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable # mentioned above. That will ensure that this target is built when you # run "make binaries". # # The $(PKG_OBJECTS) objects are created and linked into the final # library. In most cases these object files will correspond to the # source files above. # # NOTE regarding the manifest(s): When building on a non-Windows box the # treectrlNN.dll.manifest file should not exist. When building with # MingW GCC the manifest will also not exist. Only when building with # a Microsoft compiler that auto-generates a manifest (to pick the correct # MSVCRT runtime) will $@.manifest exist; in this case mt.exe should # also exist. If mt.exe is used there is actually no need for treectrl.rc # to include treectrl.dll.manifest since mt.exe will clobber that resource # with the merged manifests. #======================================================================== $(PKG_LIB_FILE): $(PKG_OBJECTS) -rm -f $(PKG_LIB_FILE) ${MAKE_LIB} $(RANLIB) $(PKG_LIB_FILE) #======================================================================== # In the following lines, $(srcdir) refers to the toplevel directory # containing your extension. If your sources are in a subdirectory, # you will have to modify the paths to reflect this: # # tkpkg.$(OBJEXT): $(srcdir)/src/win/tkpkg.c # $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/tkpkg.c` -o $@ # # Setting the VPATH variable to a list of paths will cause the # makefile to look into these paths when resolving .c to .obj # dependencies. #======================================================================== # I added leading $(srcdir) because autoconf 2.53 strips it off VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/macosx:$(srcdir)/unix:$(srcdir)/win .c.@OBJEXT@: $(COMPILE) -c `@CYGPATH@ $<` $(CC_OBJNAME) .rc.@RES@: @RC@ @RC_OUT@ $@ @RC_INCLUDE@ "`@CYGPATH@ $(srcdir)`" @RC_DEPARG@ #======================================================================== # Create the pkgIndex.tcl file. #======================================================================== pkgIndex.tcl: (\ echo 'if {[catch {package require Tcl @TK_VERSION@}]} return';\ echo 'set script ""';\ echo 'if {![info exists ::env(TREECTRL_LIBRARY)]';\ echo ' && [file exists [file join $$dir treectrl.tcl]]} {';\ echo ' append script "[list set ::treectrl_library $$dir]\n"';\ echo '}';\ echo 'append script [list load [file join $$dir $(PKG_LIB_FILE)] $(PACKAGE_NAME)]';\ echo 'package ifneeded $(PACKAGE_NAME) $(PACKAGE_PATCHLEVEL) $$script'\ ) > pkgIndex.tcl #======================================================================== # Distribution creation # You may need to tweak this target to make it work correctly. #======================================================================== #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar #COMPRESS = gtar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) DIST_NAME = tktreectrl-$(PACKAGE_PATCHLEVEL) DIST_ARC = $(DIST_NAME).tar.gz COMPRESS = tar zcvf $(DIST_ARC) $(DIST_NAME) DIST_ROOT = /tmp/dist DIST_DIR = $(DIST_ROOT)/$(DIST_NAME) DIST_DEMOS = biglist bitmaps column-lock demo explorer firefox gradients \ gradients2 gradients3 headers help imovie layout \ mailwasher mycomputer outlook-folders outlook-newgroup \ random span style-editor table textvariable www-options DIST_DOCS = man.macros treectrl.html treectrl.man treectrl.n \ What-is-New-in-TkTreeCtrl.html DIST_LIBRARY = filelist-bindings.tcl treectrl.tcl dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(DIST_ARC) dist: dist-clean mkdir -p $(DIST_DIR) mkdir -p $(DIST_DIR)/demos mkdir -p $(DIST_DIR)/demos/pics mkdir -p $(DIST_DIR)/doc mkdir -p $(DIST_DIR)/generic mkdir -p $(DIST_DIR)/library mkdir -p $(DIST_DIR)/macosx mkdir -p $(DIST_DIR)/shellicon mkdir -p $(DIST_DIR)/shellicon/tclconfig mkdir -p $(DIST_DIR)/tclconfig mkdir -p $(DIST_DIR)/tests mkdir -p $(DIST_DIR)/unix mkdir -p $(DIST_DIR)/win list='aclocal.m4 ChangeLog configure configure.ac license.terms Makefile.in pkg.m4 README.txt treectrl.dll.manifest.in treectrl.rc winrc.m4'; \ for p in $$list; do \ cp -p $(srcdir)/$$p $(DIST_DIR)/$$p; \ chmod 664 $(DIST_DIR)/$$p; \ done chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.ac list='$(DIST_DEMOS)'; for p in $$list; do \ cp -p $(srcdir)/demos/$$p.tcl $(DIST_DIR)/demos/$$p.tcl; \ chmod 664 $(DIST_DIR)/demos/$$p.tcl; \ done cp -p $(srcdir)/demos/pics/*.gif $(DIST_DIR)/demos/pics/ chmod 664 $(DIST_DIR)/demos/pics/*.gif list='$(DIST_DOCS)'; for p in $$list; do \ cp -p $(srcdir)/doc/$$p $(DIST_DIR)/doc/$$p; \ chmod 664 $(DIST_DIR)/doc/$$p; \ done list='generic macosx unix win'; for p in $$list; do \ cp -p $(srcdir)/$$p/*.[ch] $(DIST_DIR)/$$p/; \ chmod 664 $(DIST_DIR)/$$p/*.[ch]; \ done list='$(DIST_LIBRARY)'; for p in $$list; do \ cp -p $(srcdir)/library/$$p $(DIST_DIR)/library/$$p; \ chmod 664 $(DIST_DIR)/library/$$p; \ done list='aclocal.m4 configure configure.ac Makefile.in shellicon.c shellicon.rc shellicon.dll.manifest.in'; \ for p in $$list; do \ cp -p $(srcdir)/shellicon/$$p $(DIST_DIR)/shellicon/$$p; \ chmod 664 $(DIST_DIR)/shellicon/$$p; \ done chmod 775 $(DIST_DIR)/shellicon/configure $(DIST_DIR)/shellicon/configure.ac list='install-sh README.txt tcl.m4'; \ for p in $$list; do \ cp -p $(srcdir)/shellicon/tclconfig/$$p $(DIST_DIR)/shellicon/tclconfig/$$p; \ chmod 664 $(DIST_DIR)/shellicon/tclconfig/$$p; \ done chmod 775 $(DIST_DIR)/shellicon/tclconfig/install-sh list='install-sh tcl.m4'; \ for p in $$list; do \ cp $(srcdir)/tclconfig/$$p $(DIST_DIR)/tclconfig/$$p; \ done chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 chmod 775 $(DIST_DIR)/tclconfig/install-sh cp -p $(srcdir)/tests/all.tcl $(srcdir)/tests/*.test $(DIST_DIR)/tests/ chmod 664 $(DIST_DIR)/tests/all.tcl chmod 664 $(DIST_DIR)/tests/*.test (cd $(DIST_ROOT); $(COMPRESS);) #======================================================================== # Windows binary distribution #======================================================================== DIST_WIN_NAME = treectrl$(PACKAGE_PATCHLEVEL) DIST_WIN_DIR = $(DIST_ROOT)/$(DIST_WIN_NAME) DIST_WIN_ARC = tktreectrl-$(PACKAGE_PATCHLEVEL)-@DIST_WIN_MACHINE@@DIST_WIN_THREADS@-Tk@TK_VERSION@.zip COMPRESS_WIN = zip -r -v -9 $(DIST_WIN_ARC) $(DIST_WIN_NAME) # Set this to 'strip' or 'x86_64-w64-mingw32-strip' for GCC builds STRIP = # An update to the gcc tools adds support for TLS callbacks which upx chokes on # UPX = upx -9 $(DIST_WIN_DIR)/$(PKG_LIB_FILE) UPX = dist-win-clean: rm -rf $(DIST_WIN_DIR) $(DIST_ROOT)/$(DIST_WIN_ARC) dist-win: dist-win-clean mkdir -p $(DIST_WIN_DIR) mkdir -p $(DIST_WIN_DIR)/demos mkdir -p $(DIST_WIN_DIR)/demos/pics mkdir -p $(DIST_WIN_DIR)/doc mkdir -p $(DIST_WIN_DIR)/shellicon list='pkgIndex.tcl $(PKG_LIB_FILE)'; \ for p in $$list; do \ cp -p $(top_builddir)/$$p $(DIST_WIN_DIR)/$$p; \ done list='license.terms README.txt'; \ for p in $$list; do \ cp -p $(srcdir)/$$p $(DIST_WIN_DIR)/$$p; \ done test -z $(STRIP) || $(STRIP) -s $(DIST_WIN_DIR)/$(PKG_LIB_FILE) $(UPX) list='$(DIST_LIBRARY)'; for p in $$list; do \ cp -p $(srcdir)/library/$$p $(DIST_WIN_DIR)/$$p; \ done list='$(DIST_DEMOS)'; for p in $$list; do \ cp -p $(srcdir)/demos/$$p.tcl $(DIST_WIN_DIR)/demos/$$p.tcl; \ done cp -p $(srcdir)/demos/pics/*.gif $(DIST_WIN_DIR)/demos/pics/ list='$(DIST_DOCS)'; for p in $$list; do \ cp -p $(srcdir)/doc/$$p $(DIST_WIN_DIR)/doc/$$p; \ done TCL_TRIM_DOTS=`echo $(PACKAGE_VERSION) | tr -d .`; \ SHELLICON_DLL="shellicon$$TCL_TRIM_DOTS.dll"; \ cp -p $(top_builddir)/shellicon/$$SHELLICON_DLL $(DIST_WIN_DIR)/shellicon/$$SHELLICON_DLL; \ test -z $(STRIP) || $(STRIP) -s $(DIST_WIN_DIR)/shellicon/$$SHELLICON_DLL; cp -p $(top_builddir)/shellicon/pkgIndex.tcl $(DIST_WIN_DIR)/shellicon/pkgIndex.tcl (cd $(DIST_ROOT); $(COMPRESS_WIN);) #======================================================================== # End of user-definable section #======================================================================== #======================================================================== # Don't modify the file to clean here. Instead, set the "CLEANFILES" # variable in configure.in #======================================================================== clean: -test -z "$(BINARIES)" || rm -f $(BINARIES) -rm -f *.$(OBJEXT) core *.core -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean: clean -rm -f *.tab.c -rm -f $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log config.status #======================================================================== # Install binary object libraries. On Windows this includes both .dll and # .lib files. Because the .lib files are not explicitly listed anywhere, # we need to deduce their existence from the .dll file of the same name. # Library files go into the lib directory. # In addition, this will generate the pkgIndex.tcl # file in the install location (assuming it can find a usable tclsh shell) # # You should not have to modify this target. #======================================================================== install-lib-binaries: @mkdir -p $(DESTDIR)$(pkglibdir) @list='$(lib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \ echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ ext=`echo $$p|sed -e "s/.*\.//"`; \ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ fi; \ fi; \ fi; \ done @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`; \ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ fi; \ done #======================================================================== # Install binary executables (e.g. .exe files and dependent .dll files) # This is for files that must go in the bin directory (located next to # wish and tclsh), like dependent .dll files on Windows. # # You should not have to modify this target, except to define bin_BINARIES # above if necessary. #======================================================================== install-bin-binaries: @mkdir -p $(DESTDIR)$(bindir) @list='$(bin_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ fi; \ done .SUFFIXES: .c .$(OBJEXT) .SUFFIXES: .@RES@ .SUFFIXES: .rc Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status uninstall-binaries: list='$(lib_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ p=`basename $$p`; \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(bin_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(bindir)/$$p; \ done .PHONY: all binaries clean depend distclean doc install libraries test # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tktreectrl-2.4.1/pkg.m40000644000076400010400000001214411460430657015246 0ustar TimAdministrators# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # # Similar to PKG_CHECK_MODULES, make sure that the first instance of # this or PKG_CHECK_MODULES is called, or make sure to call # PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_ifval([$2], [$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$PKG_CONFIG"; then if test -n "$$1"; then pkg_cv_[]$1="$$1" else PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], [pkg_failed=yes]) fi else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` else $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD ifelse([$4], , [AC_MSG_ERROR(dnl [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT ])], [AC_MSG_RESULT([no]) $4]) elif test $pkg_failed = untried; then ifelse([$4], , [AC_MSG_FAILURE(dnl [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])], [$4]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) ifelse([$3], , :, [$3]) fi[]dnl ])# PKG_CHECK_MODULES tktreectrl-2.4.1/README.txt0000644000076400010400000000040410265321015015702 0ustar TimAdministratorsCurrent maintainer: Tim Baker (treectrl@users.sourceforge.net) Website: http://tktreectrl.sourceforge.net/ An extra help document with examples and pictures is available from the main website: http://tktreectrl.sourceforge.net/Understanding%20TkTreeCtrl.html tktreectrl-2.4.1/shellicon/0000755000076400010400000000000011646706173016206 5ustar TimAdministratorstktreectrl-2.4.1/shellicon/aclocal.m40000644000076400010400000000026211452152770020037 0ustar TimAdministrators# # Include the TEA standard macro set # builtin(include,tclconfig/tcl.m4) # # Add here whatever m4 macros you want to define for your package # builtin(include,../winrc.m4) tktreectrl-2.4.1/shellicon/configure0000755000076400010400000106333611646370127020125 0ustar TimAdministrators#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.67 for shellicon 2.4. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='shellicon' PACKAGE_TARNAME='shellicon' PACKAGE_VERSION='2.4' PACKAGE_STRING='shellicon 2.4' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS WISH_PROG TCLSH_PROG VC_MANIFEST_EMBED_EXE VC_MANIFEST_EMBED_DLL RANLIB_STUB MAKE_STUB_LIB MAKE_STATIC_LIB MAKE_SHARED_LIB MAKE_LIB TCL_DBGX LDFLAGS_DEFAULT CFLAGS_DEFAULT LD_LIBRARY_PATH_VAR SHLIB_CFLAGS SHLIB_LD_LIBS SHLIB_LD STLIB_LD CC_OBJNAME CFLAGS_WARNING CFLAGS_OPTIMIZE CFLAGS_DEBUG CELIB_DIR AR SHARED_BUILD TCL_THREADS PKG_MANIFEST MACHINE RES RC_DEPARG RC_DEFINE RC_INCLUDE RC_TYPE RC_OUT RC XMKMF TK_XLIB_DIR_NATIVE TK_TOP_DIR_NATIVE TK_INCLUDES TCL_TOP_DIR_NATIVE TCL_INCLUDES PKG_OBJECTS PKG_SOURCES MATH_LIBS EGREP GREP RANLIB SET_MAKE INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM CPP OBJEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC TK_XINCLUDES TK_LIBS TK_STUB_LIB_SPEC TK_STUB_LIB_FLAG TK_STUB_LIB_FILE TK_LIB_SPEC TK_LIB_FLAG TK_LIB_FILE TK_SRC_DIR TK_BIN_DIR TK_VERSION TCL_SHLIB_LD_LIBS TCL_LD_FLAGS TCL_EXTRA_CFLAGS TCL_DEFS TCL_LIBS CLEANFILES TCL_STUB_LIB_SPEC TCL_STUB_LIB_FLAG TCL_STUB_LIB_FILE TCL_LIB_SPEC TCL_LIB_FLAG TCL_LIB_FILE TCL_SRC_DIR TCL_BIN_DIR TCL_PATCH_LEVEL TCL_VERSION PKG_CFLAGS PKG_LIBS PKG_INCLUDES PKG_HEADERS PKG_TCL_SOURCES PKG_STUB_OBJECTS PKG_STUB_SOURCES PKG_STUB_LIB_FILE PKG_LIB_FILE EXEEXT CYGPATH PACKAGE_PATCHLEVEL target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_tcl with_tk with_tclinclude with_tkinclude with_x enable_threads enable_shared enable_64bit enable_64bit_vis enable_rpath enable_wince with_celib enable_symbols ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP XMKMF' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures shellicon 2.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/shellicon] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of shellicon 2.4:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-threads build with threads --enable-shared build and link with shared libraries (default: on) --enable-64bit enable 64bit support (default: off) --enable-64bit-vis enable 64bit Sparc VIS support (default: off) --disable-rpath disable rpath support (default: on) --enable-wince enable Win/CE support (where applicable) --enable-symbols build with debugging symbols (default: off) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-tcl directory containing tcl configuration (tclConfig.sh) --with-tk directory containing tk configuration (tkConfig.sh) --with-tclinclude directory containing the public Tcl header files --with-tkinclude directory containing the public Tk header files --with-x use the X Window System --with-celib=DIR use Windows/CE support library from DIR Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor XMKMF Path to xmkmf, Makefile generator for X Window System Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF shellicon configure 2.4 generated by GNU Autoconf 2.67 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval "test \"\${$3+set}\"" = set; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by shellicon $as_me 2.4, which was generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5 ; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu PACKAGE_PATCHLEVEL=2.4.1 cat >>confdefs.h <<_ACEOF #define PACKAGE_PATCHLEVEL "$PACKAGE_PATCHLEVEL" _ACEOF # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.9" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for correct TEA configuration" >&5 $as_echo_n "checking for correct TEA configuration... " >&6; } if test x"${PACKAGE_NAME}" = x ; then as_fn_error $? " The PACKAGE_NAME variable must be defined by your TEA configure.in" "$LINENO" 5 fi if test x"3.9" = x ; then as_fn_error $? " TEA version not specified." "$LINENO" 5 elif test "3.9" != "${TEA_VERSION}" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: warning: requested TEA version \"3.9\", have \"${TEA_VERSION}\"" >&5 $as_echo "warning: requested TEA version \"3.9\", have \"${TEA_VERSION}\"" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5 $as_echo "ok (TEA ${TEA_VERSION})" >&6; } fi compile_for_windows="no" if test x"${host_alias}" != x ; then case $host_alias in *mingw32*) compile_for_windows="yes" esac fi case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) compile_for_windows="yes" ;; esac if test $compile_for_windows = yes ; then # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CYGPATH+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CYGPATH"; then ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CYGPATH="cygpath -w" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" fi fi CYGPATH=$ac_cv_prog_CYGPATH if test -n "$CYGPATH"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CYGPATH" >&5 $as_echo "$CYGPATH" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi EXEEXT=".exe" TEA_PLATFORM="windows" else CYGPATH=echo EXEEXT="" TEA_PLATFORM="unix" fi # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi { $as_echo "$as_me:${as_lineno-$LINENO}: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&5 $as_echo "$as_me: configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}" >&6;} # This package name must be replaced statically for AC_SUBST to work # Substitute STUB_LIB_FILE in case package creates a stub library too. # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... ac_aux_dir= for ac_dir in tclconfig "$srcdir"/tclconfig; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in tclconfig \"$srcdir\"/tclconfig" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true # Check whether --with-tcl was given. if test "${with_tcl+set}" = set; then : withval=$with_tcl; with_tclconfig="${withval}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5 $as_echo_n "checking for Tcl configuration... " >&6; } if test "${ac_cv_c_tclconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&5 $as_echo "$as_me: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&2;} with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5 fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi fi if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" as_fn_error $? "Can't find Tcl configuration definitions" "$LINENO" 5 else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${TCL_BIN_DIR}/tclConfig.sh" >&5 $as_echo "found ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of ${TCL_BIN_DIR}/tclConfig.sh" >&5 $as_echo_n "checking for existence of ${TCL_BIN_DIR}/tclConfig.sh... " >&6; } if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 $as_echo "loading" >&6; } . "${TCL_BIN_DIR}/tclConfig.sh" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5 $as_echo "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; } fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" case "`uname -s`" in *CYGWIN_*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cygwin variant" >&5 $as_echo_n "checking for cygwin variant... " >&6; } case ${TCL_EXTRA_CFLAGS} in *-mwin32*|*-mno-cygwin*) TEA_PLATFORM="windows" CFLAGS="$CFLAGS -mwin32" { $as_echo "$as_me:${as_lineno-$LINENO}: result: win32" >&5 $as_echo "win32" >&6; } ;; *) TEA_PLATFORM="unix" { $as_echo "$as_me:${as_lineno-$LINENO}: result: unix" >&5 $as_echo "unix" >&6; } ;; esac EXEEXT=".exe" ;; *) ;; esac # The BUILD_$pkg is to define the correct extern storage class # handling when making this package cat >>confdefs.h <<_ACEOF #define BUILD_${PACKAGE_NAME} /**/ _ACEOF # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp *.ilk vc*.pch" fi # TEA specific: #-------------------------------------------------------------------- # Load the tkConfig.sh file if necessary (Tk extension) #-------------------------------------------------------------------- # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true # Check whether --with-tk was given. if test "${with_tk+set}" = set; then : withval=$with_tk; with_tkconfig="${withval}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk configuration" >&5 $as_echo_n "checking for Tk configuration... " >&6; } if test "${ac_cv_c_tkconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself" >&5 $as_echo "$as_me: WARNING: --with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself" >&2;} with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else as_fn_error $? "${with_tkconfig} directory doesn't contain tkConfig.sh" "$LINENO" 5 fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../tk[8-9].[0-9]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../tk[8-9].[0-9]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../../tk[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[8-9].[0-9]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi fi if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" as_fn_error $? "Can't find Tk configuration definitions" "$LINENO" 5 else no_tk= TK_BIN_DIR="${ac_cv_c_tkconfig}" { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${TK_BIN_DIR}/tkConfig.sh" >&5 $as_echo "found ${TK_BIN_DIR}/tkConfig.sh" >&6; } fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of ${TK_BIN_DIR}/tkConfig.sh" >&5 $as_echo_n "checking for existence of ${TK_BIN_DIR}/tkConfig.sh... " >&6; } if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 $as_echo "loading" >&6; } . "${TK_BIN_DIR}/tkConfig.sh" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find ${TK_BIN_DIR}/tkConfig.sh" >&5 $as_echo "could not find ${TK_BIN_DIR}/tkConfig.sh" >&6; } fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd "${TK_BIN_DIR}"; pwd`" \ "`cd "${TK_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) $as_echo "#define MAC_OSX_TK 1" >>confdefs.h TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi # TEA specific: #----------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&5 $as_echo "$as_me: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&6;} prefix=${TCL_PREFIX} else { $as_echo "$as_me:${as_lineno-$LINENO}: --prefix defaulting to /usr/local" >&5 $as_echo "$as_me: --prefix defaulting to /usr/local" >&6;} prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then { $as_echo "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&5 $as_echo "$as_me: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&6;} exec_prefix=${TCL_EXEC_PREFIX} else { $as_echo "$as_me:${as_lineno-$LINENO}: --exec-prefix defaulting to ${prefix}" >&5 $as_echo "$as_me: --exec-prefix defaulting to ${prefix}" >&6;} exec_prefix=$prefix fi fi #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5 ; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5 ; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5 ; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5 ; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- if test -n "$ac_tool_prefix"; then # 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the compiler understands -pipe" >&5 $as_echo_n "checking if the compiler understands -pipe... " >&6; } if test "${tcl_cv_cc_pipe+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_cc_pipe=yes else tcl_cv_cc_pipe=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_pipe" >&5 $as_echo "$tcl_cv_cc_pipe" >&6; } if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if test "${ac_cv_c_bigendian+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac if test "${TEA_PLATFORM}" = "unix" ; then #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- ac_fn_c_check_func "$LINENO" "sin" "ac_cv_func_sin" if test "x$ac_cv_func_sin" = x""yes; then : MATH_LIBS="" else MATH_LIBS="-lm" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lieee" >&5 $as_echo_n "checking for main in -lieee... " >&6; } if test "${ac_cv_lib_ieee_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lieee $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ieee_main=yes else ac_cv_lib_ieee_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ieee_main" >&5 $as_echo "$ac_cv_lib_ieee_main" >&6; } if test "x$ac_cv_lib_ieee_main" = x""yes; then : MATH_LIBS="-lieee $MATH_LIBS" fi #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -linet" >&5 $as_echo_n "checking for main in -linet... " >&6; } if test "${ac_cv_lib_inet_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_inet_main=yes else ac_cv_lib_inet_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5 $as_echo "$ac_cv_lib_inet_main" >&6; } if test "x$ac_cv_lib_inet_main" = x""yes; then : LIBS="$LIBS -linet" fi ac_fn_c_check_header_mongrel "$LINENO" "net/errno.h" "ac_cv_header_net_errno_h" "$ac_includes_default" if test "x$ac_cv_header_net_errno_h" = x""yes; then : $as_echo "#define HAVE_NET_ERRNO_H 1" >>confdefs.h fi #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = x""yes; then : tcl_checkSocket=0 else tcl_checkSocket=1 fi if test "$tcl_checkSocket" = 1; then ac_fn_c_check_func "$LINENO" "setsockopt" "ac_cv_func_setsockopt" if test "x$ac_cv_func_setsockopt" = x""yes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setsockopt in -lsocket" >&5 $as_echo_n "checking for setsockopt in -lsocket... " >&6; } if test "${ac_cv_lib_socket_setsockopt+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char setsockopt (); int main () { return setsockopt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_setsockopt=yes else ac_cv_lib_socket_setsockopt=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_setsockopt" >&5 $as_echo "$ac_cv_lib_socket_setsockopt" >&6; } if test "x$ac_cv_lib_socket_setsockopt" = x""yes; then : LIBS="$LIBS -lsocket" else tcl_checkBoth=1 fi fi fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" ac_fn_c_check_func "$LINENO" "accept" "ac_cv_func_accept" if test "x$ac_cv_func_accept" = x""yes; then : tcl_checkNsl=0 else LIBS=$tk_oldLibs fi fi ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = x""yes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then : LIBS="$LIBS -lnsl" fi fi # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking dirent.h" >&5 $as_echo_n "checking dirent.h... " >&6; } if test "${tcl_cv_dirent_h+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_dirent_h=yes else tcl_cv_dirent_h=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_dirent_h" >&5 $as_echo "$tcl_cv_dirent_h" >&6; } if test $tcl_cv_dirent_h = no; then $as_echo "#define NO_DIRENT_H 1" >>confdefs.h fi # TEA specific: ac_fn_c_check_header_mongrel "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default" if test "x$ac_cv_header_errno_h" = x""yes; then : else $as_echo "#define NO_ERRNO_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "float.h" "ac_cv_header_float_h" "$ac_includes_default" if test "x$ac_cv_header_float_h" = x""yes; then : else $as_echo "#define NO_FLOAT_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "values.h" "ac_cv_header_values_h" "$ac_includes_default" if test "x$ac_cv_header_values_h" = x""yes; then : else $as_echo "#define NO_VALUES_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default" if test "x$ac_cv_header_limits_h" = x""yes; then : $as_echo "#define HAVE_LIMITS_H 1" >>confdefs.h else $as_echo "#define NO_LIMITS_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = x""yes; then : tcl_ok=1 else tcl_ok=0 fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtol" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtoul" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtod" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* if test $tcl_ok = 0; then $as_echo "#define NO_STDLIB_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default" if test "x$ac_cv_header_string_h" = x""yes; then : tcl_ok=1 else tcl_ok=0 fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strstr" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strerror" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then $as_echo "#define NO_STRING_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "sys/wait.h" "ac_cv_header_sys_wait_h" "$ac_includes_default" if test "x$ac_cv_header_sys_wait_h" = x""yes; then : else $as_echo "#define NO_SYS_WAIT_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = x""yes; then : else $as_echo "#define NO_DLFCN_H 1" >>confdefs.h fi # OS/390 lacks sys/param.h (and doesn't need it, by chance). for ac_header in sys/param.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_PARAM_H 1 _ACEOF fi done # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- vars="shellicon.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then as_fn_error $? "could not find header file '${srcdir}/$i'" "$LINENO" 5 fi PKG_HEADERS="$PKG_HEADERS $i" done vars="-I\"`${CYGPATH} ${srcdir}/../generic`\"" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done PKG_CFLAGS="$PKG_CFLAGS " vars="" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then as_fn_error $? "could not find stub source file '$i'" "$LINENO" 5 fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done vars="" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then as_fn_error $? "could not find tcl source file '${srcdir}/$i'" "$LINENO" 5 fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG #-------------------------------------------------------------------- #TEA_PUBLIC_TCL_HEADERS { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl public headers" >&5 $as_echo_n "checking for Tcl public headers... " >&6; } # Check whether --with-tclinclude was given. if test "${with_tclinclude+set}" = set; then : withval=$with_tclinclude; with_tclinclude=${withval} fi if test "${ac_cv_c_tclh+set}" = set; then : $as_echo_n "(cached) " >&6 else # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else as_fn_error $? "${with_tclinclude} directory does not contain tcl.h" "$LINENO" 5 fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi fi # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then as_fn_error $? "tcl.h not found. Please specify its location with --with-tclinclude" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tclh}" >&5 $as_echo "${ac_cv_c_tclh}" >&6; } fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl private include files" >&5 $as_echo_n "checking for Tcl private include files... " >&6; } TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then as_fn_error $? "Cannot find private header tclInt.h in ${TCL_SRC_DIR}" "$LINENO" 5 fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${result}" >&5 $as_echo "${result}" >&6; } #TEA_PUBLIC_TK_HEADERS { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk public headers" >&5 $as_echo_n "checking for Tk public headers... " >&6; } # Check whether --with-tkinclude was given. if test "${with_tkinclude+set}" = set; then : withval=$with_tkinclude; with_tkinclude=${withval} fi if test "${ac_cv_c_tkh+set}" = set; then : $as_echo_n "(cached) " >&6 else # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else as_fn_error $? "${with_tkinclude} directory does not contain tk.h" "$LINENO" 5 fi else list="" if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TK_INCLUDE_SPEC}" != x ; then d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi fi # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then as_fn_error $? "tk.h not found. Please specify its location with --with-tkinclude" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_cv_c_tkh}" >&5 $as_echo "${ac_cv_c_tkh}" >&6; } fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 header files" >&5 $as_echo_n "checking for X11 header files... " >&6; } if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${INCLUDE_DIR_NATIVE}" >&5 $as_echo "${INCLUDE_DIR_NATIVE}" >&6; } fi # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tk private include files" >&5 $as_echo_n "checking for Tk private include files... " >&6; } TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I${TK_XLIB_DIR_NATIVE}" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then as_fn_error $? "Cannot find private header tkInt.h in ${TK_SRC_DIR}" "$LINENO" 5 fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${result}" >&5 $as_echo "${result}" >&6; } #-------------------------------------------------------------------- # For Unix/Tk builds, make sure that the X libraries/headers are found. #-------------------------------------------------------------------- if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5 ;; #( *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.i conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else not_really_there="yes" fi rm -f conftest.err conftest.i conftest.$ac_ext else if test ! -r $x_includes/X11/Intrinsic.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 header files" >&5 $as_echo_n "checking for X11 header files... " >&6; } found_xincludes="no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : found_xincludes="yes" else found_xincludes="no" fi rm -f conftest.err conftest.i conftest.$ac_ext if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Intrinsic.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $i" >&5 $as_echo "$i" >&6; } XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test "$found_xincludes" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: couldn't find any!" >&5 $as_echo "couldn't find any!" >&6; } fi if test "$no_x" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11 libraries" >&5 $as_echo_n "checking for X11 libraries... " >&6; } XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $i" >&5 $as_echo "$i" >&6; } XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XCreateWindow in -lXwindow" >&5 $as_echo_n "checking for XCreateWindow in -lXwindow... " >&6; } if test "${ac_cv_lib_Xwindow_XCreateWindow+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXwindow $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XCreateWindow (); int main () { return XCreateWindow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xwindow_XCreateWindow=yes else ac_cv_lib_Xwindow_XCreateWindow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xwindow_XCreateWindow" >&5 $as_echo "$ac_cv_lib_Xwindow_XCreateWindow" >&6; } if test "x$ac_cv_lib_Xwindow_XCreateWindow" = x""yes; then : XLIBSW=-lXwindow fi fi if test "$XLIBSW" = nope ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find any! Using -lX11." >&5 $as_echo "could not find any! Using -lX11." >&6; } XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi fi # Needed for OS X ppx/intel image handling { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if test "${ac_cv_c_bigendian+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac #-------------------------------------------------------------------- # __CHANGE__ # A few miscellaneous platform-specific items: # # Define a special symbol for Windows (BUILD_sample in this case) so # that we create the export library with the dll. See sha1.h on how # to use this. # # Windows creates a few extra files that need to be cleaned up. # You can add more files to clean if your extension creates any extra # files. # # Define any extra compiler flags in the PACKAGE_CFLAGS variable. # These will be appended to the current set of compiler flags for # your system. #-------------------------------------------------------------------- OUTPUTFILES=Makefile if test "${TEA_PLATFORM}" = "windows" ; then vars="gdi32.lib user32.lib comctl32.lib ole32.lib shell32.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done # Find rc.exe or windres.exe. # Defined in winrc.m4. # AC_MSG_CHECKING([for windows resource compiler]) RC_DEPARG='"$<"' if test "${GCC}" = "yes" ; then # Extract the first word of "windres", so it can be a program name with args. set dummy windres; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_RC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RC"; then ac_cv_prog_RC="$RC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RC="windres" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RC=$ac_cv_prog_RC if test -n "$RC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RC" >&5 $as_echo "$RC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "${RC}" = "" ; then as_fn_error $? "Required resource tool 'windres' not found on PATH." "$LINENO" 5 fi RC_OUT=-o RC_TYPE= RC_INCLUDE=--include RC_DEFINE=--define RES=res.o # Check for a bug in gcc's windres that causes the # compile to fail when a Windows native path is # passed into windres. The mingw toolchain requires # Windows native paths while Cygwin should work # with both. Avoid the bug by passing a POSIX # path when using the Cygwin toolchain. if test "$ac_cv_cygwin" != "yes" -a "$CYGPATH" != "echo" ; then conftest=/tmp/conftest.rc echo "STRINGTABLE BEGIN" > $conftest echo "101 \"name\"" >> $conftest echo "END" >> $conftest { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Windows native path bug in windres" >&5 $as_echo_n "checking for Windows native path bug in windres... " >&6; } cyg_conftest=`$CYGPATH $conftest` if { ac_try='$RC -o conftest.res.o $cyg_conftest' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 (eval $ac_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } RC_DEPARG='"$(shell $(CYGPATH) $<)"' else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi conftest= cyg_conftest= fi else if test "$do64bit" != "no" ; then RC="\"${MSSDK}/bin/rc.exe\"" elif test "$doWince" != "no" ; then RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" else RC="rc" fi RC_OUT=-fo RC_TYPE=-r RC_INCLUDE=-i RC_DEFINE=-d RES=res fi # X86|AMD64|IA64 for manifest # PKG_MANIFEST -> VC_MANIFEST_EMBED_DLL -> MAKE_SHARED_LIB vars="shellicon.dll.manifest" for i in $vars; do # check for existence of .manifest.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/$i.in"; then as_fn_error $? "could not find manifest file '${srcdir}/$i'" "$LINENO" 5 fi PKG_MANIFEST="$PKG_MANIFEST $i" # If package .manifest is provided, don't clean it # If package .manifest is generated by Makefile, clean it # If package .manifest is generated by configure, distclean it #TEA_ADD_CLEANFILES([$i]) done # Create shellicon.dll.manifest from shellicon.dll.manifest.in. # shellicon.dll.manifest is included by shellicon.rc. # If building with a Microsoft compiler that generates # shelliconNN.dll.manifest (to pick the correct MSVCRT runtime) then # that manifest is merged with mine using mt.exe (see the Makefile # rule for PKG_LIB_FILE). OUTPUTFILES="Makefile shellicon.dll.manifest" vars="shellicon.rc" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then as_fn_error $? "could not find source file '$i'" "$LINENO" 5 fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${RES}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${RES}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${RES}" fi PKG_OBJECTS="$PKG_OBJECTS $j" CLEANFILES="$CLEANFILES $j" ;; esac done fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then vars="-framework Carbon" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done fi #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. #-------------------------------------------------------------------- # Check whether --enable-threads was given. if test "${enable_threads+set}" = set; then : enableval=$enable_threads; tcl_ok=$enableval else tcl_ok=yes fi if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention $as_echo "#define USE_THREAD_ALLOC 1" >>confdefs.h $as_echo "#define _REENTRANT 1" >>confdefs.h if test "`uname -s`" = "SunOS" ; then $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h fi $as_echo "#define _THREAD_SAFE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5 $as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; } if test "${ac_cv_lib_pthread_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_mutex_init=yes else ac_cv_lib_pthread_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_pthread_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __pthread_mutex_init in -lpthread" >&5 $as_echo_n "checking for __pthread_mutex_init in -lpthread... " >&6; } if test "${ac_cv_lib_pthread___pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char __pthread_mutex_init (); int main () { return __pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread___pthread_mutex_init=yes else ac_cv_lib_pthread___pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_pthread___pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthread___pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthreads" >&5 $as_echo_n "checking for pthread_mutex_init in -lpthreads... " >&6; } if test "${ac_cv_lib_pthreads_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthreads $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthreads_pthread_mutex_init=yes else ac_cv_lib_pthreads_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_pthreads_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_pthreads_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc" >&5 $as_echo_n "checking for pthread_mutex_init in -lc... " >&6; } if test "${ac_cv_lib_c_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_pthread_mutex_init=yes else ac_cv_lib_c_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_c_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_c_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lc_r" >&5 $as_echo_n "checking for pthread_mutex_init in -lc_r... " >&6; } if test "${ac_cv_lib_c_r_pthread_mutex_init+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_mutex_init (); int main () { return pthread_mutex_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_r_pthread_mutex_init=yes else ac_cv_lib_c_r_pthread_mutex_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5 $as_echo "$ac_cv_lib_c_r_pthread_mutex_init" >&6; } if test "x$ac_cv_lib_c_r_pthread_mutex_init" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&5 $as_echo "$as_me: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&2;} fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output { $as_echo "$as_me:${as_lineno-$LINENO}: checking for building with threads" >&5 $as_echo_n "checking for building with threads... " >&6; } if test "${TCL_THREADS}" = 1; then $as_echo "#define TCL_THREADS 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5 $as_echo "yes (default)" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&5 $as_echo "$as_me: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&2;} fi ;; *) if test "${TCL_THREADS}" = "1"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&5 $as_echo "$as_me: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&2;} fi ;; esac #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to build libraries" >&5 $as_echo_n "checking how to build libraries... " >&6; } # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; tcl_ok=$enableval else tcl_ok=yes fi if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: shared" >&5 $as_echo "shared" >&6; } SHARED_BUILD=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: static" >&5 $as_echo "static" >&6; } SHARED_BUILD=0 $as_echo "#define STATIC_BUILD 1" >>confdefs.h fi #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- # Step 0.a: Enable 64 bit support? { $as_echo "$as_me:${as_lineno-$LINENO}: checking if 64bit support is requested" >&5 $as_echo_n "checking if 64bit support is requested... " >&6; } # Check whether --enable-64bit was given. if test "${enable_64bit+set}" = set; then : enableval=$enable_64bit; do64bit=$enableval else do64bit=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $do64bit" >&5 $as_echo "$do64bit" >&6; } # Step 0.b: Enable Solaris 64 bit VIS support? { $as_echo "$as_me:${as_lineno-$LINENO}: checking if 64bit Sparc VIS support is requested" >&5 $as_echo_n "checking if 64bit Sparc VIS support is requested... " >&6; } # Check whether --enable-64bit-vis was given. if test "${enable_64bit_vis+set}" = set; then : enableval=$enable_64bit_vis; do64bitVIS=$enableval else do64bitVIS=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $do64bitVIS" >&5 $as_echo "$do64bitVIS" >&6; } # Force 64bit on with VIS if test "$do64bitVIS" = "yes"; then : do64bit=yes fi # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports visibility \"hidden\"" >&5 $as_echo_n "checking if compiler supports visibility \"hidden\"... " >&6; } if test "${tcl_cv_cc_visibility_hidden+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {} int main () { f(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_visibility_hidden=yes else tcl_cv_cc_visibility_hidden=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_visibility_hidden" >&5 $as_echo "$tcl_cv_cc_visibility_hidden" >&6; } if test $tcl_cv_cc_visibility_hidden = yes; then : $as_echo "#define MODULE_SCOPE extern __attribute__((__visibility__(\"hidden\")))" >>confdefs.h fi # Step 0.d: Disable -rpath support? { $as_echo "$as_me:${as_lineno-$LINENO}: checking if rpath support is requested" >&5 $as_echo_n "checking if rpath support is requested... " >&6; } # Check whether --enable-rpath was given. if test "${enable_rpath+set}" = set; then : enableval=$enable_rpath; doRpath=$enableval else doRpath=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doRpath" >&5 $as_echo "$doRpath" >&6; } # TEA specific: Cross-compiling options for Windows/CE builds? if test "${TEA_PLATFORM}" = windows; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Windows/CE build is requested" >&5 $as_echo_n "checking if Windows/CE build is requested... " >&6; } # Check whether --enable-wince was given. if test "${enable_wince+set}" = set; then : enableval=$enable_wince; doWince=$enableval else doWince=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doWince" >&5 $as_echo "$doWince" >&6; } fi # Set the variable "system" to hold the name and version number # for the system. { $as_echo "$as_me:${as_lineno-$LINENO}: checking system version" >&5 $as_echo_n "checking system version... " >&6; } if test "${tcl_cv_sys_version+set}" = set; then : $as_echo_n "(cached) " >&6 else # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5 $as_echo "$as_me: WARNING: can't find uname command" >&2;} tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5 $as_echo "$tcl_cv_sys_version" >&6; } system=$tcl_cv_sys_version # Require ranlib early so we can override it in special cases below. # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O if test "$GCC" = yes; then : # TEA specific: CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" else CFLAGS_WARNING="" fi CC_OBJNAME="-o \$@" # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AR+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" if test "x$SHLIB_VERSION" = x; then : SHLIB_VERSION="1.0" fi case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test ! -d "${PATH64}" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&5 $as_echo "$as_me: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ensure latest Platform SDK is installed" >&5 $as_echo "$as_me: WARNING: Ensure latest Platform SDK is installed" >&2;} do64bit="no" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using 64-bit $MACHINE mode" >&5 $as_echo " Using 64-bit $MACHINE mode" >&6; } do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then as_fn_error $? "Windows/CE and 64-bit builds incompatible" "$LINENO" 5 fi if test "$GCC" = "yes" ; then as_fn_error $? "Windows/CE and GCC builds incompatible" "$LINENO" 5 fi # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true # Check whether --with-celib was given. if test "${with_celib+set}" = set; then : withval=$with_celib; with_celibconfig=${withval} fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Windows/CE celib directory" >&5 $as_echo_n "checking for Windows/CE celib directory... " >&6; } if test "${ac_cv_c_celibconfig+set}" = set; then : $as_echo_n "(cached) " >&6 else # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else as_fn_error $? "${with_celibconfig} directory doesn't contain inc directory" "$LINENO" 5 fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[0-9]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[0-9]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi fi if test x"${ac_cv_c_celibconfig}" = x ; then as_fn_error $? "Cannot find celib support library directory" "$LINENO" 5 else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: found $CELIB_DIR" >&5 $as_echo "found $CELIB_DIR" >&6; } fi fi # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length($1)) { printf "CEVERSION=\"%s\"\n", $1; \ if ($1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length($2)) { printf "TARGETCPU=\"%s\"\n", toupper($2) }; \ if (length($3)) { printf "ARCH=\"%s\"\n", toupper($3) }; \ if (length($4)) { printf "PLATFORM=\"%s\"\n", $4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then as_fn_error $? "could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" "$LINENO" 5 doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 vars="bufferoverflowU.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower($0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do cat >>confdefs.h <<_ACEOF #define $i 1 _ACEOF done cat >>confdefs.h <<_ACEOF #define _WIN32_WCE $CEVERSION _ACEOF cat >>confdefs.h <<_ACEOF #define UNDER_CE $CEVERSION _ACEOF CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" else RC="rc" lflags="-nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode if test x"${RC}" = x ; then RC="windres" fi CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD="$CC -shared" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" CFLAGS_DEBUG="${CFLAGS_DEBUG} -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE" CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE" CC_OBJNAME="-Fo\$@" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"; then : # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([^ ]*\)/\1_r/'` ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using $CC for compiling with threads" >&5 $as_echo "Using $CC for compiling with threads" >&6; } fi LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes; then : if test "$GCC" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} else do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" fi fi if test "`uname -m`" = ia64; then : # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" if test "$GCC" = yes; then : CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' else CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' else if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared -Wl,-bexpall' else SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" fi SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lbind" >&5 $as_echo_n "checking for inet_ntoa in -lbind... " >&6; } if test "${ac_cv_lib_bind_inet_ntoa+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbind $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_ntoa (); int main () { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bind_inet_ntoa=yes else ac_cv_lib_bind_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bind_inet_ntoa" >&5 $as_echo "$ac_cv_lib_bind_inet_ntoa" >&6; } if test "x$ac_cv_lib_bind_inet_ntoa" = x""yes; then : LIBS="$LIBS -lbind -lsocket" fi ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" EXE_SUFFIX=".exe" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnetwork" >&5 $as_echo_n "checking for inet_ntoa in -lnetwork... " >&6; } if test "${ac_cv_lib_network_inet_ntoa+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnetwork $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_ntoa (); int main () { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_network_inet_ntoa=yes else ac_cv_lib_network_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_network_inet_ntoa" >&5 $as_echo "$ac_cv_lib_network_inet_ntoa" >&6; } if test "x$ac_cv_lib_network_inet_ntoa" = x""yes; then : LIBS="$LIBS -lnetwork" fi ;; HP-UX-*.11.*) # Use updated header definitions where possible $as_echo "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library if test "`uname -m`" = ia64; then : SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi else SHLIB_SUFFIX=".sl" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if test "${ac_cv_lib_dld_shl_load+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = yes; then : LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else CFLAGS="$CFLAGS -z" # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes"; then : if test "$GCC" = yes; then : case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} ;; esac else do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" fi fi ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = yes; then : CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" else case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" fi ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes; then : if test "$GCC" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported by gcc" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported by gcc" >&2;} else do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" fi fi ;; Linux*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "`uname -m`" = "alpha"; then : CFLAGS="$CFLAGS -mieee" fi if test $do64bit = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -m64 flag" >&5 $as_echo_n "checking if compiler accepts -m64 flag... " >&6; } if test "${tcl_cv_cc_m64+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_m64=yes else tcl_cv_cc_m64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_m64" >&5 $as_echo "$tcl_cv_cc_m64" >&6; } if test $tcl_cv_cc_m64 = yes; then : CFLAGS="$CFLAGS -m64" do64bit_ok=yes fi fi # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. if test x"${USE_COMPAT}" != x; then : CFLAGS="$CFLAGS -fno-inline" fi ;; GNU*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" if test "`uname -m`" = "alpha"; then : CFLAGS="$CFLAGS -mieee" fi ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi ;; OpenBSD-*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF" >&5 $as_echo_n "checking for ELF... " >&6; } if test "${tcl_cv_ld_elf+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __ELF__ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : tcl_cv_ld_elf=yes else tcl_cv_ld_elf=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_elf" >&5 $as_echo "$tcl_cv_ld_elf" >&6; } if test $tcl_cv_ld_elf = yes; then : LDFLAGS=-Wl,-export-dynamic else LDFLAGS="" fi if test "${TCL_THREADS}" = "1"; then : # OpenBSD builds and links with -pthread, never -lpthread. LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" SHLIB_CFLAGS="$SHLIB_CFLAGS -pthread" fi # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*|FreeBSD-[3-4].*) # FreeBSD 3.* and greater have ELF. # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "${TCL_THREADS}" = "1"; then : # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" TCL_SHLIB_LD_EXTRAS="-soname \$@" SHLIB_SUFFIX=".so" LDFLAGS="" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "${TCL_THREADS}" = "1"; then : # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS" fi # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ($i~/^(isysroot|mmacosx-version-min)/) print "-"$i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!($i~/^(isysroot|mmacosx-version-min)/)) print "-"$i}'`" if test $do64bit = yes; then : case `arch` in ppc) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch ppc64 flag" >&5 $as_echo_n "checking if compiler accepts -arch ppc64 flag... " >&6; } if test "${tcl_cv_cc_arch_ppc64+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_arch_ppc64=yes else tcl_cv_cc_arch_ppc64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_ppc64" >&5 $as_echo "$tcl_cv_cc_arch_ppc64" >&6; } if test $tcl_cv_cc_arch_ppc64 = yes; then : CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes fi;; i386) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch x86_64 flag" >&5 $as_echo_n "checking if compiler accepts -arch x86_64 flag... " >&6; } if test "${tcl_cv_cc_arch_x86_64+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_cc_arch_x86_64=yes else tcl_cv_cc_arch_x86_64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS=$hold_cflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_cc_arch_x86_64" >&5 $as_echo "$tcl_cv_cc_arch_x86_64" >&6; } if test $tcl_cv_cc_arch_x86_64 = yes; then : CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes fi;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&5 $as_echo "$as_me: WARNING: Don't know how enable 64-bit on architecture \`arch\`" >&2;};; esac else # Check for combined 32-bit and 64-bit fat build if echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '; then : fat_32_64=yes fi fi # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -single_module flag" >&5 $as_echo_n "checking if ld accepts -single_module flag... " >&6; } if test "${tcl_cv_ld_single_module+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_ld_single_module=yes else tcl_cv_ld_single_module=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_single_module" >&5 $as_echo "$tcl_cv_ld_single_module" >&6; } if test $tcl_cv_ld_single_module = yes; then : SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi # TEA specific: link shlib with current and compatiblity version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([0-9]\{1,5\}\)\(\(\.[0-9]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" # Don't use -prebind when building for Mac OS X 10.4 or later only: if test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int($2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4; then : LDFLAGS="$LDFLAGS -prebind" fi LDFLAGS="$LDFLAGS -headerpad_max_install_names" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5 $as_echo_n "checking if ld accepts -search_paths_first flag... " >&6; } if test "${tcl_cv_ld_search_paths_first+set}" = set; then : $as_echo_n "(cached) " >&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int i; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_ld_search_paths_first=yes else tcl_cv_ld_search_paths_first=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_ld_search_paths_first" >&5 $as_echo "$tcl_cv_ld_search_paths_first" >&6; } if test $tcl_cv_ld_search_paths_first = yes; then : LDFLAGS="$LDFLAGS -Wl,-search_paths_first" fi if test "$tcl_cv_cc_visibility_hidden" != yes; then : $as_echo "#define MODULE_SCOPE __private_extern__" >>confdefs.h tcl_cv_cc_visibility_hidden=yes fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. if test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"; then : if test "${TEA_WINDOWINGSYSTEM}" = x11; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit X11" >&5 $as_echo_n "checking for 64-bit X11... " >&6; } if test "${tcl_cv_lib_x11_64+set}" = set; then : $as_echo_n "(cached) " >&6 else for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize(); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_lib_x11_64=yes else tcl_cv_lib_x11_64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_x11_64" >&5 $as_echo "$tcl_cv_lib_x11_64" >&6; } fi if test "${TEA_WINDOWINGSYSTEM}" = aqua; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit Tk" >&5 $as_echo_n "checking for 64-bit Tk... " >&6; } if test "${tcl_cv_lib_tk_64+set}" = set; then : $as_echo_n "(cached) " >&6 else for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { Tk_InitStubs(NULL, "", 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : tcl_cv_lib_tk_64=yes else tcl_cv_lib_tk_64=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_lib_tk_64" >&5 $as_echo "$tcl_cv_lib_tk_64" >&6; } fi # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. if test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no; then : { $as_echo "$as_me:${as_lineno-$LINENO}: Removing 64-bit architectures from compiler & linker flags" >&5 $as_echo "$as_me: Removing 64-bit architectures from compiler & linker flags" >&6;} for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done fi fi ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy $as_echo "#define _OE_SOCKETS 1" >>confdefs.h ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" if test "$SHARED_BUILD" = 1; then : SHLIB_LD='ld -shared -expect_unresolved "*"' else SHLIB_LD='ld -non_shared -expect_unresolved "*"' fi SHLIB_SUFFIX=".so" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' fi if test "$GCC" = yes; then : CFLAGS="$CFLAGS -mieee" else CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" fi # see pthread_intro(3) for pthread support on osf1, k.furukawa if test "${TCL_THREADS}" = 1; then : CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` if test "$GCC" = yes; then : LIBS="$LIBS -lpthread -lmach -lexc" else CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi fi ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) if test "$GCC" = yes; then : SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" else SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" fi SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[0-6]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. $as_echo "#define _REENTRANT 1" >>confdefs.h $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. $as_echo "#define _REENTRANT 1" >>confdefs.h $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = yes; then : arch=`isainfo` if test "$arch" = "sparcv9 sparc"; then : if test "$GCC" = yes; then : if test "`${CC} -dumpversion | awk -F. '{print $1}'`" -lt 3; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&2;} else do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" fi else do64bit_ok=yes if test "$do64bitVIS" = yes; then : CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" else CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" fi # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" fi else if test "$arch" = "amd64 i386"; then : if test "$GCC" = yes; then : case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported with GCC on $system" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;};; esac else do64bit_ok=yes case $system in SunOS-5.1[1-9]*|SunOS-5.[2-9][0-9]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit mode not supported for $arch" >&5 $as_echo "$as_me: WARNING: 64bit mode not supported for $arch" >&2;} fi fi fi SHLIB_SUFFIX=".so" if test "$GCC" = yes; then : SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$do64bit_ok" = yes; then : if test "$arch" = "sparcv9 sparc"; then : # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" else if test "$arch" = "amd64 i386"; then : # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" fi fi fi else case $system in SunOS-5.[1-9][0-9]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' fi ;; esac if test "$do64bit" = yes -a "$do64bit_ok" = no; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 64bit support being disabled -- don't know magic for this platform" >&5 $as_echo "$as_me: WARNING: 64bit support being disabled -- don't know magic for this platform" >&2;} fi # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. if test "$GCC" = yes; then : case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi if test "$tcl_cv_cc_visibility_hidden" != yes; then : $as_echo "#define MODULE_SCOPE extern" >>confdefs.h $as_echo "#define NO_VIZ /**/" >>confdefs.h fi if test "$SHARED_LIB_SUFFIX" = ""; then : # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' fi if test "$UNSHARED_LIB_SUFFIX" = ""; then : # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' fi # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary { $as_echo "$as_me:${as_lineno-$LINENO}: checking for required early compiler flags" >&5 $as_echo_n "checking for required early compiler flags... " >&6; } tcl_flags="" if test "${tcl_cv_flag__isoc99_source+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__isoc99_source=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _ISOC99_SOURCE 1 #include int main () { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__isoc99_source=yes else tcl_cv_flag__isoc99_source=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__isoc99_source}" = "xyes" ; then $as_echo "#define _ISOC99_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _ISOC99_SOURCE" fi if test "${tcl_cv_flag__largefile64_source+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile64_source=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE64_SOURCE 1 #include int main () { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile64_source=yes else tcl_cv_flag__largefile64_source=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile64_source}" = "xyes" ; then $as_echo "#define _LARGEFILE64_SOURCE 1" >>confdefs.h tcl_flags="$tcl_flags _LARGEFILE64_SOURCE" fi if test "${tcl_cv_flag__largefile_source64+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *p = (char *)open64; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile_source64=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE64 1 #include int main () { char *p = (char *)open64; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_flag__largefile_source64=yes else tcl_cv_flag__largefile_source64=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then $as_echo "#define _LARGEFILE_SOURCE64 1" >>confdefs.h tcl_flags="$tcl_flags _LARGEFILE_SOURCE64" fi if test "x${tcl_flags}" = "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_flags}" >&5 $as_echo "${tcl_flags}" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit integer type" >&5 $as_echo_n "checking for 64-bit integer type... " >&6; } if test "${tcl_cv_type_64bit+set}" = set; then : $as_echo_n "(cached) " >&6 else tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { __int64 value = (__int64) 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_type_64bit=__int64 else tcl_type_64bit="long long" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { switch (0) { case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; } ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_type_64bit=${tcl_type_64bit} fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "${tcl_cv_type_64bit}" = none ; then $as_echo "#define TCL_WIDE_INT_IS_LONG 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: using long" >&5 $as_echo "using long" >&6; } elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* { $as_echo "$as_me:${as_lineno-$LINENO}: result: using Tcl header defaults" >&5 $as_echo "using Tcl header defaults" >&6; } else cat >>confdefs.h <<_ACEOF #define TCL_WIDE_INT_TYPE ${tcl_cv_type_64bit} _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${tcl_cv_type_64bit}" >&5 $as_echo "${tcl_cv_type_64bit}" >&6; } # Now check for auxiliary declarations { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct dirent64" >&5 $as_echo_n "checking for struct dirent64... " >&6; } if test "${tcl_cv_struct_dirent64+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct dirent64 p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_struct_dirent64=yes else tcl_cv_struct_dirent64=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_dirent64" >&5 $as_echo "$tcl_cv_struct_dirent64" >&6; } if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then $as_echo "#define HAVE_STRUCT_DIRENT64 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct stat64" >&5 $as_echo_n "checking for struct stat64... " >&6; } if test "${tcl_cv_struct_stat64+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct stat64 p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_struct_stat64=yes else tcl_cv_struct_stat64=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_struct_stat64" >&5 $as_echo "$tcl_cv_struct_stat64" >&6; } if test "x${tcl_cv_struct_stat64}" = "xyes" ; then $as_echo "#define HAVE_STRUCT_STAT64 1" >>confdefs.h fi for ac_func in open64 lseek64 do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for off64_t" >&5 $as_echo_n "checking for off64_t... " >&6; } if test "${tcl_cv_type_off64_t+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { off64_t offset; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : tcl_cv_type_off64_t=yes else tcl_cv_type_off64_t=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then $as_echo "#define HAVE_TYPE_OFF64_T 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for build with symbols" >&5 $as_echo_n "checking for build with symbols... " >&6; } # Check whether --enable-symbols was given. if test "${enable_symbols+set}" = set; then : enableval=$enable_symbols; tcl_ok=$enableval else tcl_ok=no fi DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (standard debugging)" >&5 $as_echo "yes (standard debugging)" >&6; } fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then $as_echo "#define TCL_MEM_DEBUG 1" >>confdefs.h fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled symbols mem debugging" >&5 $as_echo "enabled symbols mem debugging" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled $tcl_ok debugging" >&5 $as_echo "enabled $tcl_ok debugging" >&6; } fi fi if test "${enable_symbols+set}" = set && test "$enable_symbols" != no; then PKG_CFLAGS="$PKG_CFLAGS -DTREECTRL_DEBUG" fi #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- $as_echo "#define USE_TCL_STUBS 1" >>confdefs.h $as_echo "#define USE_TK_STUBS 1" >>confdefs.h #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\$@ \$(PKG_OBJECTS)" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "manifest needed" >/dev/null 2>&1; then : # Could do a CHECK_PROG for mt, but should always be with MSVC8+ VC_MANIFEST_EMBED_DLL="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest \$(PKG_MANIFEST) -outputresource:\$@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest \$(PKG_MANIFEST) -outputresource:\$@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" # Don't clean .manifest provided by the package (see TEA_ADD_MANIFEST) # or one created by Makefile or configure. Could use the /manifest:filename # linker option to explicitly set the linker-generated filename. eval eval "manifest=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}.manifest" CLEANFILES="$CLEANFILES $manifest" fi rm -f conftest* MAKE_STUB_LIB="\${STLIB_LD} -out:\$@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \$@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi #-------------------------------------------------------------------- # Find tclsh so that we can run pkg_mkIndex to generate the pkgIndex.tcl # file during the install process. Don't run the TCLSH_PROG through # ${CYGPATH} because it's being used directly by make. # Require that we use a tclsh shell version 8.2 or later since earlier # versions have bugs in the pkg_mkIndex routine. # Add WISH as well if this is a Tk extension. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tclsh" >&5 $as_echo_n "checking for tclsh... " >&6; } if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${TCLSH_PROG}" >&5 $as_echo "${TCLSH_PROG}" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wish" >&5 $as_echo_n "checking for wish... " >&6; } if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${WISH_PROG}" >&5 $as_echo "${WISH_PROG}" >&6; } #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- ac_config_files="$ac_config_files $OUTPUTFILES" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS="" : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by shellicon $as_me 2.4, which was generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ shellicon config.status 2.4 configured by $0, generated by GNU Autoconf 2.67, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "$OUTPUTFILES") CONFIG_FILES="$CONFIG_FILES $OUTPUTFILES" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi tktreectrl-2.4.1/shellicon/configure.ac0000755000076400010400000002000111646370053020462 0ustar TimAdministrators#!/bin/bash -norc dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tcl installation dnl to configure the system for the local environment. #----------------------------------------------------------------------- # Sample configure.in for Tcl Extensions. # See the TEA sample extension for description of structure and items. #----------------------------------------------------------------------- #----------------------------------------------------------------------- # __CHANGE__ # This very first macro is used to verify that the configure script can # find the sources. The argument to AC_INIT should be a unique filename # for this package, and can be a relative path, such as: # # AC_INIT(generic/tcl.h) #----------------------------------------------------------------------- AC_INIT([shellicon], [2.4]) AC_SUBST([PACKAGE_PATCHLEVEL], [2.4.1]) AC_DEFINE_UNQUOTED(PACKAGE_PATCHLEVEL, "$PACKAGE_PATCHLEVEL") TEA_INIT([3.9]) AC_CONFIG_AUX_DIR(tclconfig) #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- TEA_PATH_TCLCONFIG TEA_LOAD_TCLCONFIG #-------------------------------------------------------------------- # Load the tkConfig.sh file if necessary (Tk extension) #-------------------------------------------------------------------- TEA_PATH_TKCONFIG TEA_LOAD_TKCONFIG #----------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- TEA_PREFIX #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- TEA_SETUP_COMPILER #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- TEA_ADD_SOURCES([shellicon.c]) TEA_ADD_HEADERS([]) TEA_ADD_INCLUDES([-I\"`${CYGPATH} ${srcdir}/../generic`\"]) TEA_ADD_CFLAGS([]) TEA_ADD_STUB_SOURCES([]) TEA_ADD_TCL_SOURCES([]) #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG #-------------------------------------------------------------------- #TEA_PUBLIC_TCL_HEADERS TEA_PRIVATE_TCL_HEADERS #TEA_PUBLIC_TK_HEADERS TEA_PRIVATE_TK_HEADERS #-------------------------------------------------------------------- # For Unix/Tk builds, make sure that the X libraries/headers are found. #-------------------------------------------------------------------- TEA_PATH_X # Needed for OS X ppx/intel image handling AC_C_BIGENDIAN #-------------------------------------------------------------------- # __CHANGE__ # A few miscellaneous platform-specific items: # # Define a special symbol for Windows (BUILD_sample in this case) so # that we create the export library with the dll. See sha1.h on how # to use this. # # Windows creates a few extra files that need to be cleaned up. # You can add more files to clean if your extension creates any extra # files. # # Define any extra compiler flags in the PACKAGE_CFLAGS variable. # These will be appended to the current set of compiler flags for # your system. #-------------------------------------------------------------------- OUTPUTFILES=Makefile if test "${TEA_PLATFORM}" = "windows" ; then TEA_ADD_LIBS([gdi32.lib user32.lib comctl32.lib ole32.lib shell32.lib]) # Find rc.exe or windres.exe. # Defined in winrc.m4. TREECTRL_PROG_RC # X86|AMD64|IA64 for manifest AC_SUBST(MACHINE) # PKG_MANIFEST -> VC_MANIFEST_EMBED_DLL -> MAKE_SHARED_LIB TEA_ADD_MANIFEST([shellicon.dll.manifest]) # Create shellicon.dll.manifest from shellicon.dll.manifest.in. # shellicon.dll.manifest is included by shellicon.rc. # If building with a Microsoft compiler that generates # shelliconNN.dll.manifest (to pick the correct MSVCRT runtime) then # that manifest is merged with mine using mt.exe (see the Makefile # rule for PKG_LIB_FILE). OUTPUTFILES="Makefile shellicon.dll.manifest" TREECTRL_ADD_RC([shellicon.rc]) fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TEA_ADD_LIBS([-framework Carbon]) fi #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. #-------------------------------------------------------------------- TEA_ENABLE_THREADS #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- TEA_ENABLE_SHARED #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- TEA_CONFIG_CFLAGS #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- TEA_ENABLE_SYMBOLS if test "${enable_symbols+set}" = set && test "$enable_symbols" != no; then TEA_ADD_CFLAGS([-DTREECTRL_DEBUG]) fi #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- AC_DEFINE(USE_TCL_STUBS) AC_DEFINE(USE_TK_STUBS) #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- TEA_MAKE_LIB #-------------------------------------------------------------------- # Find tclsh so that we can run pkg_mkIndex to generate the pkgIndex.tcl # file during the install process. Don't run the TCLSH_PROG through # ${CYGPATH} because it's being used directly by make. # Require that we use a tclsh shell version 8.2 or later since earlier # versions have bugs in the pkg_mkIndex routine. # Add WISH as well if this is a Tk extension. #-------------------------------------------------------------------- TEA_PROG_TCLSH TEA_PROG_WISH #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- AC_OUTPUT([$OUTPUTFILES]) tktreectrl-2.4.1/shellicon/Makefile.in0000644000076400010400000003664411562310655020261 0ustar TimAdministrators# Makefile.in -- # # This file is a Makefile for Sample TEA Extension. If it has the name # "Makefile.in" then it is a template for a Makefile; to generate the # actual Makefile, run "./configure", which is a configuration script # generated by the "autoconf" program (constructs like "@foo@" will get # replaced in the actual Makefile. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 2002 ActiveState SRL. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. #======================================================================== # Edit the following few lines when writing a new extension #======================================================================== #======================================================================== # Nothing of the variables below this line need to be changed. Please # check the TARGETS section below to make sure the make targets are # correct. #======================================================================== #======================================================================== # The names of the source files is defined in the configure script. # The object files are used for linking into the final library. # This will be used when a dist target is added to the Makefile. # It is not important to specify the directory, as long as it is the # $(srcdir) or in the generic, win or unix subdirectory. #======================================================================== PKG_SOURCES = @PKG_SOURCES@ PKG_OBJECTS = @PKG_OBJECTS@ #======================================================================== # PKG_TCL_SOURCES identifies Tcl runtime files that are associated with # this package that need to be installed, if any. #======================================================================== PKG_TCL_SOURCES = @PKG_TCL_SOURCES@ #======================================================================== # This is a list of public header files to be installed, if any. #======================================================================== PKG_HEADERS = @PKG_HEADERS@ PKG_EXTRA_FILES = PKG_MAN_PAGES = PKG_MANIFEST = @PKG_MANIFEST@ #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== PKG_LIB_FILE = @PKG_LIB_FILE@ PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ lib_BINARIES = $(PKG_LIB_FILE) BINARIES = $(lib_BINARIES) pkgIndex.tcl SHELL = @SHELL@ srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ datadir = @datadir@ datarootdir = @datarootdir@ mandir = @mandir@ includedir = @includedir@ DESTDIR = TREECTRL_DIR = $(libdir)/treectrl$(PACKAGE_PATCHLEVEL) PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_PATCHLEVEL) pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(TREECTRL_DIR)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) top_builddir = . INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ PACKAGE_PATCHLEVEL = @PACKAGE_PATCHLEVEL@ CC = @CC@ CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ CFLAGS_WARNING = @CFLAGS_WARNING@ CC_OBJNAME = @CC_OBJNAME@ CLEANFILES = @CLEANFILES@ EXEEXT = @EXEEXT@ LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ MAKE_LIB = @MAKE_LIB@ MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ MAKE_STUB_LIB = @MAKE_STUB_LIB@ OBJEXT = @OBJEXT@ RANLIB = @RANLIB@ RANLIB_STUB = @RANLIB_STUB@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ SHLIB_LD = @SHLIB_LD@ SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ STLIB_LD = @STLIB_LD@ TCL_DEFS = @TCL_DEFS@ TCL_SRC_DIR = @TCL_SRC_DIR@ TCL_BIN_DIR = @TCL_BIN_DIR@ TK_SRC_DIR = @TK_SRC_DIR@ TK_BIN_DIR = @TK_BIN_DIR@ # Not used, but retained for reference of what libs Tcl required TCL_LIBS = @TCL_LIBS@ TK_LIBS = @TK_LIBS@ #======================================================================== # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our # package without installing. The other environment variables allow us # to test against an uninstalled Tcl. Add special env vars that you # require for testing here (like TCLX_LIBRARY). #======================================================================== EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR) TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \ TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` \ TREECTRL_LIBRARY=`@CYGPATH@ $(srcdir)/library` \ @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ PATH="$(EXTRA_PATH):$(PATH)" \ TCLLIBPATH="$(top_builddir)" TCLSH_PROG = @TCLSH_PROG@ WISH_PROG = @WISH_PROG@ TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) WISH = $(TCLSH_ENV) $(WISH_PROG) # The local includes must come first, because the TK_XINCLUDES can be # just a comment INCLUDES = @PKG_INCLUDES@ \ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ PKG_CFLAGS = @PKG_CFLAGS@ DEFS = @DEFS@ $(PKG_CFLAGS) CONFIG_CLEAN_FILES = Makefile $(PKG_MANIFEST) CPPFLAGS = @CPPFLAGS@ LIBS = @PKG_LIBS@ @LIBS@ AR = @AR@ CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #======================================================================== # Start of user-definable TARGETS section #======================================================================== #======================================================================== # TEA TARGETS. Please note that the "libraries:" target refers to platform # independent files, and the "binaries:" target inclues executable programs and # platform-dependent libraries. Modify these targets so that they install # the various pieces of your package. The make and install rules # for the BINARIES that you specified above have already been done. #======================================================================== all: binaries libraries doc #======================================================================== # The binaries target builds executable programs, Windows .dll's, unix # shared/static libraries, and any other platform-dependent files. # The list of targets to build for "binaries:" is specified at the top # of the Makefile, in the "BINARIES" variable. #======================================================================== binaries: $(BINARIES) libraries: doc-x: @echo "If you have documentation to create, place the commands to" @echo "build the docs in the 'doc:' target. For example:" @echo " xml2nroff sample.xml > sample.n" @echo " xml2html sample.xml > sample.html" doc: @echo "No docs to build" install: all install-binaries install-libraries install-binaries: binaries install-lib-binaries install-bin-binaries @mkdir -p $(DESTDIR)$(pkglibdir) $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir) @list='$(PKG_EXTRA_FILES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`; \ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ fi; \ done #======================================================================== # This rule installs platform-independent files, such as header files. #======================================================================== install-libraries: libraries #======================================================================== # Install documentation. Unix manpages should go in the $(mandir) # directory. #======================================================================== install-doc-x: @mkdir -p $(DESTDIR)$(mandir)/mann @echo "Installing documentation in $(DESTDIR)$(mandir)" @for i in $(srcdir)/doc/*.n; do \ echo "Installing $$i"; \ rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \ $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ done install-doc: install-doc-x mkdir -p $(DESTDIR)$(pkglibdir)/htmldoc cp $(srcdir)/doc/*.html $(DESTDIR)$(pkglibdir)/htmldoc test: binaries libraries $(WISH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) | cat shell: binaries libraries @$(WISH) $(SCRIPT) demo: binaries libraries @$(WISH) `@CYGPATH@ $(srcdir)/demos/demo.tcl` | cat gdb: $(TCLSH_ENV) gdb --silent --args $(WISH_PROG) $(srcdir)/demos/demo.tcl depend: #======================================================================== # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable # mentioned above. That will ensure that this target is built when you # run "make binaries". # # The $(PKG_OBJECTS) objects are created and linked into the final # library. In most cases these object files will correspond to the # source files above. # # NOTE regarding the manifest(s): When building on a non-Windows box the # shelliconNN.dll.manifest file should not exist. When building with # MingW GCC the manifest will also not exist. Only when building with # a Microsoft compiler that auto-generates a manifest (to pick the correct # MSVCRT runtime) will $@.manifest exist; in this case mt.exe should # also exist. If mt.exe is used there is actually no need for shellicon.rc # to include shellicon.dll.manifest since mt.exe will clobber that resource # with the merged manifests. #======================================================================== $(PKG_LIB_FILE): $(PKG_OBJECTS) -rm -f $(PKG_LIB_FILE) ${MAKE_LIB} $(RANLIB) $(PKG_LIB_FILE) #======================================================================== # In the following lines, $(srcdir) refers to the toplevel directory # containing your extension. If your sources are in a subdirectory, # you will have to modify the paths to reflect this: # # tkpkg.$(OBJEXT): $(srcdir)/src/win/tkpkg.c # $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/tkpkg.c` -o $@ # # Setting the VPATH variable to a list of paths will cause the # makefile to look into these paths when resolving .c to .obj # dependencies. #======================================================================== # I added leading $(srcdir) because autoconf 2.53 strips it off VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win .c.@OBJEXT@: $(COMPILE) -c `@CYGPATH@ $<` $(CC_OBJNAME) .rc.@RES@: @RC@ @RC_OUT@ $@ @RC_INCLUDE@ "`@CYGPATH@ $(srcdir)`" @RC_DEPARG@ #======================================================================== # Create the pkgIndex.tcl file. #======================================================================== pkgIndex.tcl: (\ echo 'if {[catch {package require Tcl @TK_VERSION@}]} return';\ echo 'set script "load \"[file join $$dir $(PKG_LIB_FILE)]\" $(PACKAGE_NAME)"';\ echo 'package ifneeded $(PACKAGE_NAME) $(PACKAGE_PATCHLEVEL) $$script'\ ) > pkgIndex.tcl #======================================================================== # Distribution creation # You may need to tweak this target to make it work correctly. #======================================================================== #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar COMPRESS = gtar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) DIST_ROOT = /tmp/dist DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* dist: dist-clean mkdir -p $(DIST_DIR) cp -p $(srcdir)/shellicon.c \ $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.ac \ $(srcdir)/*.in $(DIST_DIR)/ chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4 chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.ac cp -p $(srcdir)/*.[ch] $(DIST_DIR)/ mkdir $(DIST_DIR)/tclconfig cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ $(DIST_DIR)/tclconfig/ chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 chmod +x $(DIST_DIR)/tclconfig/install-sh list='demos doc generic library mac tests unix win'; \ for p in $$list; do \ if test -d $(srcdir)/$$p ; then \ mkdir $(DIST_DIR)/$$p; \ cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ fi; \ done (cd $(DIST_ROOT); $(COMPRESS);) #======================================================================== # End of user-definable section #======================================================================== #======================================================================== # Don't modify the file to clean here. Instead, set the "CLEANFILES" # variable in configure.in #======================================================================== clean: -test -z "$(BINARIES)" || rm -f $(BINARIES) -rm -f *.$(OBJEXT) core *.core -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean: clean -rm -f *.tab.c -rm -f $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log config.status #======================================================================== # Install binary object libraries. On Windows this includes both .dll and # .lib files. Because the .lib files are not explicitly listed anywhere, # we need to deduce their existence from the .dll file of the same name. # Library files go into the lib directory. # In addition, this will generate the pkgIndex.tcl # file in the install location (assuming it can find a usable tclsh shell) # # You should not have to modify this target. #======================================================================== install-lib-binaries: @mkdir -p $(DESTDIR)$(pkglibdir) @list='$(lib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \ echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ ext=`echo $$p|sed -e "s/.*\.//"`; \ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ fi; \ fi; \ fi; \ done @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`; \ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ fi; \ done #======================================================================== # Install binary executables (e.g. .exe files and dependent .dll files) # This is for files that must go in the bin directory (located next to # wish and tclsh), like dependent .dll files on Windows. # # You should not have to modify this target, except to define bin_BINARIES # above if necessary. #======================================================================== install-bin-binaries: @mkdir -p $(DESTDIR)$(bindir) @list='$(bin_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ fi; \ done .SUFFIXES: .c .$(OBJEXT) .SUFFIXES: .@RES@ .SUFFIXES: .rc Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status uninstall-binaries: list='$(lib_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ p=`basename $$p`; \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(bin_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(bindir)/$$p; \ done .PHONY: all binaries clean depend distclean doc install libraries test # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tktreectrl-2.4.1/shellicon/shellicon.c0000644000076400010400000005752111562310667020340 0ustar TimAdministrators/* * shellicon.c -- * * This is a Tk extension that adds a new element type to TkTreeCtrl. * The element type's name is "shellicon". A shellicon element can * display the icon for a file or folder using Win32 Shell API calls. * * Copyright (c) 2005-2011 Tim Baker */ #include "tkTreeCtrl.h" #include "tkTreeElem.h" #include "tkWinInt.h" #ifndef _WIN32_IE #define _WIN32_IE 0x0501 #endif #include #include #include #include #ifndef SHGFI_ADDOVERLAYS #if (_WIN32_IE >= 0x0500) #define SHGFI_ADDOVERLAYS 0x000000020 #define SHGFI_OVERLAYINDEX 0x000000040 #endif #endif #ifndef SHIL_LARGE #define SHIL_LARGE 0 #define SHIL_SMALL 1 #define SHIL_EXTRALARGE 2 #if 0 const GUID IID_IImageList = {0x2C247F21, 0x8591, 0x11D1,{ 0xB1, 0x6A, 0x00,0xC0, 0xF0, 0x28,0x36, 0x28} }; HRESULT (*SHGetImageListProc)(int iImageList, REFIID riid, void **ppv); #endif #endif HIMAGELIST gImgListSmall = NULL; HIMAGELIST gImgListLarge = NULL; TreeCtrlStubs *stubs; #define TreeCtrl_RegisterElementType(i,t) \ stubs->TreeCtrl_RegisterElementType(i,t) #define Tree_RedrawElement(t,i,e) \ stubs->Tree_RedrawElement(t,i,e) #define Tree_ElementIterateBegin(t,et) \ stubs->Tree_ElementIterateBegin(t,et) #define Tree_ElementIterateNext(i) \ stubs->Tree_ElementIterateNext(i) #define Tree_ElementIterateGet(i) \ stubs->Tree_ElementIterateGet(i) #define Tree_ElementIterateChanged(i,m) \ stubs->Tree_ElementIterateChanged(i,m) #define PerStateInfo_Free(t,ty,in) \ stubs->PerStateInfo_Free(t,ty,in) #define PerStateInfo_FromObj(t,pr,ty,in) \ stubs->PerStateInfo_FromObj(t,pr,ty,in) #define PerStateInfo_ForState(t,ty,in,st,ma) \ stubs->PerStateInfo_ForState(t,ty,in,st,ma) #define PerStateInfo_ObjForState(t,ty,in,st,ma) \ stubs->PerStateInfo_ObjForState(t,ty,in,st,ma) #define PerStateInfo_Undefine(t,ty,in,dom,st) \ stubs->PerStateInfo_Undefine(t,ty,in,dom,st) #undef pstBoolean #define pstBoolean \ (*stubs->TreeCtrl_pstBoolean) #define PerStateBoolean_ForState(t,in,st,ma) \ stubs->PerStateBoolean_ForState(t,in,st,ma) #define PSTSave(in,sa) \ stubs->PSTSave(in,sa) #define PSTRestore(t,ty,in,sa) \ stubs->PSTRestore(t,ty,in,sa) #define TreeStateFromObj \ stubs->TreeStateFromObj #define BooleanCO_Init(ot,on) \ stubs->BooleanCO_Init(ot,on) #define StringTableCO_Init(ot,on,ta) \ stubs->StringTableCO_Init(ot,on,ta) #define PerStateCO_Init(a,b,c,d) \ stubs->PerStateCO_Init(a,b,c,d) static void AdjustForSticky(int sticky, int cavityWidth, int cavityHeight, int expandX, int expandY, int *xPtr, int *yPtr, int *widthPtr, int *heightPtr) { int dx = 0; int dy = 0; if (cavityWidth > *widthPtr) { dx = cavityWidth - *widthPtr; } if (cavityHeight > *heightPtr) { dy = cavityHeight - *heightPtr; } if ((sticky & STICKY_W) && (sticky & STICKY_E)) { if (expandX) *widthPtr += dx; else sticky &= ~(STICKY_W | STICKY_E); } if ((sticky & STICKY_N) && (sticky & STICKY_S)) { if (expandY) *heightPtr += dy; else sticky &= ~(STICKY_N | STICKY_S); } if (!(sticky & STICKY_W)) { *xPtr += (sticky & STICKY_E) ? dx : dx / 2; } if (!(sticky & STICKY_N)) { *yPtr += (sticky & STICKY_S) ? dy : dy / 2; } } /* This macro gets the value of a per-state option for an element, then * looks for a better match from the master element if it exists */ #define OPTION_FOR_STATE(xFUNC,xTYPE,xVAR,xFIELD,xSTATE) \ xVAR = xFUNC(tree, &elemX->xFIELD, xSTATE, &match); \ if ((match != MATCH_EXACT) && (masterX != NULL)) { \ xTYPE varM = xFUNC(tree, &masterX->xFIELD, xSTATE, &match2); \ if (match2 > match) \ xVAR = varM; \ } #define BOOLEAN_FOR_STATE(xVAR,xFIELD,xSTATE) \ OPTION_FOR_STATE(PerStateBoolean_ForState,int,xVAR,xFIELD,xSTATE) /* This macro gets the object for a per-state option for an element, then * looks for a better match from the master element if it exists */ #define OBJECT_FOR_STATE(xVAR,xTYPE,xFIELD,xSTATE) \ xVAR = PerStateInfo_ObjForState(tree, &xTYPE, &elemX->xFIELD, xSTATE, &match); \ if ((match != MATCH_EXACT) && (masterX != NULL)) { \ Tcl_Obj *objM = PerStateInfo_ObjForState(tree, &xTYPE, &masterX->xFIELD, xSTATE, &matchM); \ if (matchM > match) \ xVAR = objM; \ } typedef struct ElementShellIcon ElementShellIcon; struct ElementShellIcon { TreeElement_ header; #ifdef DEPRECATED PerStateInfo draw; #endif Tcl_Obj *pathObj; /* path of file or directory */ char *path; Tcl_Obj *widthObj; int width; Tcl_Obj *heightObj; int height; #define TYPE_DIRECTORY 0 #define TYPE_FILE 1 int type; /* If specified, 'path' is assumed to exist */ #define SIZE_LARGE 0 #define SIZE_SMALL 1 int size; /* SIZE_LARGE if unspecified */ HIMAGELIST hImgList; /* the system image list */ int iIcon; /* index into hImgList */ /* FIXME: overlays no longer work in Win7 */ int addOverlays; /* only when useImgList is FALSE */ int useImgList; /* if false, create icons */ #define USE_SEL_ALWAYS 0 /* always draw selected icon */ #define USE_SEL_AUTO 1 /* draw selected icon when item is selected */ #define USE_SEL_NEVER 2 /* never draw the selected icon */ int useSelected; /* when to draw the selected icon */ HICON hIcon; /* icon */ HICON hIconSel; /* selected icon */ }; #define SHELLICON_CONF_ICON 0x0001 #define SHELLICON_CONF_SIZE 0x0002 #define SHELLICON_CONF_DRAW 0x0004 static CONST char *sizeST[] = { "large", "small", (char *) NULL }; static CONST char *typeST[] = { "directory", "file", (char *) NULL }; static CONST char *useSelectedST[] = { "always", "auto", "never", (char *) NULL }; static Tk_OptionSpec shellIconOptionSpecs[] = { {TK_OPTION_CUSTOM, "-addoverlays", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementShellIcon, addOverlays), TK_OPTION_NULL_OK, (ClientData) NULL, SHELLICON_CONF_ICON}, #ifdef DEPRECATED {TK_OPTION_CUSTOM, "-draw", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementShellIcon, draw.obj), Tk_Offset(ElementShellIcon, draw), TK_OPTION_NULL_OK, (ClientData) NULL, SHELLICON_CONF_DRAW}, #endif {TK_OPTION_PIXELS, "-height", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementShellIcon, heightObj), Tk_Offset(ElementShellIcon, height), TK_OPTION_NULL_OK, (ClientData) NULL, SHELLICON_CONF_SIZE}, {TK_OPTION_STRING, "-path", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementShellIcon, pathObj), Tk_Offset(ElementShellIcon, path), TK_OPTION_NULL_OK, (ClientData) NULL, SHELLICON_CONF_ICON}, {TK_OPTION_CUSTOM, "-size",(char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementShellIcon, size), TK_OPTION_NULL_OK, (ClientData) NULL, SHELLICON_CONF_ICON}, {TK_OPTION_CUSTOM, "-type", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementShellIcon, type), TK_OPTION_NULL_OK, (ClientData) NULL, SHELLICON_CONF_ICON}, {TK_OPTION_CUSTOM, "-useimagelist", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementShellIcon, useImgList), TK_OPTION_NULL_OK, (ClientData) NULL, SHELLICON_CONF_ICON}, {TK_OPTION_CUSTOM, "-useselected", (char *) NULL, (char *) NULL, (char *) NULL, -1, Tk_Offset(ElementShellIcon, useSelected), TK_OPTION_NULL_OK, (ClientData) NULL, SHELLICON_CONF_DRAW}, {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL, (char *) NULL, Tk_Offset(ElementShellIcon, widthObj), Tk_Offset(ElementShellIcon, width), TK_OPTION_NULL_OK, (ClientData) NULL, SHELLICON_CONF_SIZE}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, -1, 0, (ClientData) NULL, 0} }; static void LoadIconIfNeeded(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementShellIcon *elemX = (ElementShellIcon *) elem; ElementShellIcon *masterX = (ElementShellIcon *) elem->master; SHFILEINFO sfi; Tcl_DString dString1, dString2; UINT uFlags = SHGFI_SYSICONINDEX; DWORD dwFileAttributes = 0; char *nativePath; int size = SIZE_LARGE; int overlays = 1; int type = -1; int useImgList = TRUE; DWORD_PTR result; /* -useimagelist boolean */ if (elemX->useImgList != -1) useImgList = elemX->useImgList; else if (masterX != NULL && masterX->useImgList != -1) useImgList = masterX->useImgList; /* Not using the system image list. */ if (!useImgList) { /* Already have an icon, or no path is given so no icon used */ if ((elemX->hIcon != NULL) || (elemX->path == NULL)) return; /* Equivalent to "file nativename $path" */ nativePath = Tcl_TranslateFileName(tree->interp, elemX->path, &dString1); if (nativePath == NULL) return; /* This will be passed to system calls, so convert from UTF8 */ nativePath = Tcl_UtfToExternalDString(NULL, nativePath, -1, &dString2); uFlags = SHGFI_ICON; /* -addoverlays boolean */ if (elemX->addOverlays != -1) overlays = elemX->addOverlays; else if (masterX != NULL && masterX->addOverlays != -1) overlays = masterX->addOverlays; if (overlays) uFlags |= SHGFI_ADDOVERLAYS; /* -size small or large */ if (elemX->size != -1) size = elemX->size; else if (masterX != NULL && masterX->size != -1) size = masterX->size; switch (size) { case SIZE_LARGE: uFlags |= SHGFI_LARGEICON | SHGFI_SHELLICONSIZE; break; case SIZE_SMALL: uFlags |= SHGFI_SMALLICON | SHGFI_SHELLICONSIZE; break; } /* -type file or -type directory */ if (elemX->type != -1) type = elemX->type; else if (masterX != NULL && masterX->type != -1) type = masterX->type; /* If SHGFI_USEFILEATTRIBUTES is set, SHGetFileInfo is supposed to * assume that the file is real but not look for it on disk. This * can be used to get the icon for a certain type of file, ex *.exe. * In practice, lots of files get a non-generic icon when a * valid file path is given. */ if (type != -1) { dwFileAttributes = (type == TYPE_FILE) ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DIRECTORY; uFlags |= SHGFI_USEFILEATTRIBUTES; } /* MSDN says SHGFI_OPENICON returns the image list containing the * small open icon. In practice the large open icon gets returned * for SHGFI_LARGEICON, so we support it. */ if (/*(size == SIZE_SMALL) && */(args->state & STATE_ITEM_OPEN)) uFlags |= SHGFI_OPENICON; CoInitialize(NULL); result = SHGetFileInfo( nativePath, dwFileAttributes, &sfi, sizeof(sfi), uFlags); if (result) { elemX->hIcon = sfi.hIcon; /* Remember the image list so we can get the icon size */ elemX->hImgList = (size == SIZE_LARGE) ? gImgListLarge : gImgListSmall; } result = SHGetFileInfo( nativePath, dwFileAttributes, &sfi, sizeof(sfi), uFlags | SHGFI_SELECTED); if (result) elemX->hIconSel = sfi.hIcon; CoUninitialize(); Tcl_DStringFree(&dString1); Tcl_DStringFree(&dString2); return; } /* Using the system image list */ if ((elemX->hImgList == NULL) && (elemX->path != NULL)) { /* Equivalent to "file nativename $path" */ nativePath = Tcl_TranslateFileName(tree->interp, elemX->path, &dString1); if (nativePath == NULL) return; /* This will be passed to system calls, so convert from UTF8 */ nativePath = Tcl_UtfToExternalDString(NULL, nativePath, -1, &dString2); /* -size small or large */ if (elemX->size != -1) size = elemX->size; else if (masterX != NULL && masterX->size != -1) size = masterX->size; switch (size) { case SIZE_SMALL: uFlags |= SHGFI_SMALLICON | SHGFI_SHELLICONSIZE; break; case SIZE_LARGE: uFlags |= SHGFI_LARGEICON | SHGFI_SHELLICONSIZE; break; } /* -type file or -type directory */ if (elemX->type != -1) type = elemX->type; else if (masterX != NULL && masterX->type != -1) type = masterX->type; /* If SHGFI_USEFILEATTRIBUTES is set, SHGetFileInfo is supposed to * assume that the file is real but not look for it on disk. This * can be used to get the icon for a certain type of file, ex *.exe. * In practice, lots of files get a non-generic icon when a * valid file path is given. */ if (type != -1) { dwFileAttributes = (type == TYPE_FILE) ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DIRECTORY; uFlags |= SHGFI_USEFILEATTRIBUTES; } /* MSDN says SHGFI_OPENICON returns the image list containing the * small open icon. In practice the large open icon gets returned * for SHGFI_LARGEICON. */ if (/*(size == SIZE_SMALL) && */(args->state & STATE_ITEM_OPEN)) uFlags |= SHGFI_OPENICON; CoInitialize(NULL); elemX->hImgList = (HIMAGELIST) SHGetFileInfo( nativePath, dwFileAttributes, &sfi, sizeof(sfi), uFlags); if (elemX->hImgList != NULL) { elemX->iIcon = sfi.iIcon; } CoUninitialize(); Tcl_DStringFree(&dString1); Tcl_DStringFree(&dString2); } } static void ForgetIcon(ElementShellIcon *elemX) { if (elemX->hIcon != NULL) DestroyIcon(elemX->hIcon); if (elemX->hIconSel != NULL) DestroyIcon(elemX->hIconSel); elemX->hImgList = NULL; elemX->hIcon = elemX->hIconSel = NULL; } static void DeleteProcShellIcon(TreeElementArgs *args) { TreeElement elem = args->elem; ElementShellIcon *elemX = (ElementShellIcon *) elem; ForgetIcon(elemX); } static int WorldChangedProcShellIcon(TreeElementArgs *args) { ElementShellIcon *elemX = (ElementShellIcon *) args->elem; int flagM = args->change.flagMaster; int flagS = args->change.flagSelf; int mask = 0; if ((flagS | flagM) & (SHELLICON_CONF_ICON | SHELLICON_CONF_SIZE)) mask |= CS_DISPLAY | CS_LAYOUT; if ((flagS | flagM) & (SHELLICON_CONF_DRAW)) mask |= CS_DISPLAY; if ((flagS | flagM) & SHELLICON_CONF_ICON) { ForgetIcon(elemX); } return mask; } static int ConfigProcShellIcon(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementShellIcon *elemX = (ElementShellIcon *) elem; Tk_SavedOptions savedOptions; int error; Tcl_Obj *errorResult = NULL; for (error = 0; error <= 1; error++) { if (error == 0) { if (Tk_SetOptions(tree->interp, (char *) elemX, elem->typePtr->optionTable, args->config.objc, args->config.objv, tree->tkwin, &savedOptions, &args->config.flagSelf) != TCL_OK) { args->config.flagSelf = 0; continue; } /* xxx */ Tk_FreeSavedOptions(&savedOptions); break; } else { errorResult = Tcl_GetObjResult(tree->interp); Tcl_IncrRefCount(errorResult); Tk_RestoreSavedOptions(&savedOptions); /* xxx */ Tcl_SetObjResult(tree->interp, errorResult); Tcl_DecrRefCount(errorResult); return TCL_ERROR; } } return TCL_OK; } static int CreateProcShellIcon(TreeElementArgs *args) { ElementShellIcon *elemX = (ElementShellIcon *) args->elem; elemX->type = -1; elemX->size = -1; elemX->addOverlays = -1; elemX->useImgList = -1; elemX->useSelected = -1; return TCL_OK; } static void DisplayProcShellIcon(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementShellIcon *elemX = (ElementShellIcon *) elem; ElementShellIcon *masterX = (ElementShellIcon *) elem->master; int state = args->state; int x = args->display.x, y = args->display.y; int width, height; int match, match2; int draw; HDC hDC; TkWinDCState dcState; UINT fStyle = ILD_TRANSPARENT; HICON hIcon = NULL; int useSelected; #ifdef DEPRECATED BOOLEAN_FOR_STATE(draw, draw, state) if (!draw) return; #endif LoadIconIfNeeded(args); if (elemX->hImgList == NULL) return; (void) ImageList_GetIconSize(elemX->hImgList, &width, &height); AdjustForSticky(args->display.sticky, args->display.width, args->display.height, FALSE, FALSE, &x, &y, &width, &height); hDC = TkWinGetDrawableDC(tree->display, args->display.drawable, &dcState); useSelected = elemX->useSelected; if (useSelected == -1 && masterX != NULL) useSelected = masterX->useSelected; switch (useSelected) { case USE_SEL_ALWAYS: hIcon = elemX->hIconSel; fStyle |= ILD_SELECTED; break; case -1: case USE_SEL_AUTO: hIcon = (state & STATE_ITEM_SELECTED) ? elemX->hIconSel : elemX->hIcon; if (state & STATE_ITEM_SELECTED) fStyle |= ILD_SELECTED; break; case USE_SEL_NEVER: hIcon = elemX->hIcon; break; } if (hIcon != NULL) { #if 1 /* If DI_DEFAULTSIZE is used, small icons get stretched */ DrawIconEx(hDC, x, y, hIcon, 0, 0, FALSE, NULL, DI_IMAGE | DI_MASK /*| DI_DEFAULTSIZE*/); #else /* Works fine for large, but not for small (they get stretched) */ DrawIcon(hDC, x, y, hIcon); #endif } else { ImageList_Draw(elemX->hImgList, elemX->iIcon, hDC, x, y, fStyle); } TkWinReleaseDrawableDC(args->display.drawable, hDC, &dcState); /* If this is a master element, forget the icon being used because the * appearance may change between items based on the open state */ if (masterX == NULL) { ForgetIcon(elemX); } } static void NeededProcShellIcon(TreeElementArgs *args) { TreeElement elem = args->elem; ElementShellIcon *elemX = (ElementShellIcon *) elem; ElementShellIcon *masterX = (ElementShellIcon *) elem->master; int width = 0, height = 0; int size = SIZE_LARGE; HIMAGELIST hImgList = NULL; /* The icon is not loaded until it is actually going to be displayed. * This is a good thing since loading the icons can take a while */ /* LoadIconIfNeeded(args);*/ if (elemX->hImgList != NULL) { hImgList = elemX->hImgList; } else if (elemX->path != NULL) { if (elemX->size != -1) size = elemX->size; else if (masterX != NULL && masterX->size != -1) size = masterX->size; switch (size) { case SIZE_SMALL: hImgList = gImgListSmall; break; case SIZE_LARGE: hImgList = gImgListLarge; break; } } if (hImgList != NULL) { (void) ImageList_GetIconSize(hImgList, &width, &height); } if (elemX->widthObj != NULL) width = elemX->width; else if ((masterX != NULL) && (masterX->widthObj != NULL)) width = masterX->width; if (elemX->heightObj != NULL) height = elemX->height; else if ((masterX != NULL) && (masterX->heightObj != NULL)) height = masterX->height; args->needed.width = width; args->needed.height = height; } static int StateProcShellIcon(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementShellIcon *elemX = (ElementShellIcon *) elem; ElementShellIcon *masterX = (ElementShellIcon *) elem->master; int match, match2; #ifdef DEPRECATED int draw1, draw2; #endif int sel1, sel2; int open1, open2; int mask = 0; #ifdef DEPRECATED BOOLEAN_FOR_STATE(draw1, draw, args->states.state1) if (draw1 == -1) draw1 = 1; #endif open1 = (args->states.state1 & STATE_ITEM_OPEN) != 0; sel1 = (args->states.state1 & STATE_ITEM_SELECTED) != 0; #ifdef DEPRECATED BOOLEAN_FOR_STATE(draw2, draw, args->states.state2) if (draw2 == -1) draw2 = 1; #endif open2 = (args->states.state2 & STATE_ITEM_OPEN) != 0; sel2 = (args->states.state2 & STATE_ITEM_SELECTED) != 0; if (elemX->path == NULL) open1 = open2 = sel1 = sel2 = 0; if ( #ifdef DEPRECATED (draw1 != draw2) || #endif (sel1 != sel2) || (open1 != open2)) mask |= CS_DISPLAY; /* Directories may have an open and closed icon. */ if (open1 != open2) { ForgetIcon(elemX); } return mask; } static int UndefProcShellIcon(TreeElementArgs *args) { TreeCtrl *tree = args->tree; TreeElement elem = args->elem; ElementShellIcon *elemX = (ElementShellIcon *) elem; int modified = 0; #ifdef DEPRECATED modified |= PerStateInfo_Undefine(tree, &pstBoolean, &elemX->draw, elem->stateDomain, args->state); #endif return modified; } static int ActualProcShellIcon(TreeElementArgs *args) { TreeCtrl *tree = args->tree; ElementShellIcon *elemX = (ElementShellIcon *) args->elem; ElementShellIcon *masterX = (ElementShellIcon *) args->elem->master; static CONST char *optionName[] = { #ifdef DEPRECATED "-draw", #endif (char *) NULL }; int index, match, matchM; Tcl_Obj *obj = NULL; if (Tcl_GetIndexFromObj(tree->interp, args->actual.obj, optionName, "option", 0, &index) != TCL_OK) return TCL_ERROR; switch (index) { #ifdef DEPRECATED case 0: { OBJECT_FOR_STATE(obj, pstBoolean, draw, args->state) break; } #endif default: break; } if (obj != NULL) Tcl_SetObjResult(tree->interp, obj); return TCL_OK; } TreeElementType elemTypeShellIcon = { "shellicon", sizeof(ElementShellIcon), shellIconOptionSpecs, NULL, CreateProcShellIcon, DeleteProcShellIcon, ConfigProcShellIcon, DisplayProcShellIcon, NeededProcShellIcon, NULL, /* heightProc */ WorldChangedProcShellIcon, StateProcShellIcon, UndefProcShellIcon, ActualProcShellIcon, NULL /* onScreenProc */ }; DLLEXPORT int Shellicon_Init(Tcl_Interp *interp) { #if 1 SHFILEINFO sfi; #else HMODULE hLib; #endif #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { return TCL_ERROR; } #endif #ifdef USE_TK_STUBS if (Tk_InitStubs(interp, "8.4", 0) == NULL) { return TCL_ERROR; } #endif /* InitCommonControlsEx must be called to use the ImageList functions */ /* This is already done by Tk on NT */ if (TkWinGetPlatformId() != VER_PLATFORM_WIN32_NT) { INITCOMMONCONTROLSEX comctl; ZeroMemory(&comctl, sizeof(comctl)); (void) InitCommonControlsEx(&comctl); } #if 1 /* Get the sytem image lists (small and large) */ CoInitialize(NULL); gImgListSmall = (HIMAGELIST) SHGetFileInfo(".exe", FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_SMALLICON); gImgListLarge = (HIMAGELIST) SHGetFileInfo(".exe", FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_LARGEICON); CoUninitialize(); #else /* FIXME: WinXP only */ /* This is broken somewhere */ hLib = LoadLibraryA("shell32"); SHGetImageListProc = (FARPROC) GetProcAddress(hLib, (LPCSTR) 727); SHGetImageListProc(SHIL_SMALL, &IID_IImageList, &gImgListSmall); SHGetImageListProc(SHIL_LARGE, &IID_IImageList, &gImgListLarge); SHGetImageListProc(SHIL_EXTRALARGE, &IID_IImageList, &gImgListXtraLarge); dbwin("small %p large %p xtralarge %p\n", gImgListSmall, gImgListLarge, gImgListXtraLarge); FreeLibrary(hLib); #endif #if 0 { typedef BOOL (WINAPI *FileIconInitProc)(BOOL fFullInit); HMODULE hShell32 = LoadLibrary("shell32.dll"); FileIconInitProc FileIconInit = (FileIconInitProc) GetProcAddress(hShell32, (LPCSTR)660); FileIconInit(TRUE); } #endif /* Load TkTreeCtrl */ if (Tcl_PkgRequire(interp, "treectrl", PACKAGE_PATCHLEVEL, TRUE) == NULL) return TCL_ERROR; /* Get the stubs table from TkTreeCtrl */ stubs = Tcl_GetAssocData(interp, "TreeCtrlStubs", NULL); if (stubs == NULL) return TCL_ERROR; #ifdef TREECTRL_DEBUG if (sizeof(TreeCtrl) != stubs->sizeofTreeCtrl || sizeof(TreeCtrlStubs) != stubs->sizeofTreeCtrlStubs || sizeof(TreeElement) != stubs->sizeofTreeElement || sizeof(TreeElementArgs) != stubs->sizeofTreeElementArgs) { Tcl_SetResult(interp, "probably forgot to recompile shellicon", TCL_VOLATILE); return TCL_ERROR; } #endif /* Initialize the options table */ BooleanCO_Init(shellIconOptionSpecs, "-addoverlays"); BooleanCO_Init(shellIconOptionSpecs, "-useimagelist"); PerStateCO_Init(shellIconOptionSpecs, "-draw", &pstBoolean, TreeStateFromObj); StringTableCO_Init(shellIconOptionSpecs, "-size", sizeST); StringTableCO_Init(shellIconOptionSpecs, "-type", typeST); StringTableCO_Init(shellIconOptionSpecs, "-useselected", useSelectedST); /* Add the "shellicon" element type */ if (TreeCtrl_RegisterElementType(interp, &elemTypeShellIcon) != TCL_OK) return TCL_ERROR; if (Tcl_PkgProvide(interp, PACKAGE_NAME, PACKAGE_PATCHLEVEL) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } DLLEXPORT int Shellicon_SafeInit(Tcl_Interp *interp) { return Shellicon_Init(interp); } tktreectrl-2.4.1/shellicon/shellicon.dll.manifest.in0000644000076400010400000000060610753133103023060 0ustar TimAdministrators tktreectrl-2.4.1/shellicon/shellicon.rc0000644000076400010400000000064011452152533020502 0ustar TimAdministrators// // On Win7 built with MSVC 2008 shellicon refuses to load without this. // When built with MingW shellicon loads normally. // Some conflict with treectrl.dll using a different comctl? // #ifndef RT_MANIFEST #define RT_MANIFEST 24 #endif #ifndef ISOLATIONAWARE_MANIFEST_RESOURCE_ID #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 #endif ISOLATIONAWARE_MANIFEST_RESOURCE_ID RT_MANIFEST "shellicon.dll.manifest" tktreectrl-2.4.1/shellicon/tclconfig/0000755000076400010400000000000011646706174020157 5ustar TimAdministratorstktreectrl-2.4.1/shellicon/tclconfig/install-sh0000755000076400010400000000421207577521126022162 0ustar TimAdministrators#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5; it is not part of GNU. # # $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" instcmd="$mvprog" chmodcmd="" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; *) if [ x"$src" = x ] then src=$1 else dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` fi # Make a temp file name in the proper directory. dstdir=`dirname $dst` dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp # and set any options; do chmod last to preserve setuid bits if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi # Now rename the file to the real destination. $doit $rmcmd $dst $doit $mvcmd $dsttmp $dst exit 0 tktreectrl-2.4.1/shellicon/tclconfig/README.txt0000644000076400010400000000145307577521126021660 0ustar TimAdministratorsThese files comprise the basic building blocks for a Tcl Extension Architecture (TEA) extension. For more information on TEA see: http://www.tcl.tk/doc/tea/ This package is part of the Tcl project at SourceForge, and latest sources should be available there: http://tcl.sourceforge.net/ This package is a freely available open source package. You can do virtually anything you like with it, such as modifying it, redistributing it, and selling it either in whole or in part. CONTENTS ======== The following is a short description of the files you will find in the sample extension. README.txt This file install-sh Program used for copying binaries and script files to their install locations. tcl.m4 Collection of Tcl autoconf macros. Included by a package's aclocal.m4 to define SC_* macros. tktreectrl-2.4.1/shellicon/tclconfig/tcl.m40000644000076400010400000040120611527030372021172 0ustar TimAdministrators# tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id$ AC_PREREQ(2.57) dnl TEA extensions pass us the version of TEA they think they dnl are compatible with (must be set in TEA_INIT below) dnl TEA_VERSION="3.9" # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TCLCONFIG], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AC_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), with_tclconfig="${withval}") AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions]) else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, AC_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), with_tkconfig="${withval}") AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions]) else no_tk= TK_BIN_DIR="${ac_cv_c_tkconfig}" AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Subst the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE # #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) case "`uname -s`" in *CYGWIN_*) AC_MSG_CHECKING([for cygwin variant]) case ${TCL_EXTRA_CFLAGS} in *-mwin32*|*-mno-cygwin*) TEA_PLATFORM="windows" CFLAGS="$CFLAGS -mwin32" AC_MSG_RESULT([win32]) ;; *) TEA_PLATFORM="unix" AC_MSG_RESULT([unix]) ;; esac EXEEXT=".exe" ;; *) ;; esac # The BUILD_$pkg is to define the correct extern storage class # handling when making this package AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], [Building extension source?]) # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp *.ilk vc*.pch" fi # TEA specific: AC_SUBST(CLEANFILES) AC_SUBST(TCL_LIBS) AC_SUBST(TCL_DEFS) AC_SUBST(TCL_EXTRA_CFLAGS) AC_SUBST(TCL_LD_FLAGS) AC_SUBST(TCL_SHLIB_LD_LIBS) ]) #------------------------------------------------------------------------ # TEA_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd "${TK_BIN_DIR}"; pwd`" \ "`cd "${TK_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TK_LIBS) AC_SUBST(TK_XINCLUDES) ]) #------------------------------------------------------------------------ # TEA_PROG_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory or the tclsh installed in a bin # directory. This macro will correctly determine the name # of the tclsh executable even if tclsh has not yet been # built in the build directory. The tclsh found is always # associated with a tclConfig.sh file. This tclsh should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments # none # # Results # Subst's the following values: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi AC_MSG_RESULT([${TCLSH_PROG}]) AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # TEA_PROG_WISH # Determine the fully qualified path name of the wish executable # in the Tk build directory or the wish installed in a bin # directory. This macro will correctly determine the name # of the wish executable even if wish has not yet been # built in the build directory. The wish found is always # associated with a tkConfig.sh file. This wish should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments # none # # Results # Subst's the following values: # WISH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi AC_MSG_RESULT([${WISH_PROG}]) AC_SUBST(WISH_PROG) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared], [build and link with shared libraries (default: on)]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) fi AC_SUBST(SHARED_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means # threads are disabled. "yes" is the default. # # TCL_THREADS is checked so that if you are compiling an extension # against a threaded core, your extension must be compiled threaded # as well. # # Note that it is legal to have a thread enabled extension run in a # threaded or non-threaded Tcl core, but a non-threaded extension may # only run in a non-threaded Tcl core. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads], [build with threads]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) AC_MSG_RESULT([yes (default)]) else AC_MSG_RESULT([no]) fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; *) if test "${TCL_THREADS}" = "1"; then AC_MSG_WARN([ --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) debugging can also be enabled. # # Arguments: # none # # TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives # the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. # Requires the following vars to be set in the Makefile: # CFLAGS_DEFAULT # LDFLAGS_DEFAULT # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to $(CFLAGS_OPTIMIZE) if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Formerly used as debug library extension; # always blank now. # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AC_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) AC_SUBST(TCL_DBGX) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # TEA_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, AC_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. # #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # TEA_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS, DL_LIBS - removed for TEA, only needed by core. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol defaults to # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${VERSION}${SHLIB_SUFFIX}. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) # #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_CFLAGS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AC_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AC_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) # Force 64bit on with VIS AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. AC_CACHE_CHECK([if compiler supports visibility "hidden"], tcl_cv_cc_visibility_hidden, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_TRY_LINK([ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, tcl_cv_cc_visibility_hidden=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ AC_DEFINE(MODULE_SCOPE, [extern __attribute__((__visibility__("hidden")))], [Compiler support for module scope symbols]) ]) # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath, AC_HELP_STRING([--disable-rpath], [disable rpath support (default: on)]), [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # TEA specific: Cross-compiling options for Windows/CE builds? AS_IF([test "${TEA_PLATFORM}" = windows], [ AC_MSG_CHECKING([if Windows/CE build is requested]) AC_ARG_ENABLE(wince, AC_HELP_STRING([--enable-wince], [enable Win/CE support (where applicable)]), [doWince=$enableval], [doWince=no]) AC_MSG_RESULT([$doWince]) ]) # Set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O AS_IF([test "$GCC" = yes], [ # TEA specific: CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" ], [CFLAGS_WARNING=""]) CC_OBJNAME="-o \[$]@" dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed. dnl AC_CHECK_TOOL(AR, ar) AC_CHECK_PROG(AR, ar, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION="1.0"]) case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test ! -d "${PATH64}" ; then AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) AC_MSG_WARN([Ensure latest Platform SDK is installed]) do64bit="no" else AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) fi if test "$GCC" = "yes" ; then AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) fi TEA_PATH_CELIB # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) done AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" AC_SUBST(CELIB_DIR) else RC="rc" lflags="-nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode if test x"${RC}" = x ; then RC="windres" fi CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD="$CC -shared" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" CFLAGS_DEBUG="${CFLAGS_DEBUG} -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE" CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE" CC_OBJNAME="-Fo\[$]@" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) ]) LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported with GCC on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" AS_IF([test "$GCC" = yes], [ CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' ], [ CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' ]) LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ], [ AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared -Wl,-bexpall' ], [ SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" ]) SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" EXE_SUFFIX=".exe" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library AS_IF([test "`uname -m`" = ia64], [ SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi ], [ SHLIB_SUFFIX=".sl" ]) AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ CFLAGS="$CFLAGS -z" # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" ]) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = "yes"], [ AS_IF([test "$GCC" = yes], [ case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac ], [ do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" ]) ]) ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [ CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" ], [ case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported by gcc]) ], [ do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" ]) ]) ;; Linux*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) AS_IF([test $do64bit = yes], [ AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_m64 = yes], [ CFLAGS="$CFLAGS -m64" do64bit_ok=yes ]) ]) # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) ;; GNU*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) ;; OpenBSD-*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}' AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ AC_EGREP_CPP(yes, [ #ifdef __ELF__ yes #endif ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) AS_IF([test $tcl_cv_ld_elf = yes], [ LDFLAGS=-Wl,-export-dynamic ], [LDFLAGS=""]) AS_IF([test "${TCL_THREADS}" = "1"], [ # OpenBSD builds and links with -pthread, never -lpthread. LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" SHLIB_CFLAGS="$SHLIB_CFLAGS -pthread" ]) # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*|FreeBSD-[[3-4]].*) # FreeBSD 3.* and greater have ELF. # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" TCL_SHLIB_LD_EXTRAS="-soname \$[@]" SHLIB_SUFFIX=".so" LDFLAGS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" AS_IF([test $do64bit = yes], [ case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, tcl_cv_cc_arch_ppc64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes ]);; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, tcl_cv_cc_arch_x86_64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes ]);; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac ], [ # Check for combined 32-bit and 64-bit fat build AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ fat_32_64=yes]) ]) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) # TEA specific: link shlib with current and compatiblity version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" # Don't use -prebind when building for Mac OS X 10.4 or later only: AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ LDFLAGS="$LDFLAGS -prebind"]) LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ LDFLAGS="$LDFLAGS -Wl,-search_paths_first" ]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [__private_extern__], [Compiler support for module scope symbols]) tcl_cv_cc_visibility_hidden=yes ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" AC_TRY_LINK([#include ], [XrmInitialize();], tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" AC_TRY_LINK([#include ], [Tk_InitStubs(NULL, "", 0);], tcl_cv_lib_tk_64=yes, tcl_cv_lib_tk_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done]) ]) ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='ld -shared -expect_unresolved "*"' ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) # see pthread_intro(3) for pthread support on osf1, k.furukawa AS_IF([test "${TCL_THREADS}" = 1], [ CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` AS_IF([test "$GCC" = yes], [ LIBS="$LIBS -lpthread -lmach -lexc" ], [ CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ]) ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) AS_IF([test "$GCC" = yes], [ SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" ], [ SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" ]) SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ arch=`isainfo` AS_IF([test "$arch" = "sparcv9 sparc"], [ AS_IF([test "$GCC" = yes], [ AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" ]) ], [ do64bit_ok=yes AS_IF([test "$do64bitVIS" = yes], [ CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" ], [ CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" ]) # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" ]) ], [AS_IF([test "$arch" = "amd64 i386"], [ AS_IF([test "$GCC" = yes], [ case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]);; esac ], [ do64bit_ok=yes case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "$do64bit_ok" = yes], [ AS_IF([test "$arch" = "sparcv9 sparc"], [ # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" ], [AS_IF([test "$arch" = "amd64 i386"], [ # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" ])]) ]) ], [ case $system in SunOS-5.[[1-9]][[0-9]]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ]) ;; esac AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) ]) dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so dnl # until the end of configure, as configure's compile and link tests use dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's dnl # preprocessing tests use only CPPFLAGS. AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [extern], [No Compiler support for module scope symbols]) AC_DEFINE(NO_VIZ, [], [No visibility hidden passed to zlib?]) ]) AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(CC_OBJNAME) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_LIBRARY_PATH_VAR) # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary TEA_TCL_EARLY_FLAGS TEA_TCL_64BIT_FLAGS ]) #-------------------------------------------------------------------- # TEA_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY # #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_TRY_RUN([ #include int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_MISSING_POSIX_HEADERS # # Supply substitutes for missing POSIX header files. Special # notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod in some versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # # Arguments: # none # # Results: # # Defines some of the following vars: # NO_DIRENT_H # NO_ERRNO_H # NO_VALUES_H # HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_SYS_PARAM_H # # HAVE_STRING_H ? # # tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and # CHECK on limits.h #-------------------------------------------------------------------- AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [ AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ AC_TRY_LINK([#include #include ], [ #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) if test $tcl_cv_dirent_h = no; then AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) fi # TEA specific: AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have ?])]) AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) AC_CHECK_HEADER(limits.h, [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) if test $tcl_ok = 0; then AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) # OS/390 lacks sys/param.h (and doesn't need it, by chance). AC_HAVE_HEADERS(sys/param.h) ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # This should be called after TEA_CONFIG_CFLAGS as setting the # LIBS line can confuse some configure macro magic. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # PKG_LIBS (appends to) # #-------------------------------------------------------------------- AC_DEFUN([TEA_PATH_X], [ if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then TEA_PATH_UNIX_X fi ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_TRY_CPP([#include ], , not_really_there="yes") else if test ! -r $x_includes/X11/Intrinsic.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Intrinsic.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test "$found_xincludes" = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi ]) #-------------------------------------------------------------------- # TEA_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK # #-------------------------------------------------------------------- AC_DEFUN([TEA_BLOCKING_STYLE], [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) TEA_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # TEA_TIME_HANDLER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR # #-------------------------------------------------------------------- AC_DEFUN([TEA_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_TRY_COMPILE([#include ], [extern long timezone; timezone += 1; exit (0);], tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_TRY_COMPILE([#include ], [extern time_t timezone; timezone += 1; exit (0);], tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # TEA_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) # #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_TRY_RUN([ extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, tcl_cv_strtod_buggy=buggy)]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm) and socket stuff (-lsocket vs. # -lnsl) are dealt with here. # # Arguments: # Requires the following vars to be set in the Makefile: # DL_LIBS (not in TEA, only needed in core) # LIBS # MATH_LIBS # # Results: # # Subst's the following var: # TCL_LIBS # MATH_LIBS # # Might append to the following vars: # LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' AC_SUBST(TCL_LIBS) AC_SUBST(MATH_LIBS) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, AC_TRY_COMPILE([[#define ]$1[ 1 ]$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], [struct stat64 buf; int i = stat64("/", &buf);]) TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], [char *p = (char *)open64;]) if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # TEA_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], tcl_type_64bit=__int64, tcl_type_64bit="long long") # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_TRY_COMPILE(,[switch (0) { case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; }],tcl_cv_type_64bit=${tcl_type_64bit})]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) AC_MSG_RESULT([using long]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_TRY_COMPILE([#include #include ],[struct dirent64 p;], tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_TRY_COMPILE([#include ],[struct stat64 p; ], tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_TRY_COMPILE([#include ],[off64_t offset; ], tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) ## ## Here ends the standard Tcl configuration bits and starts the ## TEA specific functions ## #------------------------------------------------------------------------ # TEA_INIT -- # # Init various Tcl Extension Architecture (TEA) variables. # This should be the first called TEA_* macro. # # Arguments: # none # # Results: # # Defines and substs the following vars: # CYGPATH # EXEEXT # Defines only: # TEA_VERSION # TEA_INITED # TEA_PLATFORM (windows or unix) # # "cygpath" is used on windows to generate native path names for include # files. These variables should only be used with the compiler and linker # since they generate native path names. # # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.9" AC_MSG_CHECKING([for correct TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.in]) fi if test x"$1" = x ; then AC_MSG_ERROR([ TEA version not specified.]) elif test "$1" != "${TEA_VERSION}" ; then AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) else AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) fi compile_for_windows="no" if test x"${host_alias}" != x ; then case $host_alias in *mingw32*) compile_for_windows="yes" esac fi case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) compile_for_windows="yes" ;; esac if test $compile_for_windows = yes ; then AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo) EXEEXT=".exe" TEA_PLATFORM="windows" else CYGPATH=echo EXEEXT="" TEA_PLATFORM="unix" fi # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_SOURCES # PKG_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_SOURCES], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_STUB_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_STUB_SOURCES # PKG_STUB_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_STUB_SOURCES], [ vars="$@" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find stub source file '$i']) fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_TCL_SOURCES -- # # Specify one or more Tcl source files. These should be platform # independent runtime files. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_TCL_SOURCES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_TCL_SOURCES], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done AC_SUBST(PKG_TCL_SOURCES) ]) #------------------------------------------------------------------------ # TEA_ADD_HEADERS -- # # Specify one or more source headers. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_HEADERS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_HEADERS], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find header file '${srcdir}/$i']) fi PKG_HEADERS="$PKG_HEADERS $i" done AC_SUBST(PKG_HEADERS) ]) #------------------------------------------------------------------------ # TEA_ADD_INCLUDES -- # # Specify one or more include dirs. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_INCLUDES], [ vars="$@" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done AC_SUBST(PKG_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_ADD_LIBS -- # # Specify one or more libraries. Users should check for # the right platform before adding to their list. For Windows, # libraries provided in "foo.lib" format will be converted to # "-lfoo" when using GCC (mingw). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ # TEA_ADD_CFLAGS -- # # Specify one or more CFLAGS. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_CFLAGS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CFLAGS], [ PKG_CFLAGS="$PKG_CFLAGS $@" AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_CLEANFILES -- # # Specify one or more CLEANFILES. # # Arguments: # one or more file names to clean target # # Results: # # Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CLEANFILES], [ CLEANFILES="$CLEANFILES $@" ]) #------------------------------------------------------------------------ # TEA_PREFIX -- # # Handle the --prefix=... option by defaulting to what Tcl gave # # Arguments: # none # # Results: # # If --prefix or --exec-prefix was not specified, $prefix and # $exec_prefix will be set to the values given to Tcl when it was # configured. #------------------------------------------------------------------------ AC_DEFUN([TEA_PREFIX], [ if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) prefix=${TCL_PREFIX} else AC_MSG_NOTICE([--prefix defaulting to /usr/local]) prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) exec_prefix=${TCL_EXEC_PREFIX} else AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) exec_prefix=$prefix fi fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.in files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER_CC], [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- AC_PROG_RANLIB #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER -- # # Do compiler checks that use the compiler. This must go after # TEA_SETUP_COMPILER_CC, which does the actual compiler check. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER], [ # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. AC_REQUIRE([TEA_SETUP_COMPILER_CC]) #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN if test "${TEA_PLATFORM}" = "unix" ; then TEA_TCL_LINK_LIBS TEA_MISSING_POSIX_HEADERS # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. # # Arguments: # none # # Requires: # # Results: # # Defines the following vars: # CFLAGS - Done late here to note disturb other AC macros # MAKE_LIB - Command to execute to build the Tcl library; # differs depending on whether or not Tcl is being # compiled as a shared library. # MAKE_SHARED_LIB Makefile rule for building a shared library # MAKE_STATIC_LIB Makefile rule for building a static library # MAKE_STUB_LIB Makefile rule for building a stub library # VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL # VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" AC_EGREP_CPP([manifest needed], [ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif ], [ # Could do a CHECK_PROG for mt, but should always be with MSVC8+ VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest \$(PKG_MANIFEST) -outputresource:\[$]@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest \$(PKG_MANIFEST) -outputresource:\[$]@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" # Don't clean .manifest provided by the package (see TEA_ADD_MANIFEST) # or one created by Makefile or configure. Could use the /manifest:filename # linker option to explicitly set the linker-generated filename. eval eval "manifest=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}.manifest" TEA_ADD_CLEANFILES([$manifest]) ]) MAKE_STUB_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_SHARED_LIB) AC_SUBST(MAKE_STATIC_LIB) AC_SUBST(MAKE_STUB_LIB) AC_SUBST(RANLIB_STUB) AC_SUBST(VC_MANIFEST_EMBED_DLL) AC_SUBST(VC_MANIFEST_EMBED_EXE) ]) #------------------------------------------------------------------------ # TEA_LIB_SPEC -- # # Compute the name of an existing object library located in libdir # from the given base name and produce the appropriate linker flags. # # Arguments: # basename The base name of the library without version # numbers, extensions, or "lib" prefixes. # extra_dir Extra directory in which to search for the # library. This location is used first, then # $prefix/$exec-prefix, then some defaults. # # Requires: # TEA_INIT and TEA_PREFIX must be called first. # # Results: # # Defines the following vars: # ${basename}_LIB_NAME The computed library name. # ${basename}_LIB_SPEC The computed linker flags. #------------------------------------------------------------------------ AC_DEFUN([TEA_LIB_SPEC], [ AC_MSG_CHECKING([for $1 library]) # Look in exec-prefix for the library (defined by TEA_PREFIX). tea_lib_name_dir="${exec_prefix}/lib" # Or in a user-specified location. if test x"$2" != x ; then tea_extra_lib_dir=$2 else tea_extra_lib_dir=NONE fi for i in \ `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do if test -f "$i" ; then tea_lib_name_dir=`dirname $i` $1_LIB_NAME=`basename $i` $1_LIB_PATH_NAME=$i break fi done if test "${TEA_PLATFORM}" = "windows"; then $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" else # Strip off the leading "lib" and trailing ".a" or ".so" tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" fi if test "x${$1_LIB_NAME}" = x ; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([${$1_LIB_SPEC}]) fi ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TCL_HEADERS -- # # Locate the private Tcl include files # # Arguments: # # Requires: # TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has # already been called. # # Results: # # Substs the following vars: # TCL_TOP_DIR_NATIVE # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) AC_MSG_CHECKING([for Tcl private include files]) TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi AC_SUBST(TCL_TOP_DIR_NATIVE) AC_SUBST(TCL_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TCL_HEADERS -- # # Locate the installed public Tcl header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tclinclude switch to configure. # Result is cached. # # Substs the following vars: # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ AC_MSG_CHECKING([for Tcl public headers]) AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tclh, [ # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) else AC_MSG_RESULT([${ac_cv_c_tclh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TCL_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TK_HEADERS -- # # Locate the private Tk include files # # Arguments: # # Requires: # TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has # already been called. # # Results: # # Substs the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) AC_MSG_CHECKING([for Tk private include files]) TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I${TK_XLIB_DIR_NATIVE}" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi AC_SUBST(TK_TOP_DIR_NATIVE) AC_SUBST(TK_XLIB_DIR_NATIVE) AC_SUBST(TK_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TK_HEADERS -- # # Locate the installed public Tk header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tkinclude switch to configure. # Result is cached. # # Substs the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ AC_MSG_CHECKING([for Tk public headers]) AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tkh, [ # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TK_INCLUDE_SPEC}" != x ; then d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) else AC_MSG_RESULT([${ac_cv_c_tkh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_INCLUDES) if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers AC_MSG_CHECKING([for X11 header files]) if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_XINCLUDES) fi AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) fi ]) #------------------------------------------------------------------------ # TEA_PATH_CONFIG -- # # Locate the ${1}Config.sh file and perform a sanity check on # the ${1} compile flags. These are used by packages like # [incr Tk] that load *Config.sh files from more than Tcl and Tk. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-$1=... # # Defines the following vars: # $1_BIN_DIR Full path to the directory containing # the $1Config.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CONFIG], [ # # Ok, lets find the $1 configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-$1 # if test x"${no_$1}" = x ; then # we reset no_$1 in case something fails here no_$1=true AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) AC_MSG_CHECKING([for $1 configuration]) AC_CACHE_VAL(ac_cv_c_$1config,[ # First check to see if --with-$1 was specified. if test x"${with_$1config}" != x ; then case ${with_$1config} in */$1Config.sh ) if test -f ${with_$1config}; then AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` fi;; esac if test -f "${with_$1config}/$1Config.sh" ; then ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` else AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) fi fi # then check for a private $1 installation if test x"${ac_cv_c_$1config}" = x ; then for i in \ ../$1 \ `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../$1 \ `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../../$1 \ `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ${srcdir}/../$1 \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi if test -f "$i/unix/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i/unix; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_$1config}" = x ; then $1_BIN_DIR="# no $1 configs found" AC_MSG_WARN([Cannot find $1 configuration definitions]) exit 0 else no_$1= $1_BIN_DIR=${ac_cv_c_$1config} AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG -- # # Load the $1Config.sh file # # Arguments: # # Requires the following vars to be set: # $1_BIN_DIR # # Results: # # Subst the following vars: # $1_SRC_DIR # $1_LIB_FILE # $1_LIB_SPEC # #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG], [ AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) if test -f "${$1_BIN_DIR}/$1Config.sh" ; then AC_MSG_RESULT([loading]) . "${$1_BIN_DIR}/$1Config.sh" else AC_MSG_RESULT([file not found]) fi # # If the $1_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable $1_LIB_SPEC will be set to the value # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC # instead of $1_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f "${$1_BIN_DIR}/Makefile" ; then AC_MSG_WARN([Found Makefile - using build library specs for $1]) $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} $1_LIBRARY_PATH=${$1_LIBRARY_PATH} fi AC_SUBST($1_VERSION) AC_SUBST($1_BIN_DIR) AC_SUBST($1_SRC_DIR) AC_SUBST($1_LIB_FILE) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_STUB_LIB_FILE) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_PATH) # Allow the caller to prevent this auto-check by specifying any 2nd arg AS_IF([test "x$2" = x], [ # Check both upper and lower-case variants # If a dev wanted non-stubs libs, this function could take an option # to not use _STUB in the paths below AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], [TEA_LOAD_CONFIG_LIB($1_STUB)]) ]) ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG_LIB -- # # Helper function to load correct library from another extension's # ${PACKAGE}Config.sh. # # Results: # Adds to LIBS the appropriate extension library # #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ AC_MSG_CHECKING([For $1 library for LIBS]) # This simplifies the use of stub libraries by automatically adding # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, # but this is called before CONFIG_CFLAGS. More importantly, this adds # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. if test "x${$1_LIB_SPEC}" != "x" ; then if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) else TEA_ADD_LIBS([${$1_LIB_SPEC}]) AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) fi else AC_MSG_RESULT([file not found]) fi ]) #------------------------------------------------------------------------ # TEA_EXPORT_CONFIG -- # # Define the data to insert into the ${PACKAGE}Config.sh file # # Arguments: # # Requires the following vars to be set: # $1 # # Results: # Subst the following vars: # #------------------------------------------------------------------------ AC_DEFUN([TEA_EXPORT_CONFIG], [ #-------------------------------------------------------------------- # These are for $1Config.sh #-------------------------------------------------------------------- # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}${DBGX}" else eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" fi $1_BUILD_LIB_SPEC="-L`pwd` ${$1_LIB_FLAG}" $1_LIB_SPEC="-L${pkglibdir} ${$1_LIB_FLAG}" $1_BUILD_STUB_LIB_SPEC="-L`pwd` [$]{$1_STUB_LIB_FLAG}" $1_STUB_LIB_SPEC="-L${pkglibdir} [$]{$1_STUB_LIB_FLAG}" $1_BUILD_STUB_LIB_PATH="`pwd`/[$]{PKG_STUB_LIB_FILE}" $1_STUB_LIB_PATH="${pkglibdir}/[$]{PKG_STUB_LIB_FILE}" AC_SUBST($1_BUILD_LIB_SPEC) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_PATH) AC_SUBST($1_STUB_LIB_PATH) AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) AC_SUBST(PATCHLEVEL) ]) #------------------------------------------------------------------------ # TEA_PATH_CELIB -- # # Locate Keuchel's celib emulation layer for targeting Win/CE # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-celib=... # # Defines the following vars: # CELIB_DIR Full path to the directory containing # the include and platform lib files #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CELIB], [ # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) AC_MSG_CHECKING([for Windows/CE celib directory]) AC_CACHE_VAL(ac_cv_c_celibconfig,[ # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_celibconfig}" = x ; then AC_MSG_ERROR([Cannot find celib support library directory]) else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` AC_MSG_RESULT([found $CELIB_DIR]) fi fi ]) #------------------------------------------------------------------------ # TEA_ADD_MANIFEST -- # # Specify manifest file on Windows. A package can have its own # manifest which may be merged with any manifest generated by # the Visual Studio compiler. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_MANIFEST #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_MANIFEST], [ vars="$@" for i in $vars; do # check for existence of .manifest.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/$i.in"; then AC_MSG_ERROR([could not find manifest file '${srcdir}/$i']) fi PKG_MANIFEST="$PKG_MANIFEST $i" # If package .manifest is provided, don't clean it # If package .manifest is generated by Makefile, clean it # If package .manifest is generated by configure, distclean it #TEA_ADD_CLEANFILES([$i]) done AC_SUBST(PKG_MANIFEST) ]) # Local Variables: # mode: autoconf # End: tktreectrl-2.4.1/tclconfig/0000755000076400010400000000000011646706174016177 5ustar TimAdministratorstktreectrl-2.4.1/tclconfig/install-sh0000755000076400010400000000421211646706174020202 0ustar TimAdministrators#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5; it is not part of GNU. # # $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" instcmd="$mvprog" chmodcmd="" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; *) if [ x"$src" = x ] then src=$1 else dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` fi # Make a temp file name in the proper directory. dstdir=`dirname $dst` dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp # and set any options; do chmod last to preserve setuid bits if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi # Now rename the file to the real destination. $doit $rmcmd $dst $doit $mvcmd $dsttmp $dst exit 0 tktreectrl-2.4.1/tclconfig/tcl.m40000644000076400010400000040120511646706174017225 0ustar TimAdministrators# tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id$ AC_PREREQ(2.57) dnl TEA extensions pass us the version of TEA they think they dnl are compatible with (must be set in TEA_INIT below) dnl TEA_VERSION="3.9" # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TCLCONFIG], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AC_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), with_tclconfig="${withval}") AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) if test -f "${with_tclconfig}"; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_ERROR([Can't find Tcl configuration definitions]) else no_tcl= TCL_BIN_DIR="${ac_cv_c_tclconfig}" AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_TKCONFIG], [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, AC_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), with_tkconfig="${withval}") AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) if test -f "${with_tkconfig}"; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # TEA specific: on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test "${TEA_PLATFORM}" = "windows" \ -a -f "$i/win/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/win; pwd)`" break fi if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_ERROR([Can't find Tk configuration definitions]) else no_tk= TK_BIN_DIR="${ac_cv_c_tkconfig}" AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Subst the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE # #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TCL_BIN_DIR}/Makefile" ; then TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitrary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" break fi done fi if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) case "`uname -s`" in *CYGWIN_*) AC_MSG_CHECKING([for cygwin variant]) case ${TCL_EXTRA_CFLAGS} in *-mwin32*|*-mno-cygwin*) TEA_PLATFORM="windows" CFLAGS="$CFLAGS -mwin32" AC_MSG_RESULT([win32]) ;; *) TEA_PLATFORM="unix" AC_MSG_RESULT([unix]) ;; esac EXEEXT=".exe" ;; *) ;; esac # The BUILD_$pkg is to define the correct extern storage class # handling when making this package AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], [Building extension source?]) # Do this here as we have fully defined TEA_PLATFORM now if test "${TEA_PLATFORM}" = "windows" ; then CLEANFILES="$CLEANFILES *.lib *.dll *.pdb *.exp *.ilk vc*.pch" fi # TEA specific: AC_SUBST(CLEANFILES) AC_SUBST(TCL_LIBS) AC_SUBST(TCL_DEFS) AC_SUBST(TCL_EXTRA_CFLAGS) AC_SUBST(TCL_LD_FLAGS) AC_SUBST(TCL_SHLIB_LD_LIBS) ]) #------------------------------------------------------------------------ # TEA_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TKCONFIG], [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f "${TK_BIN_DIR}/Makefile" ; then TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitrary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then for i in "`cd "${TK_BIN_DIR}"; pwd`" \ "`cd "${TK_BIN_DIR}"/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" break fi done fi if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) # TEA specific: AC_SUBST(TK_LIBS) AC_SUBST(TK_XINCLUDES) ]) #------------------------------------------------------------------------ # TEA_PROG_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory or the tclsh installed in a bin # directory. This macro will correctly determine the name # of the tclsh executable even if tclsh has not yet been # built in the build directory. The tclsh found is always # associated with a tclConfig.sh file. This tclsh should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments # none # # Results # Subst's the following values: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}" fi AC_MSG_RESULT([${TCLSH_PROG}]) AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # TEA_PROG_WISH # Determine the fully qualified path name of the wish executable # in the Tk build directory or the wish installed in a bin # directory. This macro will correctly determine the name # of the wish executable even if wish has not yet been # built in the build directory. The wish found is always # associated with a tkConfig.sh file. This wish should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments # none # # Results # Subst's the following values: # WISH_PROG #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" break fi done WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}" fi AC_MSG_RESULT([${WISH_PROG}]) AC_SUBST(WISH_PROG) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared], [build and link with shared libraries (default: on)]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) fi AC_SUBST(SHARED_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means # threads are disabled. "yes" is the default. # # TCL_THREADS is checked so that if you are compiling an extension # against a threaded core, your extension must be compiled threaded # as well. # # Note that it is legal to have a thread enabled extension run in a # threaded or non-threaded Tcl core, but a non-threaded extension may # only run in a non-threaded Tcl core. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads], [build with threads]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) AC_MSG_RESULT([yes (default)]) else AC_MSG_RESULT([no]) fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; *) if test "${TCL_THREADS}" = "1"; then AC_MSG_WARN([ --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) debugging can also be enabled. # # Arguments: # none # # TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives # the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. # Requires the following vars to be set in the Makefile: # CFLAGS_DEFAULT # LDFLAGS_DEFAULT # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to $(CFLAGS_OPTIMIZE) if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Formerly used as debug library extension; # always blank now. # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AC_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) AC_SUBST(TCL_DBGX) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # TEA_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. # #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, AC_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. # #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # TEA_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS, DL_LIBS - removed for TEA, only needed by core. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol defaults to # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${VERSION}${SHLIB_SUFFIX}. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) # #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_CFLAGS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AC_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AC_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) # Force 64bit on with VIS AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. AC_CACHE_CHECK([if compiler supports visibility "hidden"], tcl_cv_cc_visibility_hidden, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_TRY_LINK([ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, tcl_cv_cc_visibility_hidden=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ AC_DEFINE(MODULE_SCOPE, [extern __attribute__((__visibility__("hidden")))], [Compiler support for module scope symbols]) ]) # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath, AC_HELP_STRING([--disable-rpath], [disable rpath support (default: on)]), [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # TEA specific: Cross-compiling options for Windows/CE builds? AS_IF([test "${TEA_PLATFORM}" = windows], [ AC_MSG_CHECKING([if Windows/CE build is requested]) AC_ARG_ENABLE(wince, AC_HELP_STRING([--enable-wince], [enable Win/CE support (where applicable)]), [doWince=$enableval], [doWince=no]) AC_MSG_RESULT([$doWince]) ]) # Set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case and removed some core-only vars. do64bit_ok=no # default to '{$LIBS}' and set to "" on per-platform necessary basis SHLIB_LD_LIBS='${LIBS}' # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" UNSHARED_LIB_SUFFIX="" # TEA specific: use PACKAGE_VERSION instead of VERSION TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O AS_IF([test "$GCC" = yes], [ # TEA specific: CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall" ], [CFLAGS_WARNING=""]) CC_OBJNAME="-o \[$]@" dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed. dnl AC_CHECK_TOOL(AR, ar) AC_CHECK_PROG(AR, ar, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION="1.0"]) case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test ! -d "${PATH64}" ; then AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) AC_MSG_WARN([Ensure latest Platform SDK is installed]) do64bit="no" else AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) fi if test "$GCC" = "yes" ; then AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) fi TEA_PATH_CELIB # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) done AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" AC_SUBST(CELIB_DIR) else RC="rc" lflags="-nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode if test x"${RC}" = x ; then RC="windres" fi CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD="$CC -shared" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" CFLAGS_DEBUG="${CFLAGS_DEBUG} -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE" CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE" CC_OBJNAME="-Fo\[$]@" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r CC=`echo "$CC" | sed -e 's/^\([[^ ]]*\)/\1_r/'` ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) ]) LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_SUFFIX=".so" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported with GCC on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" AS_IF([test "$GCC" = yes], [ CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' ], [ CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' ]) LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ], [ AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared -Wl,-bexpall' ], [ SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" ]) SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" EXE_SUFFIX=".exe" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library AS_IF([test "`uname -m`" = ia64], [ SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi ], [ SHLIB_SUFFIX=".sl" ]) AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ CFLAGS="$CFLAGS -z" # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" ]) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = "yes"], [ AS_IF([test "$GCC" = yes], [ case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac ], [ do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" ]) ]) ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [ CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" ], [ case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported by gcc]) ], [ do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" ]) ]) ;; Linux*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) AS_IF([test $do64bit = yes], [ AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_m64 = yes], [ CFLAGS="$CFLAGS -m64" do64bit_ok=yes ]) ]) # The combo of gcc + glibc has a bug related to inlining of # functions like strtod(). The -fno-builtin flag should address # this problem but it does not work. The -fno-inline flag is kind # of overkill but it works. Disable inlining only when one of the # files in compat/*.c is being linked in. AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) ;; GNU*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) ;; OpenBSD-*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}' AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ AC_EGREP_CPP(yes, [ #ifdef __ELF__ yes #endif ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) AS_IF([test $tcl_cv_ld_elf = yes], [ LDFLAGS=-Wl,-export-dynamic ], [LDFLAGS=""]) AS_IF([test "${TCL_THREADS}" = "1"], [ # OpenBSD builds and links with -pthread, never -lpthread. LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" SHLIB_CFLAGS="$SHLIB_CFLAGS -pthread" ]) # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*|FreeBSD-[[3-4]].*) # FreeBSD 3.* and greater have ELF. # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" TCL_SHLIB_LD_EXTRAS="-soname \$[@]" SHLIB_SUFFIX=".so" LDFLAGS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1' TCL_LIB_VERSIONS_OK=nodots ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" AS_IF([test $do64bit = yes], [ case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, tcl_cv_cc_arch_ppc64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes ]);; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, tcl_cv_cc_arch_x86_64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes ]);; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac ], [ # Check for combined 32-bit and 64-bit fat build AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ fat_32_64=yes]) ]) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) # TEA specific: link shlib with current and compatiblity version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" # Don't use -prebind when building for Mac OS X 10.4 or later only: AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ LDFLAGS="$LDFLAGS -prebind"]) LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ LDFLAGS="$LDFLAGS -Wl,-search_paths_first" ]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [__private_extern__], [Compiler support for module scope symbols]) tcl_cv_cc_visibility_hidden=yes ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for combined 32 & 64 bit fat builds of Tk # extensions, verify that 64-bit build is possible. AS_IF([test "$fat_32_64" = yes && test -n "${TK_BIN_DIR}"], [ AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" AC_TRY_LINK([#include ], [XrmInitialize();], tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" AC_TRY_LINK([#include ], [Tk_InitStubs(NULL, "", 0);], tcl_cv_lib_tk_64=yes, tcl_cv_lib_tk_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ AC_MSG_NOTICE([Removing 64-bit architectures from compiler & linker flags]) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' done]) ]) ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='ld -shared -expect_unresolved "*"' ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) # see pthread_intro(3) for pthread support on osf1, k.furukawa AS_IF([test "${TCL_THREADS}" = 1], [ CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` AS_IF([test "$GCC" = yes], [ LIBS="$LIBS -lpthread -lmach -lexc" ], [ CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ]) ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) AS_IF([test "$GCC" = yes], [ SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" ], [ SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" ]) SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ arch=`isainfo` AS_IF([test "$arch" = "sparcv9 sparc"], [ AS_IF([test "$GCC" = yes], [ AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) ], [ do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" ]) ], [ do64bit_ok=yes AS_IF([test "$do64bitVIS" = yes], [ CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" ], [ CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" ]) # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" ]) ], [AS_IF([test "$arch" = "amd64 i386"], [ AS_IF([test "$GCC" = yes], [ case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) do64bit_ok=yes CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]);; esac ], [ do64bit_ok=yes case $system in SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64";; *) CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64";; esac ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "$do64bit_ok" = yes], [ AS_IF([test "$arch" = "sparcv9 sparc"], [ # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" ], [AS_IF([test "$arch" = "amd64 i386"], [ # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" ])]) ]) ], [ case $system in SunOS-5.[[1-9]][[0-9]]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ]) ;; esac AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) ]) dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so dnl # until the end of configure, as configure's compile and link tests use dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's dnl # preprocessing tests use only CPPFLAGS. AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) # Add in the arch flags late to ensure it wasn't removed. # Not necessary in TEA, but this is aligned with core LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [extern], [No Compiler support for module scope symbols]) AC_DEFINE(NO_VIZ, [], [No visibility hidden passed to zlib?]) ]) AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}']) AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(CC_OBJNAME) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_LIBRARY_PATH_VAR) # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary TEA_TCL_EARLY_FLAGS TEA_TCL_64BIT_FLAGS ]) #-------------------------------------------------------------------- # TEA_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY # #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_TRY_RUN([ #include int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include #include int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include #include int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_MISSING_POSIX_HEADERS # # Supply substitutes for missing POSIX header files. Special # notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod in some versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # # Arguments: # none # # Results: # # Defines some of the following vars: # NO_DIRENT_H # NO_ERRNO_H # NO_VALUES_H # HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_SYS_PARAM_H # # HAVE_STRING_H ? # # tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and # CHECK on limits.h #-------------------------------------------------------------------- AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [ AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ AC_TRY_LINK([#include #include ], [ #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) if test $tcl_cv_dirent_h = no; then AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) fi # TEA specific: AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have ?])]) AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) AC_CHECK_HEADER(limits.h, [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) if test $tcl_ok = 0; then AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) fi AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) # OS/390 lacks sys/param.h (and doesn't need it, by chance). AC_HAVE_HEADERS(sys/param.h) ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # This should be called after TEA_CONFIG_CFLAGS as setting the # LIBS line can confuse some configure macro magic. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # PKG_LIBS (appends to) # #-------------------------------------------------------------------- AC_DEFUN([TEA_PATH_X], [ if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then TEA_PATH_UNIX_X fi ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_TRY_CPP([#include ], , not_really_there="yes") else if test ! -r $x_includes/X11/Intrinsic.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Intrinsic.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test "$found_xincludes" = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi # TEA specific: if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi ]) #-------------------------------------------------------------------- # TEA_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK # #-------------------------------------------------------------------- AC_DEFUN([TEA_BLOCKING_STYLE], [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) TEA_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # TEA_TIME_HANDLER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR # #-------------------------------------------------------------------- AC_DEFUN([TEA_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_TRY_COMPILE([#include ], [extern long timezone; timezone += 1; exit (0);], tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_TRY_COMPILE([#include ], [extern time_t timezone; timezone += 1; exit (0);], tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # TEA_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) # #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_TRY_RUN([ extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, tcl_cv_strtod_buggy=buggy)]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm) and socket stuff (-lsocket vs. # -lnsl) are dealt with here. # # Arguments: # Requires the following vars to be set in the Makefile: # DL_LIBS (not in TEA, only needed in core) # LIBS # MATH_LIBS # # Results: # # Subst's the following var: # TCL_LIBS # MATH_LIBS # # Might append to the following vars: # LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' AC_SUBST(TCL_LIBS) AC_SUBST(MATH_LIBS) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, AC_TRY_COMPILE([[#define ]$1[ 1 ]$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], [struct stat64 buf; int i = stat64("/", &buf);]) TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], [char *p = (char *)open64;]) if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # TEA_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T # #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], tcl_type_64bit=__int64, tcl_type_64bit="long long") # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_TRY_COMPILE(,[switch (0) { case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; }],tcl_cv_type_64bit=${tcl_type_64bit})]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) AC_MSG_RESULT([using long]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_TRY_COMPILE([#include #include ],[struct dirent64 p;], tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_TRY_COMPILE([#include ],[struct stat64 p; ], tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_TRY_COMPILE([#include ],[off64_t offset; ], tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) ## ## Here ends the standard Tcl configuration bits and starts the ## TEA specific functions ## #------------------------------------------------------------------------ # TEA_INIT -- # # Init various Tcl Extension Architecture (TEA) variables. # This should be the first called TEA_* macro. # # Arguments: # none # # Results: # # Defines and substs the following vars: # CYGPATH # EXEEXT # Defines only: # TEA_VERSION # TEA_INITED # TEA_PLATFORM (windows or unix) # # "cygpath" is used on windows to generate native path names for include # files. These variables should only be used with the compiler and linker # since they generate native path names. # # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.9" AC_MSG_CHECKING([for correct TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.in]) fi if test x"$1" = x ; then AC_MSG_ERROR([ TEA version not specified.]) elif test "$1" != "${TEA_VERSION}" ; then AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) else AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) fi compile_for_windows="no" if test x"${host_alias}" != x ; then case $host_alias in *mingw32*) compile_for_windows="yes" esac fi case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) compile_for_windows="yes" ;; esac if test $compile_for_windows = yes ; then AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo) EXEEXT=".exe" TEA_PLATFORM="windows" else CYGPATH=echo EXEEXT="" TEA_PLATFORM="unix" fi # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_SOURCES # PKG_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_SOURCES], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH # To add more dirs here (like 'src'), you have to update VPATH # in Makefile.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_STUB_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_STUB_SOURCES # PKG_STUB_OBJECTS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_STUB_SOURCES], [ vars="$@" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ -a ! -f "${srcdir}/macosx/$i" \ ; then AC_MSG_ERROR([could not find stub source file '$i']) fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_TCL_SOURCES -- # # Specify one or more Tcl source files. These should be platform # independent runtime files. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_TCL_SOURCES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_TCL_SOURCES], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done AC_SUBST(PKG_TCL_SOURCES) ]) #------------------------------------------------------------------------ # TEA_ADD_HEADERS -- # # Specify one or more source headers. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_HEADERS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_HEADERS], [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find header file '${srcdir}/$i']) fi PKG_HEADERS="$PKG_HEADERS $i" done AC_SUBST(PKG_HEADERS) ]) #------------------------------------------------------------------------ # TEA_ADD_INCLUDES -- # # Specify one or more include dirs. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_INCLUDES], [ vars="$@" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done AC_SUBST(PKG_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_ADD_LIBS -- # # Specify one or more libraries. Users should check for # the right platform before adding to their list. For Windows, # libraries provided in "foo.lib" format will be converted to # "-lfoo" when using GCC (mingw). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ # TEA_ADD_CFLAGS -- # # Specify one or more CFLAGS. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_CFLAGS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CFLAGS], [ PKG_CFLAGS="$PKG_CFLAGS $@" AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_CLEANFILES -- # # Specify one or more CLEANFILES. # # Arguments: # one or more file names to clean target # # Results: # # Appends to CLEANFILES, already defined for subst in LOAD_TCLCONFIG #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_CLEANFILES], [ CLEANFILES="$CLEANFILES $@" ]) #------------------------------------------------------------------------ # TEA_PREFIX -- # # Handle the --prefix=... option by defaulting to what Tcl gave # # Arguments: # none # # Results: # # If --prefix or --exec-prefix was not specified, $prefix and # $exec_prefix will be set to the values given to Tcl when it was # configured. #------------------------------------------------------------------------ AC_DEFUN([TEA_PREFIX], [ if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) prefix=${TCL_PREFIX} else AC_MSG_NOTICE([--prefix defaulting to /usr/local]) prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) exec_prefix=${TCL_EXEC_PREFIX} else AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) exec_prefix=$prefix fi fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.in files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER_CC], [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- AC_PROG_RANLIB #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER -- # # Do compiler checks that use the compiler. This must go after # TEA_SETUP_COMPILER_CC, which does the actual compiler check. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER], [ # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. AC_REQUIRE([TEA_SETUP_COMPILER_CC]) #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN if test "${TEA_PLATFORM}" = "unix" ; then TEA_TCL_LINK_LIBS TEA_MISSING_POSIX_HEADERS # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. # # Arguments: # none # # Requires: # # Results: # # Defines the following vars: # CFLAGS - Done late here to note disturb other AC macros # MAKE_LIB - Command to execute to build the Tcl library; # differs depending on whether or not Tcl is being # compiled as a shared library. # MAKE_SHARED_LIB Makefile rule for building a shared library # MAKE_STATIC_LIB Makefile rule for building a static library # MAKE_STUB_LIB Makefile rule for building a stub library # VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL # VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" AC_EGREP_CPP([manifest needed], [ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif ], [ # Could do a CHECK_PROG for mt, but should always be with MSVC8+ VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest \$(PKG_MANIFEST) -outputresource:\[$]@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest \$(PKG_MANIFEST) -outputresource:\[$]@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" # Don't clean .manifest provided by the package (see TEA_ADD_MANIFEST) # or one created by Makefile or configure. Could use the /manifest:filename # linker option to explicitly set the linker-generated filename. eval eval "manifest=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}.manifest" TEA_ADD_CLEANFILES([$manifest]) ]) MAKE_STUB_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_SHARED_LIB) AC_SUBST(MAKE_STATIC_LIB) AC_SUBST(MAKE_STUB_LIB) AC_SUBST(RANLIB_STUB) AC_SUBST(VC_MANIFEST_EMBED_DLL) AC_SUBST(VC_MANIFEST_EMBED_EXE) ]) #------------------------------------------------------------------------ # TEA_LIB_SPEC -- # # Compute the name of an existing object library located in libdir # from the given base name and produce the appropriate linker flags. # # Arguments: # basename The base name of the library without version # numbers, extensions, or "lib" prefixes. # extra_dir Extra directory in which to search for the # library. This location is used first, then # $prefix/$exec-prefix, then some defaults. # # Requires: # TEA_INIT and TEA_PREFIX must be called first. # # Results: # # Defines the following vars: # ${basename}_LIB_NAME The computed library name. # ${basename}_LIB_SPEC The computed linker flags. #------------------------------------------------------------------------ AC_DEFUN([TEA_LIB_SPEC], [ AC_MSG_CHECKING([for $1 library]) # Look in exec-prefix for the library (defined by TEA_PREFIX). tea_lib_name_dir="${exec_prefix}/lib" # Or in a user-specified location. if test x"$2" != x ; then tea_extra_lib_dir=$2 else tea_extra_lib_dir=NONE fi for i in \ `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib64/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib64/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do if test -f "$i" ; then tea_lib_name_dir=`dirname $i` $1_LIB_NAME=`basename $i` $1_LIB_PATH_NAME=$i break fi done if test "${TEA_PLATFORM}" = "windows"; then $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" else # Strip off the leading "lib" and trailing ".a" or ".so" tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" fi if test "x${$1_LIB_NAME}" = x ; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([${$1_LIB_SPEC}]) fi ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TCL_HEADERS -- # # Locate the private Tcl include files # # Arguments: # # Requires: # TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has # already been called. # # Results: # # Substs the following vars: # TCL_TOP_DIR_NATIVE # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [ # Allow for --with-tclinclude to take effect and define ${ac_cv_c_tclh} AC_REQUIRE([TEA_PUBLIC_TCL_HEADERS]) AC_MSG_CHECKING([for Tcl private include files]) TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" # Check to see if tclPort.h isn't already with the public headers # Don't look for tclInt.h because that resides with tcl.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tclh}/tclWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tclh}/tclUnixPort.h"; then result="private headers found with public headers" else TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" else TCL_PLATFORM_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TCL_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a \ -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}" else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TCL_INCLUDES}" else if test ! -f "${TCL_SRC_DIR}/generic/tclInt.h" ; then AC_MSG_ERROR([Cannot find private header tclInt.h in ${TCL_SRC_DIR}]) fi result="Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" fi fi AC_SUBST(TCL_TOP_DIR_NATIVE) AC_SUBST(TCL_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TCL_HEADERS -- # # Locate the installed public Tcl header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tclinclude switch to configure. # Result is cached. # # Substs the following vars: # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TCL_HEADERS], [ AC_MSG_CHECKING([for Tcl public headers]) AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tclh, [ # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) else AC_MSG_RESULT([${ac_cv_c_tclh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TCL_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TK_HEADERS -- # # Locate the private Tk include files # # Arguments: # # Requires: # TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has # already been called. # # Results: # # Substs the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PRIVATE_TK_HEADERS], [ # Allow for --with-tkinclude to take effect and define ${ac_cv_c_tkh} AC_REQUIRE([TEA_PUBLIC_TK_HEADERS]) AC_MSG_CHECKING([for Tk private include files]) TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" # Check to see if tkPort.h isn't already with the public headers # Don't look for tkInt.h because that resides with tk.h in the core # sources, but the Port headers are in a different directory if test "${TEA_PLATFORM}" = "windows" -a \ -f "${ac_cv_c_tkh}/tkWinPort.h"; then result="private headers found with public headers" elif test "${TEA_PLATFORM}" = "unix" -a \ -f "${ac_cv_c_tkh}/tkUnixPort.h"; then result="private headers found with public headers" else TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" else TK_PLATFORM_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" fi # Overwrite the previous TK_INCLUDES as this should capture both # public and private headers in the same set. # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" # Detect and add ttk subdir if test -d "${TK_SRC_DIR}/generic/ttk"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/generic/ttk\"" fi if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then TK_INCLUDES="${TK_INCLUDES} -I${TK_XLIB_DIR_NATIVE}" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I\"${TK_SRC_DIR_NATIVE}/macosx\"" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a \ -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}" else TK_INCLUDES="${TK_INCLUDES} ${TK_INCLUDE_SPEC} `echo "${TK_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`" fi ;; esac result="Using ${TK_INCLUDES}" else if test ! -f "${TK_SRC_DIR}/generic/tkInt.h" ; then AC_MSG_ERROR([Cannot find private header tkInt.h in ${TK_SRC_DIR}]) fi result="Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" fi fi AC_SUBST(TK_TOP_DIR_NATIVE) AC_SUBST(TK_XLIB_DIR_NATIVE) AC_SUBST(TK_INCLUDES) AC_MSG_RESULT([${result}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TK_HEADERS -- # # Locate the installed public Tk header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tkinclude switch to configure. # Result is cached. # # Substs the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN([TEA_PUBLIC_TK_HEADERS], [ AC_MSG_CHECKING([for Tk public headers]) AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files], with_tkinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tkh, [ # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) fi else list="" if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TK_INCLUDE_SPEC}" != x ; then d=`echo "${TK_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) else AC_MSG_RESULT([${ac_cv_c_tkh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_INCLUDES) if test "${TEA_WINDOWINGSYSTEM}" != "x11"; then # On Windows and Aqua, we need the X compat headers AC_MSG_CHECKING([for X11 header files]) if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_XINCLUDES) fi AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) fi ]) #------------------------------------------------------------------------ # TEA_PATH_CONFIG -- # # Locate the ${1}Config.sh file and perform a sanity check on # the ${1} compile flags. These are used by packages like # [incr Tk] that load *Config.sh files from more than Tcl and Tk. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-$1=... # # Defines the following vars: # $1_BIN_DIR Full path to the directory containing # the $1Config.sh file #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CONFIG], [ # # Ok, lets find the $1 configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-$1 # if test x"${no_$1}" = x ; then # we reset no_$1 in case something fails here no_$1=true AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) AC_MSG_CHECKING([for $1 configuration]) AC_CACHE_VAL(ac_cv_c_$1config,[ # First check to see if --with-$1 was specified. if test x"${with_$1config}" != x ; then case ${with_$1config} in */$1Config.sh ) if test -f ${with_$1config}; then AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` fi;; esac if test -f "${with_$1config}/$1Config.sh" ; then ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` else AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) fi fi # then check for a private $1 installation if test x"${ac_cv_c_$1config}" = x ; then for i in \ ../$1 \ `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../$1 \ `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../../$1 \ `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ${srcdir}/../$1 \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi if test -f "$i/unix/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i/unix; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_$1config}" = x ; then $1_BIN_DIR="# no $1 configs found" AC_MSG_WARN([Cannot find $1 configuration definitions]) exit 0 else no_$1= $1_BIN_DIR=${ac_cv_c_$1config} AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG -- # # Load the $1Config.sh file # # Arguments: # # Requires the following vars to be set: # $1_BIN_DIR # # Results: # # Subst the following vars: # $1_SRC_DIR # $1_LIB_FILE # $1_LIB_SPEC # #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG], [ AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) if test -f "${$1_BIN_DIR}/$1Config.sh" ; then AC_MSG_RESULT([loading]) . "${$1_BIN_DIR}/$1Config.sh" else AC_MSG_RESULT([file not found]) fi # # If the $1_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable $1_LIB_SPEC will be set to the value # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC # instead of $1_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f "${$1_BIN_DIR}/Makefile" ; then AC_MSG_WARN([Found Makefile - using build library specs for $1]) $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC} $1_LIBRARY_PATH=${$1_LIBRARY_PATH} fi AC_SUBST($1_VERSION) AC_SUBST($1_BIN_DIR) AC_SUBST($1_SRC_DIR) AC_SUBST($1_LIB_FILE) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_STUB_LIB_FILE) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_PATH) # Allow the caller to prevent this auto-check by specifying any 2nd arg AS_IF([test "x$2" = x], [ # Check both upper and lower-case variants # If a dev wanted non-stubs libs, this function could take an option # to not use _STUB in the paths below AS_IF([test "x${$1_STUB_LIB_SPEC}" = x], [TEA_LOAD_CONFIG_LIB(translit($1,[a-z],[A-Z])_STUB)], [TEA_LOAD_CONFIG_LIB($1_STUB)]) ]) ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG_LIB -- # # Helper function to load correct library from another extension's # ${PACKAGE}Config.sh. # # Results: # Adds to LIBS the appropriate extension library # #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_CONFIG_LIB], [ AC_MSG_CHECKING([For $1 library for LIBS]) # This simplifies the use of stub libraries by automatically adding # the stub lib to your path. Normally this would add to SHLIB_LD_LIBS, # but this is called before CONFIG_CFLAGS. More importantly, this adds # to PKG_LIBS, which becomes LIBS, and that is only used by SHLIB_LD. if test "x${$1_LIB_SPEC}" != "x" ; then if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes" ; then TEA_ADD_LIBS([\"`${CYGPATH} ${$1_LIB_PATH}`\"]) AC_MSG_RESULT([using $1_LIB_PATH ${$1_LIB_PATH}]) else TEA_ADD_LIBS([${$1_LIB_SPEC}]) AC_MSG_RESULT([using $1_LIB_SPEC ${$1_LIB_SPEC}]) fi else AC_MSG_RESULT([file not found]) fi ]) #------------------------------------------------------------------------ # TEA_EXPORT_CONFIG -- # # Define the data to insert into the ${PACKAGE}Config.sh file # # Arguments: # # Requires the following vars to be set: # $1 # # Results: # Subst the following vars: # #------------------------------------------------------------------------ AC_DEFUN([TEA_EXPORT_CONFIG], [ #-------------------------------------------------------------------- # These are for $1Config.sh #-------------------------------------------------------------------- # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}${DBGX}" else eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" fi $1_BUILD_LIB_SPEC="-L`pwd` ${$1_LIB_FLAG}" $1_LIB_SPEC="-L${pkglibdir} ${$1_LIB_FLAG}" $1_BUILD_STUB_LIB_SPEC="-L`pwd` [$]{$1_STUB_LIB_FLAG}" $1_STUB_LIB_SPEC="-L${pkglibdir} [$]{$1_STUB_LIB_FLAG}" $1_BUILD_STUB_LIB_PATH="`pwd`/[$]{PKG_STUB_LIB_FILE}" $1_STUB_LIB_PATH="${pkglibdir}/[$]{PKG_STUB_LIB_FILE}" AC_SUBST($1_BUILD_LIB_SPEC) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_PATH) AC_SUBST($1_STUB_LIB_PATH) AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) AC_SUBST(PATCHLEVEL) ]) #------------------------------------------------------------------------ # TEA_PATH_CELIB -- # # Locate Keuchel's celib emulation layer for targeting Win/CE # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-celib=... # # Defines the following vars: # CELIB_DIR Full path to the directory containing # the include and platform lib files #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CELIB], [ # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) AC_MSG_CHECKING([for Windows/CE celib directory]) AC_CACHE_VAL(ac_cv_c_celibconfig,[ # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_celibconfig}" = x ; then AC_MSG_ERROR([Cannot find celib support library directory]) else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` AC_MSG_RESULT([found $CELIB_DIR]) fi fi ]) #------------------------------------------------------------------------ # TEA_ADD_MANIFEST -- # # Specify manifest file on Windows. A package can have its own # manifest which may be merged with any manifest generated by # the Visual Studio compiler. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_MANIFEST #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_MANIFEST], [ vars="$@" for i in $vars; do # Check for existence of .manifest.in as well if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/$i.in"; then AC_MSG_ERROR([could not find manifest file '${srcdir}/$i']) fi PKG_MANIFEST="$PKG_MANIFEST $i" # If package .manifest is provided, don't clean it # If package .manifest is generated by Makefile, clean it # If package .manifest is generated by configure, distclean it #TEA_ADD_CLEANFILES([$i]) done AC_SUBST(PKG_MANIFEST) ]) # Local Variables: # mode: autoconf # End: tktreectrl-2.4.1/tests/0000755000076400010400000000000011646706175015372 5ustar TimAdministratorstktreectrl-2.4.1/tests/all.tcl0000644000076400010400000000325211570577304016644 0ustar TimAdministrators# all.tcl -- # # This file contains a top-level script to run all of the Tcl # tests. Execute it by invoking "source all.test" when running tcltest # in this directory. # # Copyright (c) 1998-2000 by Scriptics Corporation. # All rights reserved. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest namespace import ::tcltest::* } set ::tcltest::testSingleFile false set ::tcltest::testsDirectory [file dir [info script]] # We need to ensure that the testsDirectory is absolute ::tcltest::normalizePath ::tcltest::testsDirectory set chan $::tcltest::outputChannel puts $chan "Tests running in interp: [info nameofexecutable]" puts $chan "Tests running with pwd: [pwd]" puts $chan "Tests running in working dir: $::tcltest::testsDirectory" if {[llength $::tcltest::skip] > 0} { puts $chan "Skipping tests that match: $::tcltest::skip" } if {[llength $::tcltest::match] > 0} { puts $chan "Only running tests that match: $::tcltest::match" } if {[llength $::tcltest::skipFiles] > 0} { puts $chan "Skipping test files that match: $::tcltest::skipFiles" } if {[llength $::tcltest::matchFiles] > 0} { puts $chan "Only sourcing test files that match: $::tcltest::matchFiles" } set timeCmd {clock format [clock seconds]} puts $chan "Tests began at [eval $timeCmd]" package require treectrl #tcltest::matchFiles header* # source each of the specified tests foreach file [lsort [::tcltest::getMatchingFiles]] { set tail [file tail $file] puts $chan $tail if {[catch {source $file} msg]} { puts $chan $msg } } # cleanup puts $chan "\nTests ended at [eval $timeCmd]" ::tcltest::cleanupTests 1 return tktreectrl-2.4.1/tests/column.test0000644000076400010400000004563511565601556017602 0ustar TimAdministrators# Commands covered: treectrl's widget command column # # This file contains a collection of tests for the column widget command of # the tktreectrl extension. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2000 by Scriptics Corporation. # Copyright (c) 2002 by Christian Krone. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } package require Tk package require treectrl test column-0.1 {some needed preparations} -body { pack [treectrl .t -usetheme no] # The default borderwidth in Tk 8.4 is "2" while in Tk 8.5 it is "1". # The default highlightthickness is "0" Mac OS X but "1" on other platforms. .t configure -borderwidth 1 -highlightthickness 1 } -result {} test column-0.2 {create an image} -body { image create photo emptyImg } -result {emptyImg} test column-1.1 {missing args} -body { .t column } -returnCodes error -result {wrong # args: should be ".t column command ?arg arg ...?"} test column-1.2 {unknown command} -body { .t column foo } -returnCodes error -result {bad command "foo": must be *} -match glob test column-1.3 {configure: no column exists with numerical index} -body { .t column configure 0 } -returnCodes error -result {column "0" doesn't exist} test column-1.4 {configure: no column exists with tag} -body { .t column configure column0 } -returnCodes error -result {column "column0" doesn't exist} test column-1.5 {configure: create and fill a column} -body { .t column create .t column configure 0 -tags column0 .t element create e rect -width 482 -height 20 .t style create s .t style elements s e set i [.t item create] .t item style set $i 0 s .t item lastchild root $i } -result {1} test column-1.6 {configure: create another column} -body { .t column create .t column configure 1 -tags column1 } -result {} test column-2.1 {column bbox: missing args} -body { .t column bbox } -returnCodes error -result {wrong # args: should be ".t column bbox column"} test column-2.2 {column bbox: invalid column} -body { .t column bbox foo } -returnCodes error -result {column "foo" doesn't exist} test column-2.3 {column bbox: tree doesn't show headers} -body { .t configure -showheader 0 .t column bbox column0 } -result {} test column-2.4 {column bbox} -body { .t configure -showheader 1 .t column bbox 0 } -result {2 2 484 6} test column-2.5 {column bbox: tail column not allowed} -body { .t column bbox tail } -returnCodes error -result {can't specify "tail" for this command} test column-3.1 {column configure: missing args} -body { .t column configure } -returnCodes error -result {wrong # args: should be ".t column configure column ?option? ?value? ?option value ...?"} test column-3.2 {column configure: invalid column} -body { .t column configure foo } -returnCodes error -result {column "foo" doesn't exist} test column-3.3 {column configure: list all options} -body { .t column configure column1 } -result {{-arrow {} {} none none} *} -match glob test column-3.4 {column configure: tail column} -body { .t column configure tail } -result {{-arrow {} {} none none} *} -match glob test column-3.4a {column configure: invalid option} -body { .t column configure tail -foo } -returnCodes error -result {unknown option "-foo"} test column-3.5 {column configure: invalid -arrow} -body { .t column configure column1 -arrow straight } -returnCodes error -result {bad arrow "straight": must be none, up, or down} test column-3.6 {column configure/cget: -arrow} -body { .t column configure column1 -arrow up .t column cget column1 -arrow } -result {up} test column-3.7 {column configure: invalid -arrowside} -body { .t column configure column1 -arrowside up } -returnCodes error -result {bad arrowside "up": must be left or right} test column-3.8 {column configure/cget: -arrowside} -body { .t column configure column1 -arrowside left .t column cget column1 -arrowside } -result {left} test column-3.9 {column configure: invalid -arrowgravity} -body { .t column configure column1 -arrowgravity both } -returnCodes error -result {bad arrowgravity "both": must be left or right} test column-3.10 {column configure/cget: -arrowgravity} -body { .t column configure column1 -arrowgravity right .t column cget column1 -arrowgravity } -result {right} test column-3.11 {column configure: invalid -arrowpadx} -body { .t column configure column1 -arrowpadx x } -returnCodes error -result {bad pad amount "x": must be a list of 1 or 2 positive screen distances} test column-3.11a {column configure: invalid 2 element -arrowpadx} -body { .t column configure column1 -arrowpadx {3 x} } -returnCodes error -result {bad pad amount "3 x": must be a list of 1 or 2 positive screen distances} test column-3.12 {column configure/cget: -arrowpadx} -body { .t column configure column1 -arrowpadx 8 .t column cget column1 -arrowpadx } -result {8} test column-3.12a {column configure/cget: 2 element -arrowpadx} -body { .t column configure column1 -arrowpadx {8 5} .t column cget column1 -arrowpadx } -result {8 5} test column-3.13 {column configure: invalid -bitmap} -body { .t column configure column1 -bitmap no-such-bitmap } -returnCodes error -result {bitmap "no-such-bitmap" not defined} test column-3.14 {column configure/cget: -bitmap} -body { .t column configure column1 -bitmap questhead .t column cget column1 -bitmap } -result {questhead} test column-3.15 {column configure: invalid -background} -body { .t column configure column1 -background foo } -returnCodes error -result {unknown color name "foo"} test column-3.16 {column configure/cget: -background} -body { .t column configure column1 -background magenta .t column cget column1 -background } -result {magenta} test column-3.17 {column configure: invalid -borderwidth} -body { .t column configure column1 -borderwidth x } -returnCodes error -result {bad screen distance "x"} test column-3.18 {column configure/cget: -borderwidth} -body { .t column configure column1 -borderwidth 4 .t column cget column1 -borderwidth } -result {4} test column-3.19 {column configure: invalid -button} -body { .t column configure column1 -button "" } -returnCodes error -result {expected boolean value but got ""} test column-3.20 {column configure/cget: -button} -body { .t column configure column1 -button off .t column cget column1 -button } -result {0} test column-3.21 {column configure: invalid -expand} -body { .t column configure column1 -expand ew } -returnCodes error -result {expected boolean value but got "ew"} test column-3.22 {column configure/cget: -expand} -body { .t column configure column1 -expand true .t column cget column1 -expand } -result {1} test column-3.23 {column configure: invalid -image} -body { .t column configure column1 -image questhead } -returnCodes error -result {image "questhead" doesn't exist} test column-3.24 {column configure/cget: -image} -body { .t column configure column1 -image emptyImg .t column cget column1 -image } -result {emptyImg} test column-3.25 {column configure: invalid -imagepadx} -body { .t column configure column1 -imagepadx y } -returnCodes error -result {bad pad amount "y": must be a list of 1 or 2 positive screen distances} test column-3.25a {column configure: invalid 2 element -imagepadx} -body { .t column configure column1 -imagepadx "y \{" } -returnCodes error -result {unmatched open brace in list} test column-3.26 {column configure/cget: -imagepadx} -body { .t column configure column1 -imagepadx 9 -imagepady 4 list [.t column cget column1 -imagepadx] \ [.t column cget column1 -imagepady] } -result {9 4} test column-3.26a {column configure/cget: 2 element -imagepadx/y} -body { .t column configure column1 -imagepadx {9 0} -imagepady {4 3} list [.t column cget column1 -imagepadx] \ [.t column cget column1 -imagepady] } -result {{9 0} {4 3}} test column-3.27 {column configure: invalid -itembackground} -body { .t column configure column1 -itembackground no } -returnCodes error -result {unknown color or gradient name "no"} test column-3.28 {column configure/cget: simple -itembackground} -body { .t column configure column1 -itembackground blue .t column cget column1 -itembackground } -result {blue} test column-3.29 {column configure: invalid -itembackground list} -body { .t column configure column1 -itembackground {blue selected green active} } -returnCodes error -result {unknown color or gradient name "selected"} test column-3.30 {column configure/cget: -itembackground list} -body { .t column configure column1 -itembackground {blue green magenta red} .t column cget column1 -itembackground } -result {blue green magenta red} test column-3.31 {column configure: invalid -justify} -body { .t column configure column1 -justify no } -returnCodes error -result {bad justification "no": must be left, right, or center} test column-3.32 {column configure/cget: simple -justify} -body { .t column configure column1 -justify center .t column cget column1 -justify } -result {center} test column-3.33 {column configure: invalid -minwidth} -body { .t column configure column1 -minwidth z } -returnCodes error -result {bad screen distance "z"} test column-3.34 {column configure/cget: -minwidth} -body { .t column configure column1 -minwidth 25 .t column cget column1 -minwidth } -result {25} test column-3.35 {column configure: invalid -state} -body { .t column configure column1 -state yes } -returnCodes error -result {bad state "yes": must be normal, active, or pressed} test column-3.36 {column configure/cget: -state} -body { .t column configure column1 -state pressed .t column cget column1 -state } -result {pressed} test column-3.37 {column configure: invalid -stepwidth} -constraints { deprecated } -body { .t column configure column1 -stepwidth "\t" } -returnCodes error -result {bad screen distance " "} test column-3.38 {column configure/cget: -stepwidth} -constraints { deprecated } -body { .t column configure column1 -stepwidth 125 .t column cget column1 -stepwidth } -result {125} test column-3.41 {column configure: -text} -body { .t column configure column1 -text "Text above Column 1" .t column cget column1 -text } -result {Text above Column 1} test column-3.42 {column configure: invalid -textpadx} -body { .t column configure column1 -textpadx baz } -returnCodes error -result {bad pad amount "baz": must be a list of 1 or 2 positive screen distances} test column-3.42a {column configure: invalid 2 element -textpadx} -body { .t column configure column1 -textpadx {foo bar baz} } -returnCodes error -result {bad pad amount "foo bar baz": must be a list of 1 or 2 positive screen distances} test column-3.43 {column configure/cget: -textpadx/y} -body { .t column configure column1 -textpadx 8 -textpady 5 list [.t column cget column1 -textpadx] \ [.t column cget column1 -textpady] } -result {8 5} test column-3.43a {column configure/cget: 2 element -textpadx/y} -body { .t column configure column1 -textpadx {8 4} -textpady {4 5} list [.t column cget column1 -textpadx] \ [.t column cget column1 -textpady] } -result {{8 4} {4 5}} test column-3.44 {column configure: invalid -width} -body { .t column configure column1 -width all } -returnCodes error -result {bad screen distance "all"} test column-3.45 {column configure/cget: -width} -body { .t column configure column1 -width 250 .t column cget column1 -width } -result {250} test column-3.46 {column configure: invalid -visible} -body { .t column configure column1 -visible never } -returnCodes error -result {expected boolean value but got "never"} test column-3.47 {column configure/cget: -visible} -body { .t column configure column1 -visible no .t column cget column1 -visible } -result {0} test column-3.48 {column configure: invalid -widthhack} -constraints { deprecated } -body { .t column configure column1 -widthhack ok } -returnCodes error -result {expected boolean value but got "ok"} test column-3.49 {column configure/cget: -widthhack} -constraints { deprecated } -body { .t column configure column1 -widthhack yes .t column cget column1 -widthhack } -result {1} test column-4.1 {column configure: -tags} -body { .t column configure column1 -tags column2 .t column cget column1 -tags } -returnCodes error -result {column "column1" doesn't exist} test column-4.2 {column configure: -tags} -body { .t column cget column2 -tags } -result {column2} test column-4.3 {column cget: -tags of tail} -body { .t column cget tail -tags } -result {} test column-4.4 {column configure/cget: -tags of tail} -body { .t column configure tail -tags head } -result {} test column-4.5 {column cget: specify tail by its tag} -body { .t column cget head -tags } -result {head} test column-5.1 {column delete: missing args} -body { .t column delete } -returnCodes error -result {wrong # args: should be ".t column delete first ?last?"} test column-5.2 {column delete: column tail} -body { .t column delete tail } -returnCodes error -result {can't specify "tail" for this command} test column-5.3 {column delete: first column} -body { .t column delete 0 } -result {} test column-5.4 {deleted column doesn't exist} -body { .t column cget 0 -tags } -returnCodes error -result {column "0" doesn't exist} test column-5.5 {column delete: all} -body { .t column delete all .t column list } -result {} test column-5.6 {column delete: range of 1} -body { .t column create -tags column1 .t column create -tags column2 .t column create -tags column3 .t column create -tags column4 .t column delete column1 column1 .t column list } -result {1 2 3} test column-5.7 {column delete: range of 2, reverse order} -body { .t column delete column4 column3 .t column list } -result {1} test column-6.1 {column id: missing args} -body { .t column id } -returnCodes error -result {wrong # args: should be ".t column id column"} test column-6.2 {column id: the easy case} -body { .t column id 1 } -result {1} test column-6.3 {column id} -body { .t column id column2 } -result {1} test column-6.4 {column id: tail column} -body { .t column id tail } -result {tail} test column-6.5 {column id: first column} -body { .t column id first } -result {1} test column-6.6 {column id: last column} -body { .t column id last } -result {1} test column-6.7 {column id: tail prev} -body { .t column id "tail prev" } -result {1} test column-7.1 {column move: missing args} -body { .t column move } -returnCodes error -result {wrong # args: should be ".t column move column before"} test column-7.2 {column move: invalid column} -body { .t column move 0 2 } -returnCodes error -result {column "0" doesn't exist} test column-7.3 {column move: move column2} -body { .t column create -tags column1 .t column create -tags column3 .t column move column2 column3 .t column order column2 } -result {1} test column-7.4 {correct moved?} -body { set res {} for {set x 0} {$x < [.t column count]} {incr x} { lappend res [.t column cget "order $x" -tags] } set res } -result {column1 column2 column3} test column-7.5 {column move: tail to the left} -body { .t column move tail column1 } -returnCodes error -result {can't specify "tail" for this command} test column-7.6 {column move: tail as before is ok} -body { .t column move column1 tail .t column order column1 } -result {2} test column-8.1 {column width: missing args} -body { .t column width } -returnCodes error -result {wrong # args: should be ".t column width column"} test column-8.2 {column width: invalid column} -body { .t column width foo } -returnCodes error -result {column "foo" doesn't exist} test column-8.3 {column width: tail column returns always 0} -body { .t column width tail } -result {0} test column-8.4 {column width} -body { .t element create eText2 text -font {{courier -12}} -text "Hello World" .t style create testStyle3 .t style elements testStyle3 eText2 .t item style set 1 column1 testStyle3 update idletasks list [.t column width column1] [font measure {courier -12} "Hello World"] } -result {77 77} test column-9.1 {column neededwidth: missing args} -body { .t column neededwidth } -returnCodes error -result {wrong # args: should be ".t column neededwidth column"} test column-9.2 {column neededwidth: invalid column} -body { .t column neededwidth foo } -returnCodes error -result {column "foo" doesn't exist} test column-9.3 {column neededwidth: tail column returns always 0} -body { .t column neededwidth tail } -result {0} test column-9.4 {column neededwidth} -body { .t column neededwidth column1 } -result {77} test column-10.1 {-itemstyle: not for tail} -body { .t column configure tail -itemstyle testStyle3 } -returnCodes error -result {can't change the -itemstyle option of the tail column} test column-10.2 {-itemstyle: set} -body { .t column configure column1 -itemstyle testStyle3 .t column cget column1 -itemstyle } -result {testStyle3} test column-10.3 {-itemstyle: unset} -body { .t column configure column1 -itemstyle {} .t column cget column1 -itemstyle } -result {} test column-10.4 {-itemstyle: change} -body { .t style create testStyle2 .t column configure column1 -itemstyle testStyle2 .t column cget column1 -itemstyle } -result {testStyle2} test column-10.5 {-itemstyle: style is deleted} -body { .t style delete testStyle2 .t column cget column1 -itemstyle } -result {} test column-11.1 {column count: too many args} -body { .t column count a b } -returnCodes error -result {wrong # args: should be ".t column count ?columnDesc?"} test column-11.2 {column count: no args} -body { .t column count } -result {3} test column-11.3 {column count: with desc} -body { .t column count "range first last" } -result {3} test column-11.4 {column count: all includes tail} -body { .t column count all } -result {4} test column-11.5 {column count: unknown tag} -body { .t column count {tag foo} } -result {0} test column-12.1 {column configure: passing args to header configure} -setup { .t column create -tags column0 } -body { set opts {} foreach info [.t column configure column0] { foreach {name x y default current} $info {} lappend opts $name $current } eval .t column configure column0 $opts } -result {} test column-12.2 {column configure: -font is per-state in text element} -setup { .t column create -tags column1 -text "Column 1" .t column configure column1 -font {Courier 10 bold} } -result {} test column-99.1 {some needed cleanup} -body { destroy .t } -result {} # cleanup image delete emptyImg ::tcltest::cleanupTests return tktreectrl-2.4.1/tests/display.test0000644000076400010400000004345111570775000017734 0ustar TimAdministrators# Commands covered: display code # # This file contains a collection of tests for the style widget command of # the tktreectrl extension. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2000 by Scriptics Corporation. # Copyright (c) 2002 by Christian Krone. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } package require Tk package require treectrl test display-0.1 {some needed preparations} -body { # The size of the window is important. pack [treectrl .t -width 500 -height 400] .t element create e1 text -text "Hello," .t element create e2 window -destroy yes .t element create e3 text -text " world!" .t style create S1 .t style elements S1 {e1 e2 e3} .t style layout S1 e2 -iexpand x -squeeze x .t column create -text "Column 0" -tags C0 -itemstyle S1 .t column create -text "Column 1" -tags C1 -itemstyle S1 .t column create -text "Column 2" -tags C2 -itemstyle S1 .t column create -text "Column 3" -tags C3 -itemstyle S1 foreach I [.t item create -count 10 -parent root] { foreach C [.t column list] { .t item element configure $I $C e2 -window [entry .t.w${I}C$C] } } update ; # make sure it is visible } -result {} test display-1.1 {: hide some items} -body { .t notify bind .t { puts -nonewline "%P visible=[list [lsort -integer %v]] hidden=[list [lsort -integer %h]]" } .t item configure {list {2 5 9}} -visible no update idletasks } -output { visible={} hidden={2 5 9}} test display-1.2 {: show some items} -body { .t item configure {list {9 2}} -visible yes update idletasks } -output { visible={2 9} hidden={}} test display-1.3 {: hide & show some items} -body { .t item configure {list {5}} -visible yes .t item configure {list {6 7}} -visible no update idletasks } -output { visible=5 hidden={6 7}} test display-1.4 {: delete an item when it becomes visible} -body { .t notify bind .t { %T item delete {list %v} } .t notify bind .t { puts -nonewline "%P [list [lsort -integer %i]]" } .t item configure 6 -visible yes # Deleting an item that is being displayed should not segfault. update idletasks } -output { 6} test display-2.1 {: resizing a column resizes a window element} -body { set w [.t item element cget 2 C1 e2 -window] bind $w { puts -nonewline " %W" } .t column configure C1 -width 100 update idletasks } -output { .t.w2C1} test display-2.2 {: delete a column when a window in a previous column is resized during a display update} -body { set w [.t item element cget 2 C1 e2 -window] bind $w {+ .t column delete C2 } .t column configure C1 -width 150 # Deleting a column while displaying an item should not segfault. update idletasks } -output { .t.w2C1} test display-2.3 {: delete a column when a window in a previous column is resized during a display update} -body { set w [.t item element cget 2 C1 e2 -window] bind $w { .t item delete 2 } .t column configure C1 -width 100 # Deleting an item while displaying it should not segfault. update idletasks } -output { 2} test display-3.1 {} -body { .t configure -width 200 update idletasks .t notify bind .t { puts -nonewline "%P" } .t xview moveto 1.0 update idletasks } -output {} test display-3.2 {: delete an item while scrolling} -body { .t notify bind .t { .t item delete 8 .t notify unbind .t } .t xview moveto 0.0 # Causing a display update while scrolling (during a display update) should # restart the display update and not operate on deleted items. update idletasks } -output { 8} test display-3.3 {delete the tree during a display update} -body { .t notify bind .t { destroy .t } .t item configure 4 -visible no update idletasks winfo exists .t } -result {0} # Create a 40x40 item # Check bounds via [item bbox], [marquee identify] and [item id "nearest x y"] # Configure -canvaspadx and -canvaspady with positive values # Check item bounds # Create another 40x40 item to right of the first (horizontal layout) # Check item bounds # Configure -itemgapx with positive value # Check item bounds test display-4.1 {item layout} -setup { catch {destroy .t} pack [treectrl .t -width 500 -height 500] .t configure -showroot 0 -showheader 0 -highlightthickness 0 \ -borderwidth 0 -orient horizontal .t column create -tags C1 .t element create E1 rect -width 40 -height 40 .t style create S1 .t style elements S1 [list E1] .t item create -parent root -tags I1 .t item style set I1 C1 S1 update ; # make sure it is visible } -body { .t item bbox I1 } -result {0 0 40 40} test display-4.2 {item layout} -setup { .t configure -canvaspadx 10 } -body { .t item bbox I1 } -result {10 0 50 40} test display-4.3 {item layout} -setup { .t configure -canvaspadx 0 -canvaspady 10 } -body { .t item bbox I1 } -result {0 10 40 50} test display-4.4 {item layout} -setup { .t configure -canvaspadx 10 -canvaspady 10 } -body { .t item bbox I1 } -result {10 10 50 50} test display-4.5 {item layout} -body { .t identify 0 0 } -result {} test display-4.6 {item layout} -body { .t identify 9 9 } -result {} test display-4.7 {item layout} -body { .t identify 50 50 } -result {} test display-4.8 {item layout} -body { .t identify 50 10 } -result {} test display-4.9 {item layout} -body { .t identify 10 50 } -result {} test display-4.10 {item layout} -body { .t identify 10 10 } -result {item 1 column 0 elem E1} test display-4.11 {item layout} -body { .t identify 49 10 } -result {item 1 column 0 elem E1} test display-4.12 {item layout} -body { .t identify 10 49 } -result {item 1 column 0 elem E1} test display-4.13 {item layout} -setup { .t item create -parent root -tags I2 .t item style set I2 C1 S1 } -body { .t item bbox I2 } -result {50 10 90 50} test display-4.14 {item layout} -body { .t identify 50 10 } -result {item 2 column 0 elem E1} test display-4.15 {item layout} -body { .t identify 90 10 } -result {} test display-4.16 {item layout} -body { .t item id "nearest 0 0" } -result {1} test display-4.17 {item layout} -body { .t item id "nearest 10 10" } -result {1} test display-4.18 {item layout} -body { .t item id "nearest 100 100" } -result {2} test display-4.19 {item layout} -body { .t marquee coords 0 0 100 10 .t marquee identify } -result {} test display-4.20 {item layout} -body { .t marquee coords 0 50 100 60 .t marquee identify } -result {} test display-4.21 {item layout} -body { .t marquee coords 90 0 100 100 .t marquee identify } -result {} test display-4.22 {item layout} -body { .t marquee coords 10 10 11 11 .t marquee identify } -result {{1 {0 E1}}} test display-4.23 {item layout} -body { .t marquee coords 50 10 51 11 .t marquee identify } -result {{2 {0 E1}}} test display-4.24 {item layout} -body { .t marquee coords 49 10 61 11 .t marquee identify } -result {{1 {0 E1}} {2 {0 E1}}} test display-4.25 {item layout} -setup { .t configure -itemgapx 10 } -body { .t item bbox I1 } -result {10 10 50 50} test display-4.26 {item layout} -body { .t item bbox I2 } -result {60 10 100 50} test display-4.27 {item layout} -body { .t identify 50 10 } -result {} test display-4.28 {item layout} -body { .t identify 59 10 } -result {} test display-4.29 {item layout} -body { .t identify 60 10 } -result {item 2 column 0 elem E1} test display-4.30 {item layout} -body { .t marquee coords 50 0 60 100 .t marquee identify } -result {} test display-4.31 {item layout} -body { .t marquee coords 100 0 110 100 .t marquee identify } -result {} test display-4.32 {item layout} -body { .t marquee coords 10 10 60 20 .t marquee identify } -result {{1 {0 E1}}} test display-4.33 {item layout} -body { .t marquee coords 10 10 61 20 .t marquee identify } -result {{1 {0 E1}} {2 {0 E1}}} test display-4.34 {item layout} -body { .t item id "nearest 50 10" } -result {1} test display-4.35 {item layout: < half-way between} -body { .t item id "nearest 54 10" } -result {1} test display-4.36 {item layout: >= half-way between} -body { .t item id "nearest 55 10" } -result {2} test display-5.1 {item layout} -setup { catch {destroy .t} pack [treectrl .t -width 500 -height 500] .t configure -showroot 0 -showheader 0 -highlightthickness 0 \ -borderwidth 0 -orient vertical -indent 20 .t column create -tags C1 .t configure -treecolumn C1 .t element create E1 rect -width 100 -height 20 .t style create S1 .t style elements S1 [list E1] .t item create -button yes -parent root -tags I1 .t item style set I1 C1 S1 update ; # make sure it is visible } -body { .t item bbox I1 } -result {0 0 120 20} test display-5.2 {button hit-testing} -setup { } -body { .t identify 0 0 } -result {item 1 button} test display-5.3 {button hit-testing} -setup { .t configure -canvaspadx 20 } -body { .t identify 20 0 } -result {item 1 button} test display-6.1 {no unlocked columns: no canvaspadx/y} -setup { destroy .t pack [treectrl .t] .t configure -showheader no -borderwidth 5 -highlightthickness 5 .t column create -tags C0 -lock left -width 100 .t item configure root -height 20 if 0 { .t style create s .t style elements s [.t element create e rect -fill blue] .t style layout s e -iexpand xy .t item style set root C0 s } update } -body { .t item bbox root C0 } -result {10 10 110 30} test display-6.2 {no unlocked columns: -canvaspadx ignored, -canvaspady used} -setup { .t configure -canvaspadx 10 -canvaspady 10 } -body { .t item bbox root C0 } -result {10 20 110 40} test display-6.3 {no unlocked columns: -canvaspadx ignored, -canvaspady used} -body { .t identify 10 10 } -result {} test display-6.4 {no unlocked columns: -canvaspadx ignored, -canvaspady used} -body { .t identify 10 19 } -result {} test display-6.5 {no unlocked columns: -canvaspadx ignored, -canvaspady used} -body { .t identify 10 20 } -result {item 0 column 0} proc colWid {args} { foreach c $args { lappend result [.t column width $c] } return $result } test display-7.0 {column spanning: span=1} -setup { destroy .t pack [treectrl .t] .t configure -showheader no -borderwidth 0 -highlightthickness 0 .t column create -tags C0 .t element create e1 rect -width 100 -height 20 .t style create s1 -orient horizontal .t style elements s1 e1 .t item style set root C0 s1 } -body { colWid C0 } -result {100} test display-7.1 {column spanning: span=2} -setup { .t column create -tags C1 .t item span root C0 2 } -body { colWid C0 C1 } -result {50 50} test display-7.2 {column spanning: span=3} -setup { .t column create -tags C2 .t item span root C0 3 } -body { colWid C0 C1 C2 } -result {34 33 33} test display-7.3 {column spanning: span=4} -setup { .t column create -tags C3 .t item span root C0 4 } -body { colWid C0 C1 C2 C3 } -result {25 25 25 25} test display-7.4 {column spanning: span=5} -setup { .t column create -tags C4 .t item span root C0 5 } -body { colWid C0 C1 C2 C3 C4 } -result {20 20 20 20 20} test display-7.5 {column spanning: minwidth > 0} -setup { .t column configure all -minwidth 10 } -body { colWid C0 C1 C2 C3 C4 } -result {20 20 20 20 20} test display-7.6 {column spanning: minwidth > 0} -setup { .t column configure C0 -minwidth 30 } -body { colWid C0 C1 C2 C3 C4 } -result {30 18 18 17 17} test display-7.7 {column spanning: minwidth > 0} -setup { .t column configure C2 -minwidth 30 } -body { colWid C0 C1 C2 C3 C4 } -result {30 14 30 13 13} test display-7.8 {column spanning: minwidth > 0} -setup { .t column configure all -minwidth 30 } -body { colWid C0 C1 C2 C3 C4 } -result {30 30 30 30 30} test display-7.20 {column spanning: maxwidth > 0} -setup { .t column configure all -minwidth "" .t column configure C1 -maxwidth 15 } -body { colWid C0 C1 C2 C3 C4 } -result {22 15 21 21 21} test display-7.21 {column spanning: maxwidth > 0} -setup { .t column configure C0 -maxwidth 15 } -body { colWid C0 C1 C2 C3 C4 } -result {15 15 24 23 23} test display-7.30 {column spanning: width > 0} -setup { .t column configure all -maxwidth "" .t column configure C3 -width 50 } -body { colWid C0 C1 C2 C3 C4 } -result {13 13 12 50 12} test display-7.31 {column spanning: width > 0} -setup { .t column configure C0 -width 20 } -body { colWid C0 C1 C2 C3 C4 } -result {20 10 10 50 10} test display-7.40 {column spanning: hidden columns} -setup { .t column configure all -width "" .t column configure C2 -visible no } -body { colWid C0 C1 C2 C3 C4 } -result {25 25 0 25 25} test display-7.41 {column spanning: hidden columns} -setup { .t column configure C4 -visible no } -body { colWid C0 C1 C2 C3 C4 } -result {34 33 0 33 0} test display-7.42 {column spanning: hidden columns} -setup { .t column configure all -visible no } -body { colWid C0 C1 C2 C3 C4 } -result {0 0 0 0 0} test display-7.50 {column spanning: trim the fat} -setup { .t column configure all -visible yes .t item span root all 1 .t item style set root C1 s1 .t item element configure root C0 e1 -width 75 .t item element configure root C1 e1 -width 25 .t item create -tags item1 .t item style set item1 C0 s1 .t item element configure item1 C0 e1 -width 100 .t item span item1 C0 2 } -body { colWid C0 C1 C2 C3 C4 } -result {75 25 0 0 0} proc itemWid {args} { foreach i $args { scan [.t item bbox $i] "%d %d %d %d" x1 y1 x2 y2 lappend result [expr {$x2 - $x1}] } return $result } test display-8.1 {item width} -setup { destroy .t pack [treectrl .t] .t column create -tags C0 .t element create e rect -width 55 -height 20 .t style create s .t style elements s e .t item style set root C0 s } -body { itemWid root } -result {55} test display-8.2 {-itemwidth ignored without wrapping} -body { .t configure -itemwidth 100 itemWid root } -result {55} test display-8.3 {-itemwidth plus -wrap} -body { .t configure -itemwidth 100 -wrap {1 items} itemWid root } -result {100} test display-8.4 {-itemwidth overrides -itemwidthmultiple} -body { .t configure -itemwidth 100 -itemwidthmultiple 55 itemWid root } -result {100} test display-8.5 {-itemwidthmultiple} -body { .t configure -itemwidth "" -itemwidthmultiple 55 itemWid root } -result {55} test display-8.6 {-itemwidthmultiple} -body { .t configure -itemwidth "" -itemwidthmultiple 60 itemWid root } -result {60} test display-8.7 {-itemwidthmultiple} -body { .t configure -itemwidth "" -itemwidthmultiple 50 itemWid root } -result {100} test display-8.20 {item width} -setup { .t item create -tags item1 -parent root .t item style set item1 C0 s .t item element configure item1 C0 e -width 40 .t configure -itemwidth "" -itemwidthmultiple "" } -body { itemWid root item1 } -result {55 40} test display-8.21 {-itemwidthmultiple} -body { .t configure -itemwidth "" -itemwidthmultiple 55 itemWid root item1 } -result {55 55} test display-8.22 {-itemwidthmultiple} -body { .t configure -itemwidth "" -itemwidthmultiple 40 itemWid root item1 } -result {80 40} test display-8.23 {-itemwidth} -body { .t configure -itemwidth 100 -itemwidthmultiple 40 itemWid root item1 } -result {100 100} test display-8.24 {-itemwidthequal} -body { .t configure -itemwidth "" -itemwidthmultiple "" -itemwidthequal yes itemWid root item1 } -result {55 55} test display-8.25 {-itemwidthequal with -itemwidthmultiple} -body { .t configure -itemwidth "" -itemwidthmultiple 40 -itemwidthequal yes itemWid root item1 } -result {80 80} test display-8.30 {column width} -body { colWid C0 } -result {55} test display-8.31 {column -width overrides -itemwidth} -body { .t column configure C0 -width 123 itemWid root item1 } -result {123 123} test display-8.32 {header width doesn't affect item width with -wrap} -setup { image create photo headerImage -width 175 -height 20 } -body { .t column configure C0 -width "" -image headerImage -imagepadx 0 .t configure -itemwidth "" -itemwidthmultiple "" -itemwidthequal no concat [colWid C0] [itemWid root item1] } -result {175 55 40} test display-8.33 {header width doesn't affect item width with -wrap} -body { .t configure -itemwidth "" -itemwidthmultiple "" -itemwidthequal yes concat [colWid C0] [itemWid root item1] } -result {175 55 55} test display-8.34 {header width does affect item width without -wrap} -body { .t configure -itemwidth "" -itemwidthmultiple "" -itemwidthequal yes -wrap {} concat [colWid C0] [itemWid root item1] } -result {175 175 175} test display-8.35 {horizontal layout, item width unaffected by -wrap} -body { .t configure -orient horizontal concat [colWid C0] [itemWid root item1] } -result {175 55 55} test display-8.36 {horizontal layout, item width unaffected by -wrap} -body { .t configure -itemwidthequal no concat [colWid C0] [itemWid root item1] } -result {175 55 40} test style-99.1 {some needed cleanup} -body { destroy .t } -result {} # cleanup ::tcltest::cleanupTests return tktreectrl-2.4.1/tests/element.test0000644000076400010400000001107511565025641017720 0ustar TimAdministrators# Commands covered: [element] # # This file contains a collection of tests for the style widget command of # the tktreectrl extension. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2000 by Scriptics Corporation. # Copyright (c) 2002 by Christian Krone. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } package require Tk package require treectrl test element-0.1 {some needed preparations} -body { pack [treectrl .t] } -result {} test element-1.1 {element: missing command} -body { .t element } -returnCodes error -result {wrong # args: should be ".t element command ?arg arg ...?"} test element-1.2 {element: invalid command} -body { .t element foo } -returnCodes error -result {bad command "foo": must be *} -match glob ### test element-2.1 {element cget: missing arg} -body { .t element cget } -returnCodes error -result {wrong # args: should be ".t element cget name option"} test element-2.2 {element cget: too many args} -body { .t element cget a b c d } -returnCodes error -result {wrong # args: should be ".t element cget name option"} test element-2.3 {element cget: unknown elem} -body { .t element cget foo a } -returnCodes error -result {element "foo" doesn't exist} ### test element-3.1 {element configure: missing arg} -body { .t element configure } -returnCodes error -result {wrong # args: should be ".t element configure name ?option? ?value option value ...?"} test element-3.2 {element configure: unknown elem} -body { .t element configure foo } -returnCodes error -result {element "foo" doesn't exist} ### test element-4.1 {element create: missing arg} -body { .t element create } -returnCodes error -result {wrong # args: should be ".t element create name type ?option value ...?"} test element-4.2 {element create: empty type} -body { .t element create foo "" } -returnCodes error -result {invalid element type ""} test element-4.3 {element create: ambiguous type} -body { .t element create foo b ; # bitmap or border } -returnCodes error -result {ambiguous element type "b"} test element-4.4 {element create: unknown type} -body { .t element create foo bar } -returnCodes error -result {unknown element type "bar"} ### test element-5.1 {element delete: no args} -body { .t element delete } -result {} test element-5.2 {element delete: unknown elem} -body { .t element delete foo } -returnCodes error -result {element "foo" doesn't exist} test element-5.3 {element delete: single elem} -setup { .t element create e1 bitmap } -body { .t element delete e1 .t element names } -result {} test element-5.4 {element delete: multiple elems} -setup { foreach type [list bitmap border image rect text window] { .t element create e$type $type } } -body { eval .t element delete [.t element names] .t element names } -result {} ### test element-6.1 {element names: too many args} -body { .t element names a } -returnCodes error -result {wrong # args: should be ".t element names"} ### test element-7.1 {element perstate: missing arg} -body { .t element perstate } -returnCodes error -result {wrong # args: should be ".t element perstate element option stateList"} test element-7.2 {element perstate: too many args} -body { .t element perstate a b c d } -returnCodes error -result {wrong # args: should be ".t element perstate element option stateList"} test element-7.3 {element perstate: empty stateList} -setup { .t element create eText text -fill {red !selected blue {}} } -body { .t element perstate eText -fill {} } -result {red} test element-7.4 {element perstate: non-empty statelist} -body { .t element perstate eText -fill {selected} } -result {blue} ### test element-8.1 {element type: missing arg} -body { .t element type } -returnCodes error -result {wrong # args: should be ".t element type name"} test element-8.2 {element type: too many args} -body { .t element type a b } -returnCodes error -result {wrong # args: should be ".t element type name"} test element-8.3 {element type: unknown elem} -body { .t element type foo } -returnCodes error -result {element "foo" doesn't exist} test element-8.4 {element type: success} -body { .t element type eText } -result {text} test element-99.1 {some needed cleanup} -body { destroy .t } -result {} # cleanup ::tcltest::cleanupTests return tktreectrl-2.4.1/tests/header.test0000644000076400010400000011344411567276233017531 0ustar TimAdministrators# Commands covered: treectrl's widget command header # # This file contains a collection of tests for the header widget command of # the tktreectrl extension. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2011 by Tim Baker. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } package require Tk package require treectrl test header-0.1 {some needed preparations} -body { pack [treectrl .t -usetheme no] # The default borderwidth in Tk 8.4 is "2" while in Tk 8.5 it is "1" .t configure -borderwidth 1 # If a treectrl has never been mapped then Tk_Width and Tk_Height return 1 update } -result {} test header-0.2 {create an image} -body { image create photo emptyImg } -result {emptyImg} test header-1.1 {missing args} -body { .t header } -returnCodes error -result {wrong # args: should be ".t header command ?arg arg ...?"} test header-1.2 {unknown command} -body { .t header foo } -returnCodes error -result {bad command "foo": must be *} -match glob test header-1.3 {default header exists} -body { .t header count } -result {1} test header-1.4 {default header exists} -body { .t header id all } -result {0} test header-1.5 {no header exists with numerical index} -body { .t header configure 1 } -returnCodes error -result {header "1" doesn't exist} test header-1.6 {configure: no header exists with tag} -body { .t header configure header0 } -returnCodes error -result {header "header0" doesn't exist} test header-1.7 {header-column tail exists} -body { .t header cget 0 tail -arrow } -result {none} test header-2.1 {header bbox: missing args} -body { .t header bbox } -returnCodes error -result {wrong # args: should be ".t header bbox header ?column? ?element?"} test header-2.2 {header bbox: too many args} -body { .t header bbox a b c d } -returnCodes error -result {wrong # args: should be ".t header bbox header ?column? ?element?"} test header-2.3 {header bbox: invalid header} -body { .t header bbox foo } -returnCodes error -result {header "foo" doesn't exist} test header-2.4 {header bbox: no visible columns, tail isn't shown} -body { # When there are no visible columns, a header isn't ReallyVisible .t header bbox 0 } -result {} test header-2.5 {header bbox: zero-sized visible column} -setup { .t column create -width 0 -tags column0 } -body { .t header bbox 0 } -result {2 2 202 6} test header-2.6 {header bbox: zero-sized visible -lock=left column} -setup { .t column configure column0 -lock left } -body { .t header bbox 0 } -cleanup { .t column configure column0 -lock none } -result {2 2 202 6} test header-2.6.1 {header bbox: no visible columns is same as no columns} -setup { .t column configure column0 -lock left -visible no } -body { # When there are no visible columns, a header isn't ReallyVisible .t header bbox 0 } -result {} test header-2.7 {header bbox: tree doesn't show headers} -setup { .t configure -showheader 0 } -body { .t header bbox 0 } -cleanup { .t column delete column0 .t configure -showheader 1 } -result {} test header-2.8 {header bbox: header is not visible} -setup { .t header configure first -visible no } -body { .t header bbox first } -result {} if 0 { test header-2.9 {header bbox: header is ownerdrawn but has no style} -setup { .t header configure first -visible yes -ownerdrawn yes } -body { .t header bbox first } -cleanup { .t header configure first -ownerdrawn no } -result {2 2 202 2} } test header-2.20 {header bbox: invalid column} -body { .t header configure first -visible yes .t header bbox 0 first } -returnCodes error -result {column "first" doesn't exist} test header-2.21 {header bbox: tree doesn't show headers} -setup { .t column create -tags column0 .t element create e rect -width 482 -height 20 .t style create s .t style elements s e set i [.t item create -parent root] .t item style set $i column0 s .t column create -tags column1 .t configure -showheader 0 } -body { .t header bbox 0 column0 } -result {} test header-2.22 {header bbox: tree does show headers} -setup { .t configure -showheader 1 } -body { .t header bbox 0 column0 } -cleanup { .t style delete s .t element delete e } -result {2 2 484 6} test header-2.23 {header bbox: tail column not allowed} -body { .t header bbox first tail } -returnCodes error -result {can't specify "tail" for this command} test header-2.30 {header bbox: no style} -body { .t header bbox first column0 foo } -returnCodes error -result {header 0 column 0 has no style} test header-2.31 {header bbox: unknown element} -setup { .t style create s -statedomain header .t element create e rect -statedomain header -width 482 -height 20 .t style elements s e .t header style set first column0 s } -body { .t header bbox first column0 foo } -returnCodes error -result {element "foo" doesn't exist} test header-2.32 {header bbox: element} -body { .t column configure column0 -width "" .t header bbox first column0 e } -cleanup { .t header style set first column0 "" } -result {2 2 484 22} test header-3.1 {header configure: missing args} -body { .t header configure } -returnCodes error -result {wrong # args: should be ".t header configure header ?column? ?option? ?value? ?option value ...?"} test header-3.2 {header configure: invalid header} -body { .t header configure foo } -returnCodes error -result {header "foo" doesn't exist} test header-3.3 {header configure: list all options} -body { .t header configure first column1 } -result {{-arrow {} {} none none} *} -match glob test header-3.4 {header configure: tail column} -body { .t header configure first tail } -result {{-arrow {} {} none none} *} -match glob test header-3.4a {header configure: invalid option} -body { .t header configure first tail -foo } -returnCodes error -result {unknown option "-foo"} test header-3.5 {header configure: invalid -arrow} -body { .t header configure first column1 -arrow straight } -returnCodes error -result {bad arrow "straight": must be none, up, or down} test header-3.6 {header configure/cget: -arrow} -body { .t header configure first column1 -arrow up .t header cget first column1 -arrow } -result {up} test header-3.7 {header configure: invalid -arrowside} -body { .t header configure first column1 -arrowside up } -returnCodes error -result {bad arrowside "up": must be left or right} test header-3.8 {header configure/cget: -arrowside} -body { .t header configure first column1 -arrowside left .t header cget first column1 -arrowside } -result {left} test header-3.9 {header configure: invalid -arrowgravity} -body { .t header configure first column1 -arrowgravity both } -returnCodes error -result {bad arrowgravity "both": must be left or right} test header-3.10 {header configure/cget: -arrowgravity} -body { .t header configure first column1 -arrowgravity right .t header cget first column1 -arrowgravity } -result {right} test header-3.11 {header configure: invalid -arrowpadx} -body { .t header configure first column1 -arrowpadx x } -returnCodes error -result {bad pad amount "x": must be a list of 1 or 2 positive screen distances} test header-3.11a {header configure: invalid 2 element -arrowpadx} -body { .t header configure first column1 -arrowpadx {3 x} } -returnCodes error -result {bad pad amount "3 x": must be a list of 1 or 2 positive screen distances} test header-3.12 {header configure/cget: -arrowpadx} -body { .t header configure first column1 -arrowpadx 8 .t header cget first column1 -arrowpadx } -result {8} test header-3.12a {header configure/cget: 2 element -arrowpadx} -body { .t header configure first column1 -arrowpadx {8 5} .t header cget first column1 -arrowpadx } -result {8 5} test header-3.13 {header configure: invalid -bitmap} -body { .t header configure first column1 -bitmap no-such-bitmap } -returnCodes error -result {bitmap "no-such-bitmap" not defined} test header-3.14 {header configure/cget: -bitmap} -body { .t header configure first column1 -bitmap questhead .t header cget first column1 -bitmap } -result {questhead} test header-3.15 {header configure: invalid -background} -body { .t header configure first column1 -background foo } -returnCodes error -result {unknown color name "foo"} test header-3.16 {header configure/cget: -background} -body { .t header configure first column1 -background magenta .t header cget first column1 -background } -result {magenta} test header-3.17 {header configure: invalid -borderwidth} -body { .t header configure first column1 -borderwidth x } -returnCodes error -result {bad screen distance "x"} test header-3.18 {header configure/cget: -borderwidth} -body { .t header configure first column1 -borderwidth 4 .t header cget first column1 -borderwidth } -result {4} test header-3.19 {header configure: invalid -button} -body { .t header configure first column1 -button "" } -returnCodes error -result {expected boolean value but got ""} test header-3.20 {header configure/cget: -button} -body { .t header configure first column1 -button off .t header cget first column1 -button } -result {0} ### test header-3.23 {header configure: invalid -image} -body { .t header configure first column1 -image questhead } -returnCodes error -result {image "questhead" doesn't exist} test header-3.24 {header configure/cget: -image} -body { .t header configure first column1 -image emptyImg .t header cget first column1 -image } -result {emptyImg} test header-3.25 {header configure: invalid -imagepadx} -body { .t header configure first column1 -imagepadx y } -returnCodes error -result {bad pad amount "y": must be a list of 1 or 2 positive screen distances} test header-3.25a {header configure: invalid 2 element -imagepadx} -body { .t header configure first column1 -imagepadx "y \{" } -returnCodes error -result {unmatched open brace in list} test header-3.26 {header configure/cget: -imagepadx} -body { .t header configure first column1 -imagepadx 9 -imagepady 4 list [.t header cget first column1 -imagepadx] \ [.t header cget first column1 -imagepady] } -result {9 4} test header-3.26a {header configure/cget: 2 element -imagepadx/y} -body { .t header configure first column1 -imagepadx {9 0} -imagepady {4 3} list [.t header cget first column1 -imagepadx] \ [.t header cget first column1 -imagepady] } -result {{9 0} {4 3}} ### test header-3.31 {header configure: invalid -justify} -body { .t header configure first column1 -justify no } -returnCodes error -result {bad justification "no": must be left, right, or center} test header-3.32 {header configure/cget: simple -justify} -body { .t header configure first column1 -justify center .t header cget first column1 -justify } -result {center} ### test header-3.35 {header configure: invalid -state} -body { .t header configure first column1 -state yes } -returnCodes error -result {bad state "yes": must be normal, active, or pressed} test header-3.36 {header configure/cget: -state} -body { .t header configure first column1 -state pressed .t header cget first column1 -state } -result {pressed} ### test header-3.41 {header configure: -text} -body { .t header configure first column1 -text "Text above Column 1" .t header cget first column1 -text } -result {Text above Column 1} test header-3.42 {header configure: invalid -textpadx} -body { .t header configure first column1 -textpadx baz } -returnCodes error -result {bad pad amount "baz": must be a list of 1 or 2 positive screen distances} test header-3.42a {header configure: invalid 2 element -textpadx} -body { .t header configure first column1 -textpadx {foo bar baz} } -returnCodes error -result {bad pad amount "foo bar baz": must be a list of 1 or 2 positive screen distances} test header-3.43 {header configure/cget: -textpadx/y} -body { .t header configure first column1 -textpadx 8 -textpady 5 list [.t header cget first column1 -textpadx] \ [.t header cget first column1 -textpady] } -result {8 5} test header-3.43a {header configure/cget: 2 element -textpadx/y} -body { .t header configure first column1 -textpadx {8 4} -textpady {4 5} list [.t header cget first column1 -textpadx] \ [.t header cget first column1 -textpady] } -result {{8 4} {4 5}} ### test header-3.46 {header configure: invalid -visible} -body { .t header configure first -visible never } -returnCodes error -result {expected boolean value but got "never"} test header-3.47 {header configure/cget: -visible} -body { .t header configure first -visible no .t header cget first -visible } -result {0} ### test header-4.1 {header configure: -tags} -body { .t header configure first -tags header0 .t header cget header1 -tags } -returnCodes error -result {header "header1" doesn't exist} test header-4.2 {header configure: -tags} -body { .t header cget header0 -tags } -result {header0} ### test header-5.1 {header delete: missing args} -body { .t header delete } -returnCodes error -result {wrong # args: should be ".t header delete header"} test header-5.2 {header delete: too many args} -body { .t header delete a b } -returnCodes error -result {wrong # args: should be ".t header delete header"} test header-5.3 {header delete: first header} -setup { .t header create -tags header1 } -body { .t header delete header1 } -result {} test header-5.4 {deleted header doesn't exist} -body { .t header cget header1 -tags } -returnCodes error -result {header "header1" doesn't exist} test header-5.5 {header delete: 'all' ignores header 0} -setup { .t header create .t header create .t header create } -body { .t header delete all .t header id all } -result {0} test header-5.6 {header delete: delete one} -body { .t header create -tags header1 .t header create -tags header2 .t header create -tags header3 .t header create -tags header4 .t header delete header1 .t header id all } -result {0 2 3 4} test header-5.7 {header delete: delete two} -body { .t header delete header4 .t header delete header3 .t header id all } -result {0 2} test header-5.8 {header delete: deleting all headers resets the next unique id} -body { .t header delete all .t header create } -result {1} test header-6.1 {header id: missing args} -setup { .t header delete all .t header configure header0 -visible no .t header create -tags header1 .t header create -tags header2 } -body { .t header id } -returnCodes error -result {wrong # args: should be ".t header id header"} test header-6.2 {header id: too many args} -body { .t header id a b } -returnCodes error -result {wrong # args: should be ".t header id header"} test header-6.3 {header id: by ID} -setup { .t header delete header1 } -body { .t header id 2 } -result {2} test header-6.4 {header id: by tag} -body { .t header id header2 } -result {2} test header-6.5 {header id: by keyword first} -body { .t header id first } -result {0} test header-6.6 {header id: by keyword last} -body { .t header id last } -result {2} test header-6.7 {header id: by keyword end} -body { .t header id end } -result {2} test header-6.8 {header id: by tag expression} -body { .t header id header2||header0 } -result {0 2} test header-6.9 {header id: qualifier 'tag'} -body { .t header id {tag header2} } -result {2} test header-6.10 {header id: qualifier 'tag'} -body { .t header id {all tag header2} } -result {2} test header-6.11 {header id: qualifier 'tag'} -body { .t header id {first tag header2} } -result {2} test header-6.12 {header id: qualifier 'visible'} -body { .t header id visible } -result {2} test header-6.13 {header id: qualifier 'visible'} -body { .t header id {last visible} } -result {2} test header-6.14 {header id: qualifier '!visible'} -body { .t header id !visible } -result {0} test header-6.15 {header id: qualifier '!visible'} -body { .t header id {all !visible} } -result {0} ### test header-11.1 {header count: too many args} -body { .t header count a b } -returnCodes error -result {wrong # args: should be ".t header count ?headerDesc?"} test header-11.2 {header count: no args} -setup { .t header delete all } -body { .t header count } -result {1} test header-11.3 {header count: with desc} -body { .t header count first } -result {1} test header-11.4 {header count: all} -body { .t header count all } -result {1} test header-11.5 {header count: unknown tag} -body { .t header count foo } -result {0} test header-11.6 {header count: 2 new headers} -setup { .t header create -tags header1 .t header create -tags header2 } -body { .t header count } -result {3} test header-11.7 {header count: delete a header} -setup { .t header delete header1 } -body { .t header count } -result {2} test header-11.8 {header count: delete another header} -setup { .t header delete header2 } -body { .t header count } -result {1} test header-12.1 {header dragconfigure: no args} -setup { .t header delete all .t header create -tags header1 } -body { .t header dragconfigure } -result {{-enable {} {} 0 0} *} -match glob test header-12.2 {header dragconfigure: unknown option} -body { .t header dragconfigure -foo } -returnCodes error -result {unknown option "-foo"} test header-12.3 {header dragconfigure: bad option-value} -body { .t header dragconfigure -enable foo } -returnCodes error -result {expected boolean value but got "foo"} test header-12.4 {header dragconfigure: missing option-value} -body { .t header dragconfigure -enable yes -imagespan } -returnCodes error -result {value for "-imagespan" missing} test header-12.5 {header dragconfigure: tail column forbidden} -body { .t header dragconfigure -imagecolumn tail } -returnCodes error -result {can't specify "tail" for this command} test header-12.6 {header dragconfigure: negative spans not an error} -body { .t header dragconfigure -imagespan -10 } -result {} test header-12.20 {header dragconfigure: unknown header} -body { .t header dragconfigure foo } -returnCodes error -result {header "foo" doesn't exist} test header-12.21 {header dragconfigure: valid header} -body { .t header dragconfigure first } -result {{-draw {} {} 1 1} *} -match glob test header-12.22 {header dragconfigure: multiple headers not allowed} -body { .t header dragconfigure all } -returnCodes error -result {can't specify > 1 header for this command} test header-12.23 {header dragconfigure: multiple headers not allowed} -body { .t header dragconfigure all -foo } -returnCodes error -result {can't specify > 1 header for this command} test header-12.24 {header dragconfigure: multiple headers unknown option} -body { .t header dragconfigure all -foo bar } -returnCodes error -result {unknown option "-foo"} test header-12.25 {header dragconfigure: multiple headers ok} -body { .t header dragconfigure all -draw no } -result {} test header-12.26 {header dragconfigure: single header ok} -body { .t header dragconfigure first -draw yes } -result {} test header-12.30 {header dragconfigure: deleting a column clears -imagecolumn} -setup { # .t header configure 0 -visible yes .t column delete all .t column create -tags column0 -text "Column 0" .t column create -tags column1 -text "Column 1" .t column create -tags column2 -text "Column 2" .t header dragconfigure -imagecolumn column0 update .t column delete column0 } -body { .t header dragcget -imagecolumn } -result {} test header-12.31 {header dragconfigure: deleting a column clears -indicatorcolumn} -setup { .t header dragconfigure -indicatorcolumn column1 update .t column delete column1 } -body { .t header dragcget -indicatorcolumn } -result {} test header-13.1 {header dragcget: too few args} -body { .t header dragcget } -returnCodes error -result {wrong # args: should be ".t header dragcget ?header? option"} test header-13.2 {header dragcget: too many args} -body { .t header dragcget a b c } -returnCodes error -result {wrong # args: should be ".t header dragcget ?header? option"} test header-13.3 {header dragcget: unknown option} -body { .t header dragcget -foo } -returnCodes error -result {unknown option "-foo"} test header-13.4 {header dragcget: valid option} -body { .t header dragcget -enable } -result {0} test header-13.5 {header dragcget: unknown header} -body { .t header dragcget foo -bar } -returnCodes error -result {header "foo" doesn't exist} test header-13.6 {header dragcget: multiple headers not allowed} -body { .t header dragcget all -foo } -returnCodes error -result {can't specify > 1 header for this command} test header-13.7 {header dragcget: single header, valid option} -body { .t header dragcget first -enable } -result {1} test header-20.1 {unknown column config options are passed to the first header} -setup { .t header delete all .t column delete all } -body { .t column create -text "Column 0" -tags column0 .t header cget first column0 -text } -result {Column 0} test header-20.2 {unknown column config options are retrieved from the first header} -body { .t header configure first column0 -text "Header 0, Column 0" .t column cget column0 -text } -result {Header 0, Column 0} test header-20.3 {unknown header config options are passed to the underlying item} -body { .t header configure first -visible no } -result {} test header-20.4 {unknown header config options are retrieved from the underlying item} -body { .t header cget first -visible } -result {0} test header-21.1 {column create doesn't mess up header-columns} -setup { .t header delete all .t column delete all .t style create stail -statedomain header .t header style set first all stail } -body { .t header style set first } -result {stail} test header-21.2 {column create doesn't mess up header-columns} -setup { .t column create -tags column0 .t style create s0 -statedomain header .t header style set first column0 s0 } -body { .t header style set first } -result {s0 stail} test header-21.3 {column create doesn't mess up header-columns} -setup { .t column create -tags columnL -lock left .t style create sL -statedomain header .t header style set first columnL sL } -body { .t header style set first } -result {sL s0 stail} test header-21.4 {column create doesn't mess up header-columns} -setup { .t column create -tags columnR -lock right .t style create sR -statedomain header .t header style set first columnR sR } -body { .t header style set first } -result {sL s0 sR stail} test header-21.5 {aborted column create doesn't mess up header-columns} -setup { catch {.t column create -foo bar} } -body { .t header style set first } -result {sL s0 sR stail} test header-22.1 {changing column -width invalidates needed height of headers} -body { .t header delete all .t column delete all .t header conf 0 -visible 1 .t column create -tags column0 -text "Here is a long line of text that will wrap" -textlines 0 scan [.t header bbox 0 column0] "%d %d %d %d" left top right bottom .t column configure column0 -width [expr {($right - $left) / 2}] scan [.t header bbox 0 column0] "%d %d %d %d" left1 top1 right1 bottom1 set fh [font metrics [.t cget -font] -linespace] expr {$bottom1 >= $bottom + $fh} } -result {1} test header-22.2 {squeezing columns invalidates needed height of headers} -body { .t column configure column0 -width "" -squeeze yes set nw [.t column neededwidth column0] .t configure -width [expr {$nw * 1.5}] update idletasks ; # scan [.t header bbox 0 column0] "%d %d %d %d" left top right bottom .t configure -width [expr {$nw * 0.5}] update idletasks ; # scan [.t header bbox 0 column0] "%d %d %d %d" left1 top1 right1 bottom1 set fh [font metrics [.t cget -font] -linespace] expr {$bottom1 >= $bottom + $fh} } -result {1} test header-22.3 {-canvaspadx is added to width of leftmost unlocked column when calculating needed height} -body { .t column configure column0 -width "" -squeeze no scan [.t header bbox 0 column0] "%d %d %d %d" left top right bottom .t column configure column0 -width [.t column neededwidth column0] .t configure -canvaspadx 50 scan [.t header bbox 0 column0] "%d %d %d %d" left1 top1 right1 bottom1 expr {$bottom1 == $bottom} } -cleanup { .t configure -canvaspadx 0 } -result {1} test header-23.1 {layout: no bitmap/image/text/arrow, as tall as borders} -setup { .t header delete all .t column delete all .t column create -tags C0 -width 100 .t header configure 0 C0 -borderwidth 3 .t configure -showheader yes -usetheme no -highlightthickness 0 -borderwidth 0 } -body { .t header bbox 0 C0 } -result {0 0 100 6} test header-23.2 {layout: no bitmap/image/text, add a sort arrow} -setup { .t header configure 0 C0 -arrow up } -body { # Assuming non-themed arrow height==9 .t header bbox 0 C0 } -result {0 0 100 15} test header-23.3 {layout: no bitmap/image/text, width is -arrowpadx plus arrow width} -setup { .t column configure C0 -width "" } -body { # Assuming non-themed arrow width==9 and -arrowpadx==6, borders ignored .t header bbox 0 C0 } -result {0 0 21 15} test header-23.4 {layout: -arrowpady added to height} -setup { .t header configure 0 C0 -arrowpady 2 } -body { # height was 3 + 9 + 3, -arrowpady adds +4 .t header bbox 0 C0 } -result {0 0 21 19} test header-23.5 {layout: add an -image} -setup { image create photo headerImage -width 20 -height 20 .t header configure 0 C0 -image headerImage } -body { # width = 6 + img=20 + max(6,6) + arrow=9 + 6 # height = 3 + 20 + 3 .t header bbox 0 C0 } -result {0 0 47 26} test header-23.6 {layout: -imagepadx and -arrowpadx overlap} -setup { .t header configure 0 C0 -imagepadx {6 0} } -body { .t header bbox 0 C0 } -cleanup { .t header configure 0 C0 -imagepadx 6 } -result {0 0 47 26} test header-23.7 {layout: -canvaspadx adds to the width} -setup { .t configure -canvaspadx 10 } -body { .t header bbox 0 C0 } -cleanup { .t configure -canvaspadx 0 } -result {0 0 57 26} test header-23.8 {layout: -imagepady adds to height} -setup { .t header configure 0 C0 -imagepady 2 } -body { .t header bbox 0 C0 } -result {0 0 47 30} test header-23.9 {layout: arrow on the left doesn't change anything} -setup { .t header configure 0 C0 -arrowside left } -body { .t header bbox 0 C0 } -result {0 0 47 30} test header-24.1 {custom style: } -setup { .t header delete all .t column delete all .t column create -tags C0 -width "" .t header configure 0 C0 .t configure -showheader yes -usetheme no -highlightthickness 0 -borderwidth 0 .t element create custom.header header -statedomain header -borderwidth 3 .t element create custom.image image -statedomain header -image headerImage .t style create custom -statedomain header -orient horizontal .t style elements custom {custom.header custom.image} .t style layout custom custom.header -union custom.image .t style layout custom custom.image -padx 6 .t header style set 0 C0 custom } -body { .t header bbox 0 C0 } -result {0 0 32 26} test header-24.2 {custom style: header element sees -arrow option} -setup { # Not configuring header element's -arrow here, it checks the header state flags .t header configure 0 C0 -arrow down } -body { # 6 + img=20 + max(6,6) + arrow=9 + 6 list [.t header bbox 0 C0] [.t header bbox 0 C0 custom.image] } -result {{0 0 47 26} {6 3 26 23}} test header-24.3 {custom style: arrow on the left} -setup { .t element configure custom.header -arrowside left } -body { # 6 + arrow=9 + max(6,6) + img=20 + 6 list [.t header bbox 0 C0] [.t header bbox 0 C0 custom.image] } -result {{0 0 47 26} {21 3 41 23}} test header-24.4 {custom style: unequal padding} -setup { .t element configure custom.header -arrowpadx {6 12} } -body { # 6 + arrow=9 + max(12,6) + img=20 + 6 list [.t header bbox 0 C0] [.t header bbox 0 C0 custom.image] } -result {{0 0 53 26} {27 3 47 23}} test header-24.5 {custom style: unequal padding} -setup { .t element configure custom.header -arrowpadx {6 0} } -body { # 6 + arrow=9 + max(0,6) + img=20 + 6 list [.t header bbox 0 C0] [.t header bbox 0 C0 custom.image] } -result {{0 0 47 26} {21 3 41 23}} test header-24.6 {custom style: external padding of header doesn't change its width} -setup { .t style layout custom custom.header -padx 10 } -body { # 10 + 6 + arrow=9 + max(0,6) + img=20 + 6 + 10 list [.t header bbox 0 C0] [.t header bbox 0 C0 custom.image] } -result {{0 0 67 26} {31 3 51 23}} test header-30.1 {library: CursorAction} -setup { destroy .t treectrl .t -usetheme no -borderwidth 0 -highlightthickness 0 pack .t .t header configure 0 -tags header0 .t header create -tags header1 .t header configure all -height 20 foreach tag {left1 left2} { .t column create -tags $tag -lock left } foreach tag {none1 none2 none3 none4} { .t column create -tags $tag -lock none } foreach tag {right1 right2} { .t column create -tags $tag -lock right } .t column configure all -width 50 .t header span header0 left1 2 none1 2 none3 2 right1 2 # 50-pixel gap between last non-locked column and first right-locked column .t configure -width [expr {[.t column count] * 50 + 50}] update } -body { array unset v TreeCtrl::CursorAction .t 0 0 v parray v } -output {v(action) = header-button v(column) = 0 v(header) = 0 } test header-30.2 {library: CursorAction} -body { array unset v TreeCtrl::CursorAction .t 49 0 v parray v } -output {v(action) = header-button v(column) = 0 v(header) = 0 } test header-30.3 {library: CursorAction} -body { array unset v TreeCtrl::CursorAction .t 99 0 v parray v } -output {v(action) = header-resize v(column) = 1 v(header) = 0 } test header-30.4 {library: CursorAction} -body { array unset v TreeCtrl::CursorAction .t 100 0 v parray v } -output {v(action) = header-resize v(column) = 1 v(header) = 0 } test header-30.5 {library: CursorAction} -body { array unset v TreeCtrl::CursorAction .t 4 0 v parray v } -output {v(action) = header-button v(column) = 0 v(header) = 0 } test header-30.6 {library: CursorAction} -body { array unset v TreeCtrl::CursorAction .t 104 0 v parray v } -output {v(action) = header-button v(column) = 2 v(header) = 0 } test header-30.7 {library: CursorAction} -body { array unset v TreeCtrl::CursorAction .t 199 0 v parray v } -output {v(action) = header-resize v(column) = 3 v(header) = 0 } test header-30.8 {library: CursorAction} -body { array unset v TreeCtrl::CursorAction .t 203 0 v parray v } -output {v(action) = header-resize v(column) = 3 v(header) = 0 } test header-30.9 {library: CursorAction} -body { array unset v TreeCtrl::CursorAction .t 204 0 v parray v } -output {v(action) = header-button v(column) = 4 v(header) = 0 } #---------------------------------------------------------------------- # # Procedures needed by this test file # #---------------------------------------------------------------------- proc HeaderXY {H C xpos ypos _x _y} { upvar $_x x $_y y scan [.t header bbox $H $C] "%d %d %d %d" x1 y1 x2 y2 if {[string match "left*" $xpos]} { set dx [string range $xpos 4 end] set x $x1 } elseif {[string match "right*" $xpos]} { set dx [string range $xpos 5 end] set x $x2 } else { set dx $xpos set x $x1 } if {[string match "top*" $xpos]} { set dy [string range $ypos 4 end] set y $y1 } elseif {[string match "bottom*" $ypos]} { set dy [string range $ypos 5 end] set y $y2 } else { set dy $ypos set y $y1 } incr x $dx incr y $dy return } proc Motion {H C xpos ypos} { HeaderXY $H $C $xpos $ypos x y event generate .t -x $x -y $y set ::gx $x set ::gy $y return } proc Press1 {} { event generate .t -x $::gx -y $::gy return } proc Release1 {} { event generate .t -x $::gx -y $::gy return } proc Drag1 {dx dy} { incr ::gx $dx incr ::gy $dy event generate .t -x $::gx -y $::gy return } test header-40.1 {bindings: enter + invoke 0,0} -setup { .t notify install .t notify install .t notify bind test {lappend v state %H %C %s} .t notify bind test {lappend v invoke %H %C} } -body { array unset v set v {} Motion header0 left1 0 0 lappend v | Press1 lappend v | Release1 lappend v | [.t cget -cursor] set v } -result {state 0 0 active | state 0 0 pressed | state 0 0 active invoke 0 0 | {}} test header-40.2 {bindings: hover left side of 1,0} -body { set v {} Motion header1 left1 0 0 lappend v | [.t cget -cursor] set v } -result {state 0 0 normal state 1 0 active | {}} test header-40.3 {bindings: hover 1 pixel left of right side of 1,0} -body { set v {} Motion header1 left1 right-5 0 lappend v | [.t cget -cursor] } -result {| {}} test header-40.4 {bindings: hover right side of 1,0} -body { set v {} Motion header1 left1 right-4 0 lappend v | [.t cget -cursor] } -result {| sb_h_double_arrow} test header-40.5 {bindings: hover left side of 1,1} -body { set v {} Motion header1 left2 3 0 lappend v | [.t cget -cursor] set v } -result {| sb_h_double_arrow} test header-40.6 {bindings: hover 1 pixel right of left side of 1,1} -body { set v {} Motion header1 left2 4 0 lappend v | [.t cget -cursor] set v } -result {state 1 0 normal state 1 1 active | {}} test header-40.7 {bindings: hover right side of 1,1} -body { set v {} Motion header1 left2 right-1 0 lappend v | [.t cget -cursor] set v } -result {| sb_h_double_arrow} test header-40.8 {bindings: hover left side of 1,2} -body { set v {} Motion header1 none1 0 0 lappend v | [.t cget -cursor] set v } -result {| sb_h_double_arrow} test header-40.9 {bindings: hover right side of 1,5} -body { set v {} Motion header1 none4 right-1 0 lappend v | [.t cget -cursor] set v } -result {state 1 1 normal state 1 5 active | sb_h_double_arrow} test header-40.10 {bindings: hover left side of 1,tail} -body { set v {} Motion header1 none4 right+0 0 lappend v | [.t cget -cursor] set v } -result {| sb_h_double_arrow} test header-40.11 {bindings: hover 1 pixel right of left side of 1,tail} -body { set v {} Motion header1 none4 right+4 0 lappend v | [.t cget -cursor] set v } -result {state 1 5 normal | {}} test header-40.12 {bindings: hover 5 pixels left of left side of 1,6} -body { set v {} Motion header1 right1 -5 0 lappend v | [.t cget -cursor] set v } -result {| {}} test header-40.13 {bindings: hover 4 pixels left of left side of 1,6} -body { set v {} Motion header1 right1 -4 0 lappend v | [.t cget -cursor] set v } -result {state 1 6 active | sb_h_double_arrow} test header-40.14 {bindings: hover left side of 1,6} -body { set v {} Motion header1 right1 0 0 lappend v | [.t cget -cursor] set v } -result {| sb_h_double_arrow} test header-40.15 {bindings: hover left side of 1,6} -body { set v {} Motion header1 right1 3 0 lappend v | [.t cget -cursor] set v } -result {| sb_h_double_arrow} test header-40.16 {bindings: hover 1 pixel right of left side of 1,6} -body { set v {} Motion header1 right1 4 0 lappend v | [.t cget -cursor] set v } -result {| {}} test header-40.17 {bindings: hover right side of 1,6} -body { set v {} Motion header1 right1 right-1 0 lappend v | [.t cget -cursor] set v } -result {state 1 6 normal state 1 7 active | sb_h_double_arrow} test header-40.18 {bindings: hover left side of 1,7} -body { set v {} Motion header1 right2 0 0 lappend v | [.t cget -cursor] set v } -result {| sb_h_double_arrow} test header-40.19 {bindings: hover right side of 1,7} -body { set v {} Motion header1 right2 right-1 0 lappend v | [.t cget -cursor] set v } -result {| {}} test header-41.1 {bindings: resize -lock=left span=2} -body { Motion header0 left1 right-1 0 Press1 Drag1 -25 0 Release1 .t column cget left2 -width } -result {25} test header-41.2 {bindings: resize -lock=none span=2} -body { Motion header0 none1 right-1 0 Press1 Drag1 -25 0 Release1 .t column cget none2 -width } -result {25} test header-41.3 {bindings: resize -lock=none span=2} -body { Motion header0 none3 right-1 0 Press1 Drag1 -25 0 Release1 .t column cget none4 -width } -result {25} test header-41.4 {bindings: resize -lock=right span=2} -body { Motion header0 right1 0 0 Press1 Drag1 +25 0 Release1 .t column cget right1 -width } -result {25} test header-41.5 {bindings: resize span with hidden column} -setup { .t column configure all -width 50 .t column configure none2 -visible no } -body { Motion header0 none1 right-1 0 Press1 Drag1 +25 0 Release1 .t column cget none1 -width ; # not none2 } -result {75} test header-41.6 {bindings: resize too-large span} -setup { .t column configure all -width 50 .t column configure none2 -visible yes .t header span header0 none3 20 } -body { Motion header0 none3 right-1 0 Press1 Drag1 +25 0 Release1 .t column cget none4 -width } -result {75} test header-99.1 {some needed cleanup} -body { destroy .t } -result {} # cleanup image delete emptyImg image delete headerImage ::tcltest::cleanupTests return tktreectrl-2.4.1/tests/item.test0000644000076400010400000013616211565025646017237 0ustar TimAdministrators# Commands covered: treectrl's widget command item # # This file contains a collection of tests for the item widget command of # the tktreectrl extension. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2000 by Scriptics Corporation. # Copyright (c) 2002 by Christian Krone. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } package require Tk package require treectrl test item-0.1 {some needed preparations} -body { pack [treectrl .t] } -result {} test item-1.1 {item: missing command} -body { .t item } -returnCodes error -result {wrong # args: should be ".t item command ?arg arg ...?"} test item-2.2 {item: invalid command} -body { .t item foo } -returnCodes error -result {bad command "foo": must be *} -match glob # Before continuing to test the item descriptions and their modifiers, # lets create some items with this hierarchy: # 0 # + 1 # | + 2 # | + 3 # | + 4 # + 5 # | + 6 # | + 7 # + 8 test item-2.4 {create some items} -body { set n1 [.t item create]; .t item lastchild 0 $n1 set n2 [.t item create]; .t item lastchild $n1 $n2 set n3 [.t item create]; .t item lastchild $n1 $n3 set n4 [.t item create]; .t item lastchild $n3 $n4 set n5 [.t item create]; .t item lastchild 0 $n5 set n6 [.t item create]; .t item lastchild $n5 $n6 set n7 [.t item create]; .t item lastchild $n5 $n7 set n8 [.t item create]; .t item lastchild 0 $n8 } -result {8} test item-2.5 {some more preparations} -body { .t state define state0 .t element create eBorder border .t element create eImage image .t element create eRect rect .t element create eText text -fill red .t style create testStyle .t style elements testStyle {eText eBorder} } -result {} test item-2.6 {item create} -body { list [.t item create] [.t item create] [.t item create] } -result {9 10 11} test item-3.1 {item delete: missing itemDesc} -body { .t item delete } -returnCodes error -result {wrong # args: should be ".t item delete first ?last?"} test item-3.2 {item delete: unknown item} -body { .t item delete 999 } -returnCodes error -result {item "999" doesn't exist} test item-3.3 {item delete: one item} -body { .t item delete 9 } -result {} test item-3.4 {item delete: item range without common ancestor} -body { .t item delete 10 11 } -returnCodes error -result {item 10 and item 11 don't share a common ancestor} test item-3.5 {item delete: item range with common ancestor} -body { .t item lastchild 8 10 .t item lastchild 8 11 .t item delete 10 11 } -result {} test item-3.6 {item delete: don't delete "root" itemDesc} -body { .t item delete root .t item id root } -result {0} test item-3.7 {item delete: deleting root should be ignored} -body { .t item delete [.t item id root] update idletasks } -result {} test item-4.1 {item ancestors: no ancestor yet} -body { .t item create .t item ancestors 12 } -result {} test item-4.2 {item ancestors} -body { .t item lastchild 7 12 .t item ancestors 12 } -result {7 5 0} test item-5.1 {item children: no children} -body { .t item children 12 } -result {} test item-5.2 {item children} -body { .t item children 0 } -result {1 5 8} test item-6.1 {item firstchild: missing itemDesc} -body { .t item firstchild } -returnCodes error -result {wrong # args: should be ".t item firstchild item ?newFirstChild?"} test item-6.2 {item firstchild: no children} -body { .t item firstchild 12 } -result {} test item-6.3 {item firstchild} -body { .t item firstchild 1 } -result {2} test item-7.1 {item lastchild: no children} -body { .t item lastchild 1 } -result {3} test item-8.1 {item nextsibling: no sibling} -body { .t item nextsibling 12 } -result {} test item-8.2 {item nextsibling: no sibling} -body { .t item nextsibling 2 } -result {3} test item-9.1 {item numchildren: no children} -body { .t item numchildren 12 } -result {0} test item-9.2 {item numchildren} -body { .t item numchildren 1 } -result {2} test item-10.1 {item parent: no parent} -body { .t item parent root } -result {} test item-10.2 {item parent} -body { .t item parent "root firstchild" } -result {0} test item-11.1 {item prevsibling: missing arg} -body { .t item prevsibling } -returnCodes error -result {wrong # args: should be ".t item prevsibling item ?newPrevSibling?"} test item-11.2 {item prevsibling: no prevsibling} -body { .t item prevsibling 1 } -result {} test item-11.3 {item prevsibling} -body { .t item prevsibling 3 } -result {2} test item-12.1 {item remove: invalid item} -body { .t item remove 999 } -returnCodes error -result {item "999" doesn't exist} test item-12.2 {item remove} -body { .t item remove 12 } -result {} test item-13.1 {item complex: missing args} -constraints { deprecated } -body { .t item complex 8 } -returnCodes error -result {wrong # args: should be ".t item complex item list ..."} test item-13.2 {item complex: only allowed if column style is defined} -constraints { deprecated } -body { .t item complex 8 {{e1 -text Hallo}} } -returnCodes error -result {column #0 doesn't exist} test item-13.3 {item complex: invalid list} -constraints { deprecated } -body { .t column create -tag column0 .t item style set 8 0 testStyle .t item complex 8 {{e1 -text}} } -returnCodes error -result {wrong # args: should be "element option value ..."} test item-13.4 {item complex: element name not defined in style} -constraints { deprecated } -body { .t item complex 8 {{e1 -text Hallo}} } -returnCodes error -result {element "e1" doesn't exist} test item-13.5 {item complex: option not known in element} -constraints { deprecated } -body { .t item complex 8 {{eText -bitmap questhead}} } -returnCodes error -result {unknown option "-bitmap"} test item-13.6 {item complex: invalid option value in element} -constraints { deprecated } -body { .t item complex 8 {{eText -fill foo}} } -cleanup { .t column delete column0 } -returnCodes error -result {unknown color name "foo"} test item-14.1 {item element: missing command} -setup { # in case the deprecated complex command is not run... .t column create -tag column0 .t item style set 8 0 testStyle .t item text 8 0 "" } -body { .t item element } -returnCodes error -result {wrong # args: should be ".t item element command item column element ?arg ...?"} test item-14.2 {item element: invalid command} -body { .t item element foo 8 column0 eText } -returnCodes error -result {bad command "foo": must be *} -match glob test item-14.3 {item element perstate: missing arg} -body { .t item element perstate 8 column0 eText } -returnCodes error -result {wrong # args: should be ".t item element perstate item column element option ?stateList?"} test item-14.4 {item element perstate: without stateList} -body { .t element configure eText -fill {red !selected blue {}} .t item element perstate 8 column0 eText -fill } -result {red} test item-14.5 {item element perstate: without stateList} -body { .t item element perstate 8 column0 eText -fill } -result {red} test item-14.6 {item element perstate: with stateList} -body { .t item element perstate 8 column0 eText -fill {selected} } -result {blue} test item-14.7 {item element perstate: all items} -body { .t item element perstate all column0 eText -fill {selected} } -returnCodes error -result {can't specify > 1 item for this command} test item-14.8 {item element perstate: several items} -body { .t item element perstate {list {8 root}} column0 eText -fill {selected} } -returnCodes error -result {can't specify > 1 item for this command} test item-14.21 {item element cget: missing arg} -body { .t item element cget 8 column0 eText } -returnCodes error -result {wrong # args: should be ".t item element cget item column element option"} test item-14.22 {item element cget: too many args} -body { .t item element cget 8 a b c d } -returnCodes error -result {wrong # args: should be ".t item element cget item column element option"} test item-14.23 {item element cget: single item, get -fill} -body { .t item element cget 8 column0 eText -fill } -result {} test item-14.24 {item element cget: all items, get -fill} -body { .t item element cget all column0 eText -fill } -returnCodes error -result {can't specify > 1 item for this command} test item-14.25 {item element cget: multiple items, get -fill} -body { .t item element cget {list {8 1 3}} column0 eText -fill } -returnCodes error -result {can't specify > 1 item for this command} test item-14.31 {item element configure: get all config info} -body { .t item element configure 8 column0 eText } -result {{-data {} {} {} {}} {-datatype {} {} {} {}} *} -match glob test item-14.32 {item element configure: single item, set -fill} -body { .t item element configure 8 column0 eText -fill yellow .t item element cget 8 0 eText -fill } -result {yellow} test item-14.33 {item element configure: single item, get -fill} -body { .t item element configure 8 column0 eText -fill } -result {-fill {} {} {} yellow} test item-14.34 {item element configure: all items, get -fill} -body { .t item element configure all column0 eText -fill } -returnCodes error -result {can't specify > 1 item for this command} test item-14.35 {item element configure: several items, get -fill} -body { .t item element configure {list {8 3}} column0 eText -fill } -returnCodes error -result {can't specify > 1 item for this command} test item-14.36 {item element configure: all items, set -fill} -body { .t item style set all column0 testStyle .t item element configure all column0 eText -fill orange set res {} foreach I [.t item id {range first last}] { lappend res [.t item element cget $I column0 eText -fill] } set res } -result {orange orange orange orange orange orange orange orange orange} test item-14.37 {item element configure: single item, multiple elements} -body { .t item element configure root column0 eText -fill blue + } -returnCodes error -result {missing element name after "+"} test item-14.38 {item element configure: single item, multiple elements} -body { .t item element configure root column0 eText -fill blue + eBorder } -returnCodes error -result {missing option-value pair after element "eBorder"} test item-14.39 {item element configure: single item, multiple elements} -body { .t item element configure root column0 eText -fill blue + eBorder -draw } -returnCodes error -result {missing option-value pair after element "eBorder"} test item-14.40 {item element configure: single item, multiple elements} -body { .t item element configure root column0 eText -fill blue + eBorder -draw false list [.t item element cget root column0 eText -fill] \ [.t item element cget root column0 eBorder -draw] } -result {blue false} test item-14.41 {item element configure: single item, multiple columns} -body { .t item element configure root column0 eText -fill blue , } -returnCodes error -result {missing column after ","} test item-14.42 {item element configure: single item, multiple columns} -body { .t column create -tag column1 .t item style set all column1 testStyle .t item element configure root column0 eText -fill blue , column1 } -returnCodes error -result {missing element name after column "column1"} test item-14.43 {item element configure: single item, multiple columns} -body { .t item element configure root column0 eText -fill blue , column1 eBorder } -returnCodes error -result {missing option-value pair after element "eBorder"} test item-14.44 {item element configure: single item, multiple columns} -body { .t item element configure root column0 eText -fill blue , column1 eBorder -draw } -returnCodes error -result {missing option-value pair after element "eBorder"} test item-14.45 {item element configure: single item, multiple columns} -body { .t item element configure root column0 eText -fill green , column1 eBorder -draw true list [.t item element cget root column0 eText -fill] \ [.t item element cget root column1 eBorder -draw] } -result {green true} test item-14.46 {item element configure: multiple items, multiple columns/elements} -body { .t item element configure {list {1 3}} column0 eText -fill green -text boo + \ eBorder -background red , column1 eBorder -draw true + eText -font {{times 12}} set res {} foreach I {1 3} { lappend res [.t item element cget $I column0 eText -fill] lappend res [.t item element cget $I column0 eText -text] lappend res [.t item element cget $I column0 eBorder -background] lappend res [.t item element cget $I column1 eBorder -draw] lappend res [.t item element cget $I column1 eText -font] } set res } -result {green boo red true {{times 12}} green boo red true {{times 12}}} test item-14.50 {item element configure: cleanup} -body { .t item style set all 0 "" .t column delete all .t column create .t item style set 8 0 testStyle .t item element configure 8 0 eText -fill yellow } -result {} test item-14.60 {item element cget: tail not allowed} -body { .t item element cget root tail eText -fill } -returnCodes error -result {can't specify "tail" for this command} test item-14.61 {item element configure: tail not allowed} -body { .t item element configure root tail eText -fill } -returnCodes error -result {can't specify "tail" for this command} test item-14.62 {item element perstate: tail not allowed} -body { .t item element perstate root tail eText -fill } -returnCodes error -result {can't specify "tail" for this command} test item-15.1 {item style: missing args} -body { .t item style } -returnCodes error -result {wrong # args: should be ".t item style command item ?arg ...?"} test item-15.2 {item style: invalid command} -body { .t item style foo bar } -returnCodes error -result {bad command "foo": must be *} -match glob test item-15.3 {item style: invalid command} -body { .t item style foo bar } -returnCodes error -result {bad command "foo": must be *} -match glob test item-15.4 {item style elements: missing args} -body { .t item style elements 8 } -returnCodes error -result {wrong # args: should be ".t item style elements item column"} test item-15.5 {item style elements: invalid item} -body { .t item style elements 999 } -returnCodes error -result {item "999" doesn't exist} test item-15.6 {item style elements: item without style} -body { .t item style elements 1 0 } -returnCodes error -result {item 1 column 0 has no style} test item-15.7 {item style elements} -body { .t item style elements 8 0 } -result {eText} test item-15.8 {item style map: missing args} -body { .t item style map 8 } -returnCodes error -result {wrong # args: should be ".t item style map item column style map"} test item-15.9 {item style map: invalid item} -body { .t item style map 999 } -returnCodes error -result {item "999" doesn't exist} test item-15.10 {item style map: item with unknown style} -body { .t item style map 1 0 noStyle {foo bar} } -returnCodes error -result {style "noStyle" doesn't exist} test item-15.11 {item style map: odd elemented list} -body { .t item style map 8 0 testStyle foo .t item style elements 8 0 } -returnCodes error -result {list must contain even number of elements} test item-15.12 {item style map: unknown element} -body { .t style create testStyle2 .t item style map 8 0 testStyle2 {eText foo} .t item style elements 8 0 } -returnCodes error -result {element "foo" doesn't exist} test item-15.13 {item style map: element not in to-style} -body { .t item style map 8 0 testStyle2 {eText eRect} } -returnCodes error -result {style testStyle2 does not use element eRect} test item-15.14 {item style map: element not in from-style} -body { # .t style elements testStyle2 {eImage eRect} .t item style map 8 0 testStyle2 {eRect eBorder} } -returnCodes error -result {style testStyle does not use element eRect} test item-15.15 {item style map: different element types} -body { .t style elements testStyle2 {eImage eRect} .t item style map 8 0 testStyle2 {eBorder eRect} } -returnCodes error -result {can't map element type border to rect} test item-15.16 {item style set: invalid item} -body { .t item style set foo bar } -returnCodes error -result {item "foo" doesn't exist} test item-15.17 {item style set: without args returns all styles} -body { .t item style set 2 } -result {{}} test item-15.18 {item style set: without args returns style} -body { .t item style set 2 0 } -result {} test item-15.19 {item style set: without args returns style} -body { .t item style set 8 0 } -result {testStyle} test item-15.20 {item style set: single item, single column} -body { .t item style set 8 0 testStyle2 .t item style set 8 } -result {testStyle2} test item-15.21 {item style set: all items, single column} -body { .t item style set all 0 testStyle2 set res {} foreach I [.t item id {range 1 8}] { lappend res [.t item style set $I] } set res } -result {testStyle2 testStyle2 testStyle2 testStyle2 testStyle2 testStyle2 testStyle2 testStyle2} test item-15.22 {item style set: list of items, single column} -body { .t item style set {list {2 4 6 8}} 0 "" set res {} foreach I [.t item id {range 1 8}] { lappend res [.t item style set $I] } set res } -result {testStyle2 {{}} testStyle2 {{}} testStyle2 {{}} testStyle2 {{}}} test item-15.23 {item style set: all items, multiple columns} -body { .t column create .t item style set all 0 testStyle 1 testStyle2 set res {} foreach I [.t item id {range 1 8}] { lappend res [.t item style set $I] } set res } -result {{testStyle testStyle2} {testStyle testStyle2} {testStyle testStyle2} {testStyle testStyle2} {testStyle testStyle2} {testStyle testStyle2} {testStyle testStyle2} {testStyle testStyle2}} test item-15.24 {item style set: list of items, multiple columns} -body { .t item style set {list {2 4 6 8}} 0 testStyle2 1 "" set res {} foreach I [.t item id {range 1 8}] { lappend res [.t item style set $I] } set res } -result {{testStyle testStyle2} {testStyle2 {}} {testStyle testStyle2} {testStyle2 {}} {testStyle testStyle2} {testStyle2 {}} {testStyle testStyle2} {testStyle2 {}}} test item-15.25 {item style set: all items, multiple columns} -body { .t item style set all 1 "" 0 "" set res {} foreach I [.t item id {range 1 8}] { lappend res [.t item style set $I] } .t column delete all .t column create set res } -result {{{} {}} {{} {}} {{} {}} {{} {}} {{} {}} {{} {}} {{} {}} {{} {}}} test item-15.30 {item style elements: tail not allowed} -body { .t item style elements root tail } -returnCodes error -result {can't specify "tail" for this command} test item-15.31 {item style map: tail not allowed} -body { .t item style map root tail testStyle2 {} } -returnCodes error -result {can't specify "tail" for this command} test item-15.32 {item style set: tail not allowed} -body { .t item style set root tail } -returnCodes error -result {can't specify "tail" for this command} test item-15.33 {item style set: tail not allowed} -body { .t item style set root tail testStyle2 } -returnCodes error -result {can't specify "tail" for this command} test item-16.1 {item state: missing args} -body { .t item state } -returnCodes error -result {wrong # args: should be ".t item state command item ?arg ...?"} test item-16.2 {item state: unknown command} -body { .t item state foo bar } -returnCodes error -result {bad command "foo": must be *} -match glob test item-16.3 {item state get: unknown item} -body { .t item state get 999 } -returnCodes error -result {item "999" doesn't exist} test item-16.4 {item state get: too much arg} -body { .t item state get 8 open enabled } -returnCodes error -result {wrong # args: should be ".t item state get item ?state?"} test item-16.5 {item state get: invalid arg} -body { .t item state get 8 !open } -returnCodes error -result {can't specify '!' for this command} test item-16.6 {item state get: invalid arg} -body { .t item state get 8 ~open } -returnCodes error -result {can't specify '~' for this command} test item-16.6 {item state get: unknown state} -body { .t item state get 8 foo } -returnCodes error -result {unknown state "foo"} test item-16.7 {item state: list all set states} -body { .t item state get 8 } -result {open enabled} test item-16.8 {item state get: state not set} -body { .t item state get 8 active } -result {0} test item-16.9 {item state get: state set} -body { .t item state get 8 open } -result {1} test item-16.10 {item state get: user defined state not set} -body { .t item state get 8 state0 } -result {0} test item-16.11 {item state set: missing arg} -body { .t item state set 8 } -returnCodes error -result {wrong # args: should be ".t item state set item ?last? stateList"} test item-16.12 {item state: try to reset predefined state} -body { .t item state set 8 open } -returnCodes error -result {can't specify state "open" for this command} test item-16.13 {item state: unknown states} -body { .t item state set 8 {foo bar} } -returnCodes error -result {unknown state "foo"} test item-16.14 {item state: unknown state leaded by !} -body { .t item state set 8 !foo } -returnCodes error -result {unknown state "foo"} test item-16.15 {item state: unknown state leaded by ~} -body { .t item state set 8 ~bar } -returnCodes error -result {unknown state "bar"} test item-16.16 {item state: switch on states} -body { .t item state set 8 state0 .t item state get 8 } -result {open enabled state0} test item-16.17 {item state get: user defined state set} -body { .t item state get 8 state0 } -result {1} test item-16.18 {item state: toggle state} -body { .t item state set 8 ~state0 .t item state get 8 } -result {open enabled} test item-16.19 {item state: switch off states} -body { .t item state set 8 !state0 .t item state get 8 state0 } -result {0} test item-16.20 {item state: reset predefined state} -body { .t item collapse 8 .t item state get 8 } -result {enabled} test item-16.21 {item state: reset predefined state} -body { .t item expand 8 .t item state get 8 } -result {open enabled} test item-16.22 {item state: reset predefined state} -body { .t item toggle 8 .t item state get 8 enabled } -result {1} test item-16.23 {item state: set range} -body { .t item state set 1 8 state0 set res {} foreach I [.t item id {range 1 8}] { lappend res [.t item state get $I state0] } set res } -result {1 1 1 1 1 1 1 1} test item-16.24 {item state: set list} -body { .t item state set {list {2 4 6 8}} !state0 set res {} foreach I [.t item id {range 1 8}] { lappend res [.t item state get $I state0] } set res } -result {1 0 1 0 1 0 1 0} test item-16.25 {item state: set all} -body { .t item state set all ~state0 set res {} foreach I [.t item id {range 1 8}] { lappend res [.t item state get $I state0] } set res } -result {0 1 0 1 0 1 0 1} test item-16.26 {item state set: invalid range} -body { set I [.t item create] .t item state set $I 8 state0 } -returnCodes error -result {item 13 and item 8 don't share a common ancestor} test item-16.40 {item state forcolumn: missing arg} -body { .t item state forcolumn } -returnCodes error -result {wrong # args: should be ".t item state forcolumn item column ?stateList?"} test item-16.41 {item state forcolumn: missing arg} -body { .t item state forcolumn 8 } -returnCodes error -result {wrong # args: should be ".t item state forcolumn item column ?stateList?"} test item-16.42 {item state forcolumn: too many args} -body { .t item state forcolumn a b c d } -returnCodes error -result {wrong # args: should be ".t item state forcolumn item column ?stateList?"} test item-16.43 {item state forcolumn: get for single item} -body { .t item state forcolumn 8 0 } -result {} test item-16.44 {item state forcolumn: get for all} -body { .t item state forcolumn all 0 } -returnCodes error -result {can't specify > 1 item for this command} test item-16.45 {item state forcolumn: set for single item} -body { .t item state forcolumn 8 0 state0 .t item state forcolumn 8 0 } -result {state0} test item-16.46 {item state forcolumn: set all} -body { .t item state forcolumn all 0 state0 set res {} foreach I [.t item id {range 1 8}] { lappend res [.t item state forcolumn $I 0] } set res } -result {state0 state0 state0 state0 state0 state0 state0 state0} test item-16.47 {item state forcolumn: set list} -body { .t item state forcolumn {list {2 4 6 8}} 0 !state0 set res {} foreach I [.t item id {range 1 8}] { lappend res [.t item state forcolumn $I 0] } set res } -result {state0 {} state0 {} state0 {} state0 {}} test item-16.50 {item state forcolumn: tail not allowed} -body { .t item state forcolumn root tail } -returnCodes error -result {can't specify "tail" for this command} test item-16.51 {item state forcolumn: tail not allowed} -body { .t item state forcolumn root tail foo } -returnCodes error -result {can't specify "tail" for this command} test item-17.1 {item sort: missing args} -body { .t item sort } -returnCodes error -result {wrong # args: should be ".t item sort item ?option ...?"} test item-17.2 {item sort: invalid item} -body { .t item sort foo } -returnCodes error -result {item "foo" doesn't exist} test item-17.3 {item sort: is all allowed?} -body { .t item sort all } -returnCodes error -result {can't specify > 1 item for this command} test item-17.4 {item sort: invalid option} -body { .t item sort root -foo } -returnCodes error -result {bad option "-foo": must be *} -match glob test item-17.5 {item sort: missing arg to an option} -body { .t item sort root -first } -returnCodes error -result {missing value for "-first" option} test item-17.6 {item sort: invalid column} -body { .t item sort root -column 3 } -returnCodes error -result {column "3" doesn't exist} test item-17.7 {item sort: invalid column, second try} -body { .t item sort root -column tail } -returnCodes error -result {can't specify "tail" for this command} test item-17.8 {item sort: sort needs style to find text} -body { .t item sort root } -returnCodes error -result {item 1 column 0 has no style} proc listItems {t {i root}} { set res {} foreach c [$t item children $i] { lappend res $c eval lappend res [listItems $t $c] } return $res } test item-17.9 {item sort: set the texts in column 0 for all items} -body { .t column create .t style create textStyle .t style elements textStyle {eRect eBorder eText} .t element create eTime text .t style create timeStyle .t style elements timeStyle eTime foreach i [listItems .t] { .t item style set $i 0 textStyle .t item style set $i 1 timeStyle .t item text $i 0 [expr {$i+5}] } .t item text 8 0 } -result {13} test item-17.10 {item sort: sort all by ascii} -body { .t item sort root listItems .t } -result {5 6 7 8 1 2 3 4} test item-17.11 {item sort: sort all decreasing by ascii} -body { .t item sort root -decreasing listItems .t } -result {1 2 3 4 8 5 6 7} test item-17.12 {item sort: sort all as integer} -body { .t item sort root -integer listItems .t } -result {1 2 3 4 5 6 7 8} test item-17.13 {item sort: for integers -dictionary works also} -body { .t item sort root -dictionary listItems .t } -result {1 2 3 4 5 6 7 8} test item-17.14 {item sort: sort all decreasing as integer} -body { .t item sort root -integer -decreasing listItems .t } -result {8 5 6 7 1 2 3 4} test item-17.15 {item sort: don't sort, only return sorted items} -body { .t item lastchild root 5 list [.t item sort root -notreally] [listItems .t] } -result {{5 8 1} {8 1 2 3 4 5 6 7}} test item-17.16 {item sort: return integer sorted items} -body { .t item sort root -notreally -integer } -result {1 5 8} test item-17.17 {item sort: return integer sorted items} -body { .t item sort root -notreally -dictionary -decreasing } -result {8 5 1} test item-17.18 {item sort: two sort options, last wins (as in lsort)} -body { .t item sort root -integer -ascii listItems .t } -result {5 6 7 8 1 2 3 4} test item-17.19 {item sort: two order options, last wins (as in lsort)} -body { .t item sort root -real -decreasing -increasing listItems .t } -result {1 2 3 4 5 6 7 8} test item-17.20 {item sort: restrict to item of different parent} -body { .t item sort root -first 2 } -returnCodes error -result {item 2 is not a child of item 0} test item-17.21 {item sort: restrict to unknown item} -body { .t item sort root -first foo } -returnCodes error -result {item "foo" doesn't exist} test item-17.22 {item sort: restricted sort} -body { .t item sort root -first 5 -last 8 -decreasing listItems .t } -result {1 2 3 4 8 5 6 7} test item-17.23 {item sort: restricted sort returned} -body { .t item sort root -first 5 -last 8 -notreally } -result {5 8} test item-17.24 {item sort: order of restriction doesn't matter} -body { .t item sort root -first 8 -last 5 -notreally } -result {5 8} test item-17.25 {item sort: very restricted sort returned} -body { .t item sort root -first 5 -last 5 -notreally } -result {5} test item-17.26 {item sort -command: missing arg} -body { .t item sort root -command } -returnCodes error -result {missing value for "-command" option} test item-17.27 {item sort -command: unknown command} -body { .t item sort root -command foo } -returnCodes error -result {invalid command name "foo"} test item-17.28 {item sort -command: unknown command} -body { .t item sort root -command # } -returnCodes error -result {invalid command name "#"} test item-17.29 {item sort -command: invalid return value} -body { .t item sort root -command list } -returnCodes error -result {-command returned non-numeric result} proc myCompare {op item1 item2} { switch -- $op { 1 - 0 - -1 { return $op } timespan-1 { regsub -all : [.t item text $item1 1] "" val1 regsub -all : [.t item text $item2 1] "" val2 return [expr {[string trimleft $val1 0]-[string trimleft $val2 0]}] } ascii { return [string compare [.t item text $item1 0] \ [.t item text $item2 0]] } ascii-1 { return [string compare [.t item text $item1 1] \ [.t item text $item2 1]] } default { return -code $op 0 } } } test item-17.30 {item sort -command: too less arguments to proc call} -body { .t item sort root -command myCompare } -returnCodes error -result {wrong # args: should be "myCompare op item1 item2"} test item-17.31 {item sort -command: always returning 0 is identity} -body { set res [list [listItems .t]] .t item sort root -command {myCompare 0} lappend res [listItems .t] } -result {{1 2 3 4 8 5 6 7} {1 2 3 4 8 5 6 7}} test item-17.32 {item sort -command: returnCode break} -body { list [catch {.t item sort root -command {myCompare break}} msg] $msg \ $errorInfo } -result {3 0 {0 (evaluating item sort -command)}} test item-17.33 {item sort -command: always returning 1 is identity?} -body { set res [list [listItems .t]] .t item sort root -command {myCompare 1} } -returnCodes error -result {buggy item sort -command detected} test item-17.34 {item sort -command: always returning -1 reverts?} -constraints { knownBug } -body { .t item sort root -command {myCompare -1} } -returnCodes error -result {buggy item sort -command detected} test item-17.35 {item sort -command: ascii} -body { .t item sort root -command {myCompare ascii} listItems .t } -result {5 6 7 8 1 2 3 4} test item-17.36 {item sort -command: reverse ascii} -body { .t item sort root -command {myCompare ascii} -decreasing listItems .t } -result {1 2 3 4 8 5 6 7} test item-17.37 {item sort: with timespans column} -body { .t item text 1 1 "01:00" .t item text 5 1 "10:00" .t item text 8 1 "02:09:00" .t item sort root -column 1 listItems .t } -result {1 2 3 4 8 5 6 7} test item-17.38 {item sort -command: ascii with timespans column} -body { .t item sort root -command {myCompare ascii-1} listItems .t } -result {1 2 3 4 8 5 6 7} test item-17.39 {item sort -command: timespan with timespans column} -body { .t item sort root -command {myCompare timespan-1} listItems .t } -result {1 2 3 4 5 6 7 8} test item-17.40 {item sort -command: reverse timespan with timespans} -body { .t item sort root -command {myCompare timespan-1} -decreasing listItems .t } -result {8 5 6 7 1 2 3 4} test item-17.41 {item sort -command: reverse timespan with timespans} -body { .t item sort root -command {myCompare timespan-1} -decreasing -notreally } -result {8 5 1} test item-17.42 {item sort -element: missing arg} -body { .t item sort root -element } -returnCodes error -result {missing value for "-element" option} test item-17.43 {item sort -element: invalid element} -body { .t item sort root -element foo } -returnCodes error -result {element "foo" doesn't exist} test item-17.44 {item sort -element: no text element} -body { .t item sort root -element eBorder } -returnCodes error -result {element eBorder is not of type "text"} test item-17.45 {item sort -element: element in wrong column} -body { .t item sort root -column 1 -element eText -dictionary listItems .t } -returnCodes error -result {style timeStyle does not use element eText} test item-17.46 {item sort -element: -colum defaults to 0} -body { .t item sort root -element eTime listItems .t } -returnCodes error -result {style textStyle does not use element eTime} test item-17.47 {item sort -element: element in columns} -body { .t item sort root -column 1 -element eTime listItems .t } -result {1 2 3 4 8 5 6 7} ;# same result as in 17.37 test item-17.48 {item sort -element: useless for -command} -body { .t item sort root -column 1 -element eTime -command {myCompare timespan-1} listItems .t } -result {1 2 3 4 5 6 7 8} ;# same result as in 17.39 test item-17.49 {item sort -command: no columns} -body { while {![catch {.t column configure "order 0"}]} { .t column delete "order 0" } .t item sort root } -returnCodes error -result {there are no columns} test item-18.1 {item enabled: too few args} -body { .t item enabled } -returnCodes error -result {wrong # args: should be ".t item enabled item ?boolean?"} test item-18.2 {item enabled: too many args} -body { .t item enabled a b c } -returnCodes error -result {wrong # args: should be ".t item enabled item ?boolean?"} test item-18.3 {item enabled: null item} -body { .t item enabled 99 } -returnCodes error -result {item "99" doesn't exist} test item-18.4 {item enabled: single item get} -body { .t item enabled root } -result {1} test item-18.5 {item enabled: single item set} -body { .t item enabled root false set res {} foreach I [.t item id {range first last}] { lappend res [.t item enabled $I] } set res } -result {0 1 1 1 1 1 1 1 1} test item-18.6 {item enabled: all get} -body { .t item enabled all } -returnCodes error -result {can't specify > 1 item for this command} test item-18.7 {item enabled: all set} -body { .t item enabled all false set res {} foreach I [.t item id {range first last}] { lappend res [.t item enabled $I] } set res } -result {0 0 0 0 0 0 0 0 0} test item-18.8 {item enabled: multi get} -body { .t item enabled {list {2 4 7}} } -returnCodes error -result {can't specify > 1 item for this command} test item-18.9 {item enabled: multi set} -body { .t item enabled {list {2 4 7}} true set res {} foreach I [.t item id {range first last}] { lappend res [.t item enabled $I] } set res } -result {0 0 1 0 1 0 0 1 0} test item-19.1 {item text: too few args} -body { .t item text } -returnCodes error -result {wrong # args: should be ".t item text item ?column? ?text? ?column text ...?"} test item-19.2 {item text: all items, get every column} -body { .t item text all } -returnCodes error -result {can't specify > 1 item for this command} test item-19.3 {item text: all items, set first column} -body { .t column create .t item style set all first testStyle .t item text all first abc set res {} foreach I [.t item id {range first last}] { lappend res [.t item text $I first] } set res } -result {abc abc abc abc abc abc abc abc abc} test item-19.4 {item text: all items, get first column} -body { .t item text all first } -returnCodes error -result {can't specify > 1 item for this command} test item-19.5 {item text: several items, set first column} -body { .t item text {list {2 4 6 8}} first def set res {} foreach I [.t item id {range first last}] { lappend res [.t item text $I first] } set res } -result {abc abc def abc def abc def abc def} test item-19.6 {item text: several items, get first column} -body { .t item text {list {2 4 6 8}} first } -returnCodes error -result {can't specify > 1 item for this command} test item-19.10 {item text: tail not allowed} -body { .t item text root tail } -returnCodes error -result {can't specify "tail" for this command} test item-19.11 {item text: tail not allowed} -body { .t item text root tail "hello" } -returnCodes error -result {can't specify "tail" for this command} test item-20.1 {item tag: too few args} -body { .t item tag } -returnCodes error -result {wrong # args: should be ".t item tag command ?arg arg ...?"} test item-20.2 {item tag add: too few args} -body { .t item tag add } -returnCodes error -result {wrong # args: should be ".t item tag add item tagList"} test item-20.3 {item tag add: too many args} -body { .t item tag add a b c } -returnCodes error -result {wrong # args: should be ".t item tag add item tagList"} test item-20.4 {item tag names: too few args} -body { .t item tag names } -returnCodes error -result {wrong # args: should be ".t item tag names item"} test item-20.5 {item tag names: too many args} -body { .t item tag names a b } -returnCodes error -result {wrong # args: should be ".t item tag names item"} test item-20.6 {item tag remove: too few args} -body { .t item tag remove } -returnCodes error -result {wrong # args: should be ".t item tag remove item tagList"} test item-20.7 {item tag remove: too many args} -body { .t item tag remove a b c } -returnCodes error -result {wrong # args: should be ".t item tag remove item tagList"} test item-20.11 {item tag: add tags to all} -body { .t item delete all .t item create -count 9999 -parent root .t item tag add all {a b c} .t item tag expr all {c && a && b} } -result {1} test item-20.12 {item tag: add duplicate tags} -body { .t item tag add all {c b a} lsort [.t item tag names all] } -result {a b c} test item-20.13 {item tag: remove 1 tag from several items} -body { .t item tag remove {range 100 5000} b list [lsort [.t item tag names all]] [lsort [.t item tag names {range 100 5000}]] } -result {{a b c} {a c}} test item-20.14 {item tag: remove 1 tag from all items} -body { .t item tag remove all b lsort [.t item tag names all] } -result {a c} test item-20.15 {item tag: add tags to all (some dups)} -body { .t item tag add all {a e f b d h g} lsort [.t item tag names all] } -result {a b c d e f g h} test item-20.16 {item tag: long expr} -body { llength [.t item id "tag {(a && e) && (f && b) && (d && h && g)}"] } -result {10000} test item-20.17 {item tag: remove b from 100 items} -body { .t item tag remove {range 100 199} b llength [.t item id "tag !b"] } -result {100} test item-20.18 {item tag: expr} -body { llength [.t item id "tag b"] } -result {9900} test item-20.19 {item tag: remove e from 100 items, overlapping 50 of !b items} -body { .t item tag remove {range 150 249} e llength [.t item id "tag !e"] } -result {100} test item-20.20 {item tag: expr} -body { llength [.t item id "tag {(!b || !e)}"] } -result {150} test item-20.21 {item tag: expr} -body { llength [.t item id "tag b^e"] } -result {100} test item-20.22 {item tag: expr} -body { .t item tag remove {tag !b||!e} {a c d f g h} llength [.t item id "tag !a"] } -result {150} test item-20.23 {item tag: item create -tags} -body { .t item create -count 50 -tags {orphan50 x y z} llength [.t item id "tag x"] } -result {50} test item-20.24 {item tag: item create -tags with dups} -body { .t item create -count 10 -tags {orphan10 x z x y z y} lsort [.t item tag names "tag orphan10"] } -result {orphan10 x y z} test item-20.40 {item tag: [expr]} -body { .t item tag expr "tag orphan50" x } -result {1} test item-20.41 {item tag: [expr]} -body { .t item tag expr "all tag orphan50" x&&y&&z } -result {1} test item-20.42 {item tag: [expr]} -body { .t item tag expr "tag orphan50" a } -result {0} test item-20.43 {item tag: [expr]} -body { .t item tag expr 100 e^b } -cleanup { .t item delete all } -result {1} test item-21.1 {item count: too many args} -body { .t item count a b } -returnCodes error -result {wrong # args: should be ".t item count ?itemDesc?"} test item-21.2 {item count: no args, only root} -body { .t item count } -result {1} test item-21.2 {item count: no args, many items} -setup { .t item create -count 50 -parent root } -body { .t item count } -result {51} test item-21.3 {item count: double-check with range} -body { expr {[.t item count] == [llength [.t item range first last]]} } -result {1} test item-21.4 {item count: double-check with range} -body { expr {[.t item count] == [.t item count "range first last"]} } -result {1} test item-21.5 {item count: all is same as no args} -body { expr {[.t item count] == [.t item count all]} } -result {1} test item-21.6 {item count: depth test} -body { .t item count "depth 1" } -result {50} test item-21.7 {item count: double-check with selection} -setup { .t selection add "range 10 20" } -body { expr {[.t item count "state selected"] == [.t selection count]} } -result {1} test item-22.1 {-button: default value} -setup { .t item delete all .t item create -tags foo } -body { .t item cget foo -button } -result {0} test item-22.2 {-button: default value} -body { .t item cget foo -button } -result {0} test item-22.3 {-button: set true} -body { .t item conf foo -button true .t item cget foo -button } -result {1} test item-22.4 {-button: set true} -body { .t item conf foo -button ON .t item cget foo -button } -result {1} test item-22.5 {-button: set false} -body { .t item conf foo -button NO .t item cget foo -button } -result {0} test item-22.6 {-button: set auto} -body { .t item conf foo -button auto .t item cget foo -button } -result {auto} test item-22.7 {-button: set auto abbreviation} -body { .t item conf foo -button a .t item cget foo -button } -result {auto} test item-23.1 {compare: missing args} -body { .t item compare } -returnCodes error -result {wrong # args: should be ".t item compare item1 op item2"} test item-23.2 {compare: unknown operator} -body { .t item compare root foo root } -returnCodes error -result {bad comparison operator "foo": must be <, <=, ==, >=, >, or !=} test item-23.3 {compare: unknown item} -body { .t item compare root foo bar } -returnCodes error -result {item "bar" doesn't exist} test item-23.4 {compare: same item} -body { set result {} foreach op {< <= == >= > !=} { lappend result [.t item compare root $op root] } set result } -result {0 1 1 1 0 0} test item-23.5 {compare: different items} -setup { .t item delete all .t item create -tags item1 -parent root .t item create -tags item2 -parent root } -body { set result {} foreach op {< <= == >= > !=} { lappend result [.t item compare item1 $op item2] } set result } -result {1 1 0 0 0 1} test item-23.6 {compare: different items} -setup { .t item delete all .t item create -tags item1 -parent root .t item create -tags item2 -parent root } -body { set result {} foreach op {< <= == >= > !=} { lappend result [.t item compare item2 $op item1] } set result } -result {0 0 0 1 1 1} test item-23.7 {compare: uncommon ancestor, LT} -setup { .t item delete all .t item create -tags item1 ; # no parent .t item create -tags item2 ; # no parent } -body { .t item compare item1 < item2 } -returnCodes error -result {item 1 and item 2 don't share a common ancestor} test item-23.8 {compare: uncommon ancestor, GT} -body { .t item compare item1 > item2 } -returnCodes error -result {item 1 and item 2 don't share a common ancestor} test item-23.9 {compare: uncommon ancestor, EQ or NE} -body { .t item compare item1 == item2 .t item compare item1 != item2 } -result {1} test item-24.1 {buttonstate: missing args} -body { .t item buttonstate } -returnCodes error -result {wrong # args: should be ".t item buttonstate item ?state?"} test item-24.2 {buttonstate: unknown item} -body { .t item buttonstate foo } -returnCodes error -result {item "foo" doesn't exist} test item-24.3 {buttonstate: current state} -body { .t item buttonstate root } -result {normal} test item-24.4 {buttonstate: unknown state} -body { .t item buttonstate root foo } -returnCodes error -result {bad state "foo": must be active, normal, or pressed} test item-24.5 {buttonstate: set state} -body { .t item buttonstate root active } -result {active} test item-25.1 {span: too few args} -setup { .t item delete all .t item create -parent root -tags item0 .t column delete all .t column create -tags column0 .t column create -tags column1 .t column create -tags column2 .t column create -tags column3 } -body { .t item span } -returnCodes error -result {wrong # args: should be ".t item span item ?column? ?span? ?column span ...?"} test item-25.2 {span: unknown item} -body { .t item span foo } -returnCodes error -result {item "foo" doesn't exist} test item-25.3 {span: multiple items no column not allowed} -body { .t item span all } -returnCodes error -result {can't specify > 1 item for this command} test item-25.4 {span: single item, no column} -body { .t item span root } -result {1 1 1 1} test item-25.5 {span: multiple items single column not allowed} -body { .t item span all column0 } -returnCodes error -result {can't specify > 1 item for this command} test item-25.6 {span: single item missing span} -body { .t item span root column0 1 column1 } -returnCodes error -result {missing argument after column "column1"} test item-25.7 {span: multiple items missing span} -body { .t item span all column0 1 column1 } -returnCodes error -result {missing argument after column "column1"} test item-25.8 {span: single item single column} -body { .t item span root column0 } -result {1} test item-25.9 {span: single item multiple columns} -body { .t item span root all 3 .t item span root } -result {3 3 3 3} test item-25.10 {span: multiple items multiple columns} -body { .t item span all all 2 list [.t item span root] [.t item span item0] } -result {{2 2 2 2} {2 2 2 2}} test item-99.1 {some needed cleanup} -body { destroy .t } -result {} # cleanup ::tcltest::cleanupTests return tktreectrl-2.4.1/tests/itemdesc.test0000644000076400010400000003370011562311305020053 0ustar TimAdministrators# Commands covered: item descriptions # # This file contains a collection of tests for the treectrl command of # the tktreectrl extension. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2000 by Scriptics Corporation. # Copyright (c) 2002 by Christian Krone. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } package require Tk package require treectrl # For the tests of the item descriptions we use [.t see], # if we want to generate an error on unknown items. # For the positive cases we use [.t item id] since it returns the item id. test itemdesc-0.1 {some needed preparations} -body { treectrl .t -itemheight 20 -showheader no .t column create -width 200 pack .t -expand yes -fill both update idletasks } -result {} test itemdesc-1.1 {bogus itemdesc} -body { .t item id "" } -returnCodes error -result {bad item description ""} test itemdesc-1.1.1 {bogus itemdesc} -body { .t item id "\{all" } -returnCodes error -result "bad item description \"\{all\"" test itemdesc-1.2 {all} -setup { .t item create -count 10 } -body { lsort -integer [.t item id all] } -cleanup { .t item delete all } -result {0 1 2 3 4 5 6 7 8 9 10} test itemdesc-1.3 {unknown id} -body { .t see 999 } -returnCodes error -result {item "999" doesn't exist} test itemdesc-1.4 {id of root} -body { .t item id 0 } -result {0} test itemdesc-1.5 {id of active} -body { .t item id active } -result {0} test itemdesc-1.6 {id of anchor (abbreviated)} -body { .t item id an } -result {0} test itemdesc-1.7 {first} -body { .t item id first } -result {0} test itemdesc-1.8 {first visible} -setup { .t configure -showroot 1 } -body { .t item id "first visible" } -result {0} test itemdesc-1.9 {first visible without any node} -setup { .t configure -showroot 0 } -body { .t see "first visible" } -returnCodes error -result {item "first visible" doesn't exist} test itemdesc-1.10 {last} -body { .t item id last } -result {0} test itemdesc-1.10.1 {end} -body { .t item id end } -result {0} test itemdesc-1.11 {last visible} -setup { .t configure -showroot 1 } -body { .t item id "last visible" } -result {0} test itemdesc-1.12 {last visible without any node} -setup { .t configure -showroot 0 } -body { .t see "last visible" } -returnCodes error -result {item "last visible" doesn't exist} test itemdesc-1.13 {nearest without x/y} -body { .t item id nearest } -returnCodes error -result {missing arguments to "nearest" keyword} test itemdesc-1.14 {nearest with invalid x/y} -body { .t item id "nearest foo bar" } -returnCodes error -result {bad screen distance "foo"} test itemdesc-1.15 {nearest with valid x/y} -setup { .t configure -showroot 1 } -body { .t item id "nearest 10 10" } -result {0} test itemdesc-1.16 {nearest with valid x/y, but no item} -setup { .t configure -showroot 0 } -body { .t item id "nearest 10 10" } -result {} # Before continuing to test the item descriptions and their modifiers, # lets create some items with this hierarchy: # 0 # + 1 # | + 2 # | + 3 # | + 4 # + 5 # | + 6 # | + 7 # + 8 test itemdesc-2.16 {create some items} -body { set n1 [.t item create]; .t item lastchild 0 $n1 set n2 [.t item create]; .t item lastchild $n1 $n2 set n3 [.t item create]; .t item lastchild $n1 $n3 set n4 [.t item create]; .t item lastchild $n3 $n4 set n5 [.t item create]; .t item lastchild 0 $n5 set n6 [.t item create]; .t item lastchild $n5 $n6 set n7 [.t item create]; .t item lastchild $n5 $n7 set n8 [.t item create]; .t item lastchild 0 $n8 } -result {8} test itemdesc-2.18 {rnc without r/c} -body { .t item id rnc } -returnCodes error -result {missing arguments to "rnc" keyword} test itemdesc-2.19 {rnc with invalid r/c} -body { .t item id "rnc foo bar" } -returnCodes error -result {expected integer but got "foo"} test itemdesc-2.20 {rnc with valid r/c} -body { .t item id "rnc 0 0" } -result {1} test itemdesc-2.21 {root} -body { .t configure -showroot 1 -orient vertical .t item id root } -result {0} test itemdesc-2.22 {bogus modifier} -body { .t item id "0 foo" } -returnCodes error -result {bad modifier "foo": must be *} -match glob test itemdesc-2.23 {valid modifier with too few arguments} -body { .t item id "0 child" } -returnCodes error -result {missing arguments to "child" modifier} test itemdesc-2.24 {modifier visible alone generates an error} -body { .t item id "0 visible" } -returnCodes error -result {bad modifier "visible": must be *} -match glob test itemdesc-2.25 {modifier above} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n above"] } set res } -result {{} 0 1 2 3 4 5 6 7} test itemdesc-2.26 {modifier below} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n below"] } set res } -result {1 2 3 4 5 6 7 8 {}} test itemdesc-2.27 {modifier bottom} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n bottom"] } set res } -result {8 8 8 8 8 8 8 8 8} test itemdesc-2.28 {modifier child} -body { set res {} for {set n 0} {$n < 6} {incr n} { for {set c 0} {$c < 3} {incr c} { lappend res [.t item id "$n child $c"] } } set res } -result {1 5 8 2 3 {} {} {} {} 4 {} {} {} {} {} 6 7 {}} test itemdesc-2.29 {modifier firstchild} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n firstchild"] } set res } -result {1 2 {} 4 {} 6 {} {} {}} test itemdesc-2.30 {modifier lastchild} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n lastchild"] } set res } -result {8 3 {} 4 {} 7 {} {} {}} test itemdesc-2.30 {modifier left, leftmost, right, and rightmost} -body { list [.t item id "1 left"] [.t item id "1 right"] \ [.t item id "2 leftmost"] [.t item id "3 rightmost"] } -result {{} {} 2 3} test itemdesc-2.31 {modifier next} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n next"] } set res } -result {1 2 3 4 5 6 7 8 {}} test itemdesc-2.32 {modifier nextsibling} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n nextsibling"] } set res } -result {{} 5 3 {} {} 8 7 {} {}} test itemdesc-2.33 {modifier parent} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n parent"] } set res } -result {{} 0 1 1 3 0 5 5 0} test itemdesc-2.34 {modifier prev} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n prev"] } set res } -result {{} 0 1 2 3 4 5 6 7} test itemdesc-2.34 {modifier prevsibling} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n prevsibling"] } set res } -result {{} {} {} 2 {} 1 {} 6 5} test itemdesc-2.35 {modifier sibling} -body { set res {} for {set n 0} {$n < 7} {incr n} { for {set c 0} {$c < 3} {incr c} { lappend res [.t item id "$n sibling $c"] } } set res } -result {{} {} {} 1 5 8 2 3 {} 2 3 {} 4 {} {} 1 5 8 6 7 {}} test itemdesc-2.36 {modifier top} -body { set res {} for {set n 0} {$n < 9} {incr n} { lappend res [.t item id "$n top"] } set res } -result {0 0 0 0 0 0 0 0 0} test itemdesc-2.37 {modifier cocktail} -body { set res {} set itemDesc 7 foreach mod { bottom rightmost sibling 0 nextsibling prev parent prevsibling prev nextsibling lastchild next } { lappend itemDesc $mod catch {lappend res [.t item id $itemDesc]} } set res } -result {8 8 1 5 4 3 2 1 5 7 8} test itemdesc-2.38 {multiple items: list} -body { .t item id "list {3 8 8}" } -result {3 8 8} test itemdesc-2.39 {multiple items: range} -body { .t item id "range 1 6" } -result {1 2 3 4 5 6} test itemdesc-2.40 {multiple items: range reversed} -body { .t item id "range 6 1" } -result {1 2 3 4 5 6} test itemdesc-2.41 {multiple items: ancestors} -body { .t item id "4 ancestors" } -result {3 1 0} test itemdesc-2.42 {multiple items: children} -body { .t item id "root children" } -result {1 5 8} test itemdesc-2.43 {multiple items: nested list} -body { .t item id "list {3 {list {1 root}} 4}" } -result {3 1 0 4} test itemdesc-2.44 {multiple items: descendants} -body { .t item id "1 descendants" } -result {2 3 4} # qualifiers in item descriptions test itemdesc-3.1 {where visible is allowed} -body { .t item collapse 3 .t item collapse 5 set res {} foreach index { first last } { lappend res [.t item id "$index visible"] } foreach modifier { next prev firstchild lastchild {child 1} nextsibling prevsibling {sibling 0} } { lappend res [.t item id "5 $modifier visible"] } set res } -result {0 8 8 3 {} {} {} 8 1 1} test itemdesc-3.2 {where state is allowed} -body { set res {} foreach index { first last } { lappend res [.t item id "$index state enabled"] } foreach modifier { next prev firstchild lastchild {child 0} nextsibling prevsibling {sibling 0} } { lappend res [.t item id "5 $modifier state enabled"] } set res } -result {0 8 6 4 6 7 6 8 1 1} test itemdesc-3.3 {qualifier state: missing args} -body { .t item id "first state" } -returnCodes error -result {missing arguments to "state" qualifier} test itemdesc-3.4 {qualifier state: unknown state} -body { .t item id "first state foo" } -returnCodes error -result {unknown state "foo"} test itemdesc-3.5 {qualifier state: toggle not allowed} -body { .t item id "first state ~open" } -returnCodes error -result {can't specify '~' for this command} test itemdesc-3.6 {qualifier state: open ok} -body { .t item id "first state open" } -result {0} test itemdesc-3.7 {qualifier state: !open ok} -body { set res {} lappend res [.t item id "first state !open"] lappend res [.t item id "last state !open"] } -result {3 5} test itemdesc-3.8 {qualifier state: multiple states} -body { .t item id "last state {open enabled active}" } -result {0} test itemdesc-3.9 {qualifier after index and modifier} -body { .t item id "first state !open next state !open" } -result {5} test itemdesc-3.10 {qualifier state: following each modifier} -body { set res {} foreach modifier { firstchild lastchild {child 0} } { lappend res [.t item id "root $modifier state !open"] } foreach modifier { next prev nextsibling prevsibling {sibling 0} } { lappend res [.t item id "1 $modifier state !open"] } .t item expand 3 .t item expand 5 set res } -result {5 5 5 3 {} 5 {} 5} test itemdesc-4.1 {modifiers following multiple items is forbidden} -body { .t item id "all children" } -returnCodes error -result {unexpected arguments after "all"} test itemdesc-4.2 {modifiers following multiple items is forbidden} -body { .t item id "all visible children" } -returnCodes error -result {unexpected arguments after "all visible"} test itemdesc-4.3 {modifiers following multiple items is forbidden} -body { .t item id "range 1 2 next" } -returnCodes error -result {unexpected arguments after "range 1 2"} test itemdesc-4.4 {modifiers following multiple items is forbidden} -body { .t item id "1 descendants next" } -returnCodes error -result {unexpected arguments after "1 descendants"} test itemdesc-4.5 {modifiers following multiple items is forbidden} -setup { .t item tag add "1 descendants" tagA } -body { lsort -integer [.t item id "tagA above"] } -cleanup { .t item tag remove all tagA } -returnCodes error -result {unexpected arguments after "tagA"} test itemdesc-4.10 {modifiers following single item ok} -setup { .t item tag add 3 tagA } -body { lsort -integer [.t item id "tagA above"] } -cleanup { .t item tag remove all tagA } -result {2} test itemdesc-5.1 {qualifiers may be first} -body { lsort -integer [.t item id "depth 1"] } -result {1 5 8} test itemdesc-5.2 {qualifiers may be first} -body { lsort -integer [.t item id "visible"] } -result {0 1 2 3 4 5 6 7 8} test itemdesc-5.3 {qualifiers may be first} -setup { .t item collapse 3 } -body { lsort -integer [.t item id "!visible"] } -cleanup { .t item expand 3 } -result {4} test itemdesc-5.4 {qualifiers may be first} -setup { .t item tag add "1 descendants" a } -body { lsort -integer [.t item id "tag a"] } -cleanup { .t item tag remove all a } -result {2 3 4} test itemdesc-5.5 {qualifiers may be first} -setup { .t item collapse {list {3 5}} } -body { lsort -integer [.t item id "state !open"] } -cleanup { .t item expand {list {3 5}} } -result {3 5} test itemdesc-6.1 {-itemprefix} -setup { .t configure -itemprefix item } -body { lsort -dictionary [.t item id "item1 descendants"] } -cleanup { .t configure -itemprefix "" } -result {item2 item3 item4} test itemdesc-6.2 {-itemprefix same as a tag} -setup { .t configure -itemprefix item .t item tag add all item1 } -body { lsort -dictionary [.t item id "item1 descendants"] } -cleanup { .t configure -itemprefix "" .t item tag remove all item1 } -result {item2 item3 item4} test itemdesc-7.1 {-itemtagexpr, error} -setup { .t item tag add "depth 1" a&&b|| } -body { lsort -dictionary [.t item id "tag a&&b||"] } -returnCodes error -result {Missing tag in tag search expression} test itemdesc-7.2 {-itemtagexpr, tag as first word} -setup { .t configure -itemtagexpr false } -body { lsort -dictionary [.t item id "a&&b||"] } -result {1 5 8} test itemdesc-7.3 {-itemtagexpr, tag as qualifier} -body { lsort -dictionary [.t item id "tag a&&b||"] } -cleanup { .t configure -itemtagexpr true .t item tag remove all a&&b|| } -result {1 5 8} test itemdesc-99.1 {some needed cleanup} -body { destroy .t } -result {} # cleanup ::tcltest::cleanupTests return tktreectrl-2.4.1/tests/notify-old.test0000644000076400010400000003262511565025665020365 0ustar TimAdministrators# Commands covered: treectrl's widget command notify # # This file contains a collection of tests for the notify widget command of # the tktreectrl extension. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2000 by Scriptics Corporation. # Copyright (c) 2002 by Christian Krone. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } package require Tk package require treectrl test notify-0.1 {some needed preparations} -body { treectrl .t } -result {.t} test notify-1.1 {notify: missing args} -body { .t notify } -returnCodes error -result {wrong # args: should be ".t notify command ?arg arg ...?"} test notify-1.2 {notify: unknown command} -body { .t notify foo } -returnCodes error -result {bad command "foo": must be *} -match glob test notify-2.1 {notify eventnames: too much args} -body { .t notify eventnames Open } -returnCodes error -result {wrong # args: should be ".t notify eventnames"} test notify-2.2 {notify eventnames: nothing own installed yet} -body { lsort [.t notify eventnames] } -result {ActiveItem Collapse Expand ItemDelete ItemVisibility Scroll Selection} test notify-2.3 {notify install: missing args} -body { .t notify install } -returnCodes error -result {wrong # args: should be ".t notify install pattern ?percentsCommand?"} test notify-2.4 {notify install: bad pattern} -body { .t notify install foo } -returnCodes error -result {missing "<" in event pattern "foo"} test notify-2.5 {notify install event: old-style missing args} -body { .t notify install event } -returnCodes error -result {wrong # args: should be ".t notify install event name ?percentsCommand?"} test notify-2.6 {notify install event: old-style too much args} -body { .t notify install event foo bar baz } -returnCodes error -result {wrong # args: should be ".t notify install event name ?percentsCommand?"} test notify-2.7 {notify install event} -body { .t notify install event Greetings .t notify install event GoodBye } -result {} test notify-2.8 {notify eventnames: list Greetings} -body { lsort [.t notify eventnames] } -result {ActiveItem Collapse Expand GoodBye Greetings ItemDelete ItemVisibility Scroll Selection} test notify-2.9 {notify detailnames: missing args} -body { .t notify detailnames } -returnCodes error -result {wrong # args: should be ".t notify detailnames eventName"} test notify-2.10 {notify detailnames: too many args} -body { .t notify detailnames foo bar } -returnCodes error -result {wrong # args: should be ".t notify detailnames eventName"} test notify-2.11 {notify detailnames: unknown event} -body { .t notify detailnames Hello } -returnCodes error -result {unknown event "Hello"} test notify-2.12 {notify detailnames: no details yet} -body { .t notify detailnames Greetings } -result {} test notify-2.13 {notify install detail: old-style missing args} -body { .t notify install detail } -returnCodes error -result {wrong # args: should be ".t notify install detail event detail ?percentsCommand?"} test notify-2.14 {notify install detail: old-style unknown event} -body { .t notify install detail Hello GoodBye } -returnCodes error -result {unknown event "Hello"} test notify-2.15 {notify install detail} -body { .t notify install detail Greetings Wrote .t notify install detail Greetings Sent } -result {} test notify-2.16 {notify detailnames} -body { lsort [.t notify detailnames Greetings] } -result {Sent Wrote} test notify-3.1 {notify linkage: missing args} -body { .t notify linkage } -returnCodes error -result {wrong # args: should be ".t notify linkage pattern"} test notify-3.2 {notify linkage: unknown event} -body { .t notify linkage foo } -returnCodes error -result {unknown event "foo"} test notify-3.3 {notify linkage: standard event} -body { .t notify linkage Scroll } -result {static} test notify-3.4 {notify linkage: self made event} -body { .t notify linkage Greetings } -result {dynamic} test notify-3.5 {notify linkage: unknown detail} -body { .t notify linkage Greetings foo } -returnCodes error -result {unknown detail "foo" for event "Greetings"} test notify-3.6 {notify linkage: standard event} -body { .t notify linkage Scroll x } -result {static} test notify-3.7 {notify linkage: self made event} -body { .t notify linkage Greetings Sent } -result {dynamic} test notify-4.1 {notify bind: too much args} -body { .t notify bind z y z z y } -returnCodes error -result {wrong # args: should be ".t notify bind ?object? ?pattern? ?script?"} test notify-4.2 {notify bind: nothing bound yet} -body { .t notify bind .t } -result {} test notify-4.3 {notify bind: invalid pattern} -body { .t notify bind .t Greetings } -returnCodes error -result {missing "<" in event pattern "Greetings"} test notify-4.4 {notify bind: unknown event} -body { .t notify bind .t } -returnCodes error -result {unknown event "Hello"} test notify-4.5 {notify bind: unknown detail} -body { .t notify bind .t } -returnCodes error -result {unknown detail "Prepare" for event "Greetings"} test notify-4.6 {notify bind: nothing yet for simple event} -body { .t notify bind .t } -result {} test notify-4.7 {notify bind: simple event} -body { .t notify bind .t {puts -nonewline "Bye bye"} } -result {} test notify-4.8 {notify bind: simple event, script added} -body { .t notify bind .t {+puts ""} } -result {} test notify-4.9 {notify bind: simple event defined} -body { .t notify bind .t } -result {puts -nonewline "Bye bye" puts ""} test notify-4.10 {notify bind: nothing yet for event with detail} -body { .t notify bind .t } -result {} test notify-4.11 {notify bind: event with detail} -body { .t notify bind .t {puts -nonewline "Hello World"} .t notify bind .t {puts ""} } -result {} test notify-4.12 {notify bind: event with detail defined} -body { .t notify bind .t } -result {puts ""} test notify-4.13 {notify bind without pattern} -body { lsort [.t notify bind .t] } -result { } test notify-5.1 {notify configure: missing args} -body { .t notify configure } -returnCodes error -result {wrong # args: should be ".t notify configure object pattern ?option? ?value? ?option value ...?"} test notify-5.2 {notify configure: unknown event} -body { .t notify configure .t } -returnCodes error -result {unknown event "Hello"} test notify-5.3 {notify configure: unknown event with detail} -body { .t notify configure .t } -returnCodes error -result {unknown event "Hello"} test notify-5.4 {notify configure: unbound event} -body { .t notify configure .t } -result {} test notify-5.5 {notify configure: unbound event with details} -body { .t notify configure .t } -result {} test notify-5.6 {notify configure: dynamic event} -body { .t notify configure .t } -result {-active 1} test notify-5.7 {notify configure: dynamic event} -body { .t notify configure .t -active 0 .t notify configure .t } -result {-active 0} test notify-6.1 {notify generate: missing args} -body { .t notify generate } -returnCodes error -result {wrong # args: should be ".t notify generate pattern ?charMap? ?percentsCommand?"} test notify-6.2 {notify generate: invalid event} -body { .t notify generate Greetings } -returnCodes error -result {missing "<" in event pattern "Greetings"} test notify-6.3 {notify generate: virtual event} -body { .t notify generate <> } -returnCodes error -result {unknown event ""} test notify-6.4 {notify generate: unknown event} -body { .t notify generate } -returnCodes error -result {unknown event "Hello"} test notify-6.5 {notify generate: unknown detail} -body { .t notify generate } -returnCodes error -result {unknown detail "Prepare" for event "Greetings"} test notify-6.6 {notify generate: missing detail} -body { .t notify generate } -returnCodes error -result {cannot generate "": missing detail} test notify-6.7 {notify generate: NOW!} -body { .t notify generate } -output {Hello World} test notify-6.8 {notify generate: not active} -body { .t notify generate } -result {} test notify-6.9 {notify generate: and AGAIN!} -body { .t notify configure .t -active 1 .t notify generate } -output { } test notify-6.10 {notify generate: invalid percent char} -body { .t notify generate {foo bar} } -returnCodes error -result {invalid percent char "foo"} test notify-6.11 {notify generate: odd number of field args} -body { .t notify generate f } -returnCodes error -result {char map must have even number of elements} test notify-6.12 {notify generate: huge number of field args} -body { for {set x 1} {$x < 2048} {incr x} { lappend map f $x } .t notify generate $map } -output { } test notify-6.13 {notify generate: not so much field args} -body { .t notify generate \ {0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j X x} } -output { } test notify-6.14 {notify install/bind/generate: do some replacements} -body { .t notify install event Percent .t notify install detail Percent Test .t notify bind .t \ {puts -nonewline "%%W: %2 %b %| %~ %2 %b%%"} .t notify generate {2 to b be ~ not | or} } -output {%W: to be or not to be%} proc doMyOwnSubst {field window eventName detail args} { return [string map {2 TO b BE ~ NOT | OR} $field] } test notify-6.15 {notify install/bind/generate: my own replacements} -body { .t notify uninstall detail Percent Test .t notify install detail Percent Test doMyOwnSubst .t notify bind .t \ {puts -nonewline "%%W: %2 %b %| %~ %2 %b%%"} .t notify generate } -output {%W: TO BE OR NOT TO BE%} test notify-6.16 {notify install/bind/generate: standard replacements} -body { .t notify generate {2 to b be ~ not | or} } -output {%W: TO BE OR NOT TO BE%} test notify-6.17 {notify install/bind/generate: my own replacements} -body { .t notify uninstall detail Percent Test .t notify uninstall event Percent .t notify install event Percent doMyOwnSubst .t notify bind .t \ {puts -nonewline "%%W: %2 %b %| %~ %2 %b%%"} .t notify generate } -output {%W: TO BE OR NOT TO BE%} test notify-6.18 {notify install/bind/generate: standard replacements} -body { .t notify generate {2 to b be ~ not | or} } -output {%W: TO BE OR NOT TO BE%} test notify-7.1 {notify uninstall: missing args} -body { .t notify uninstall } -returnCodes error -result {wrong # args: should be ".t notify uninstall pattern"} test notify-7.2 {notify uninstall: unknown command} -body { .t notify uninstall foo } -returnCodes error -result {missing "<" in event pattern "foo"} test notify-7.3 {notify uninstall detail: missing args} -body { .t notify uninstall detail } -returnCodes error -result {wrong # args: should be ".t notify uninstall detail event detail"} test notify-7.4 {notify uninstall detail: too much args} -body { .t notify uninstall detail foo bar baz } -returnCodes error -result {wrong # args: should be ".t notify uninstall detail event detail"} test notify-7.5 {notify uninstall detail: unknown event} -body { .t notify uninstall detail foo bar } -returnCodes error -result {unknown event "foo"} test notify-7.6 {notify uninstall detail: unknown detail} -body { .t notify uninstall detail Greetings GoodBye } -returnCodes error -result {unknown detail "GoodBye" for event "Greetings"} test notify-7.7 {notify uninstall detail} -body { .t notify uninstall detail Greetings Sent } -result {} test notify-7.8 {notify uninstall detail: double check} -body { lsearch -exact [.t notify detailnames Greetings] Sent } -result {-1} test notify-7.9 {notify uninstall detail: delete a static detail} -body { .t notify uninstall detail Scroll x } -returnCodes error -result {can't uninstall static detail "x"} test notify-7.10 {notify uninstall event: missing args} -body { .t notify uninstall event } -returnCodes error -result {wrong # args: should be ".t notify uninstall event name"} test notify-7.11 {notify uninstall event: too much args} -body { .t notify uninstall event foo bar } -returnCodes error -result {wrong # args: should be ".t notify uninstall event name"} test notify-7.12 {notify uninstall event: unknown event} -body { .t notify uninstall event foo } -returnCodes error -result {unknown event "foo"} test notify-7.13 {notify uninstall event} -body { .t notify uninstall event Greetings } -result {} test notify-7.14 {notify uninstall event: double check} -body { lsearch -exact [.t notify eventnames] Greetings } -result {-1} test notify-7.15 {notify uninstall event: delete a static event} -body { .t notify uninstall event Scroll } -returnCodes error -result {can't uninstall static event "Scroll"} test notify-99.1 {some needed cleanup} -body { destroy .t } -result {} # cleanup ::tcltest::cleanupTests return tktreectrl-2.4.1/tests/notify.test0000644000076400010400000003153011565025672017601 0ustar TimAdministrators# Commands covered: treectrl's widget command notify # # This file contains a collection of tests for the notify widget command of # the tktreectrl extension. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2000 by Scriptics Corporation. # Copyright (c) 2002 by Christian Krone. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } package require Tk package require treectrl test notify-0.1 {some needed preparations} -body { treectrl .t } -result {.t} test notify-1.1 {notify: missing args} -body { .t notify } -returnCodes error -result {wrong # args: should be ".t notify command ?arg arg ...?"} test notify-1.2 {notify: unknown command} -body { .t notify foo } -returnCodes error -result {bad command "foo": must be *} -match glob test notify-2.1 {notify eventnames: too much args} -body { .t notify eventnames Open } -returnCodes error -result {wrong # args: should be ".t notify eventnames"} test notify-2.2 {notify eventnames: nothing own installed yet} -body { lsort [.t notify eventnames] } -result {ActiveItem Collapse Expand ItemDelete ItemVisibility Scroll Selection} test notify-2.3 {notify install: missing args} -body { .t notify install } -returnCodes error -result {wrong # args: should be ".t notify install pattern ?percentsCommand?"} test notify-2.4 {notify install: bad pattern} -body { .t notify install foo } -returnCodes error -result {missing "<" in event pattern "foo"} test notify-2.6 {notify install event: too much args} -body { .t notify install bar baz } -returnCodes error -result {wrong # args: should be ".t notify install pattern ?percentsCommand?"} test notify-2.7 {notify install event} -body { .t notify install .t notify install } -result {} test notify-2.8 {notify eventnames: list Greetings} -body { lsort [.t notify eventnames] } -result {ActiveItem Collapse Expand GoodBye Greetings ItemDelete ItemVisibility Scroll Selection} test notify-2.9 {notify detailnames: missing args} -body { .t notify detailnames } -returnCodes error -result {wrong # args: should be ".t notify detailnames eventName"} test notify-2.10 {notify detailnames: too many args} -body { .t notify detailnames foo bar } -returnCodes error -result {wrong # args: should be ".t notify detailnames eventName"} test notify-2.11 {notify detailnames: unknown event} -body { .t notify detailnames Hello } -returnCodes error -result {unknown event "Hello"} test notify-2.12 {notify detailnames: no details yet} -body { .t notify detailnames Greetings } -result {} test notify-2.15 {notify install detail} -body { .t notify install .t notify install } -result {} test notify-2.16 {notify detailnames} -body { lsort [.t notify detailnames Greetings] } -result {Sent Wrote} test notify-3.1 {notify linkage: missing args} -body { .t notify linkage } -returnCodes error -result {wrong # args: should be ".t notify linkage pattern"} test notify-3.2 {notify linkage: unknown event} -body { .t notify linkage } -returnCodes error -result {unknown event "foo"} test notify-3.3 {notify linkage: standard event} -body { .t notify linkage } -result {static} test notify-3.4 {notify linkage: self made event} -body { .t notify linkage } -result {dynamic} test notify-3.5 {notify linkage: unknown detail} -body { .t notify linkage } -returnCodes error -result {unknown detail "foo" for event "Greetings"} test notify-3.6 {notify linkage: standard event} -body { .t notify linkage } -result {static} test notify-3.7 {notify linkage: self made event} -body { .t notify linkage } -result {dynamic} test notify-4.1 {notify bind: too much args} -body { .t notify bind z y z z y } -returnCodes error -result {wrong # args: should be ".t notify bind ?object? ?pattern? ?script?"} test notify-4.2 {notify bind: nothing bound yet} -body { .t notify bind .t } -result {} test notify-4.3 {notify bind: invalid pattern} -body { .t notify bind .t Greetings } -returnCodes error -result {missing "<" in event pattern "Greetings"} test notify-4.4 {notify bind: unknown event} -body { .t notify bind .t } -returnCodes error -result {unknown event "Hello"} test notify-4.5 {notify bind: unknown detail} -body { .t notify bind .t } -returnCodes error -result {unknown detail "Prepare" for event "Greetings"} test notify-4.6 {notify bind: nothing yet for simple event} -body { .t notify bind .t } -result {} test notify-4.7 {notify bind: simple event} -body { .t notify bind .t {puts -nonewline "Bye bye"} } -result {} test notify-4.8 {notify bind: simple event, script added} -body { .t notify bind .t {+puts ""} } -result {} test notify-4.9 {notify bind: simple event defined} -body { .t notify bind .t } -result {puts -nonewline "Bye bye" puts ""} test notify-4.10 {notify bind: nothing yet for event with detail} -body { .t notify bind .t } -result {} test notify-4.11 {notify bind: event with detail} -body { .t notify bind .t {puts -nonewline "Hello World"} .t notify bind .t {puts ""} } -result {} test notify-4.12 {notify bind: event with detail defined} -body { .t notify bind .t } -result {puts ""} test notify-4.13 {notify bind without pattern} -body { lsort [.t notify bind .t] } -result { } test notify-5.1 {notify configure: missing args} -body { .t notify configure } -returnCodes error -result {wrong # args: should be ".t notify configure object pattern ?option? ?value? ?option value ...?"} test notify-5.2 {notify configure: unknown event} -body { .t notify configure .t } -returnCodes error -result {unknown event "Hello"} test notify-5.3 {notify configure: unknown event with detail} -body { .t notify configure .t } -returnCodes error -result {unknown event "Hello"} test notify-5.4 {notify configure: unbound event} -body { .t notify configure .t } -result {} test notify-5.5 {notify configure: unbound event with details} -body { .t notify configure .t } -result {} test notify-5.6 {notify configure: dynamic event} -body { .t notify configure .t } -result {-active 1} test notify-5.7 {notify configure: dynamic event} -body { .t notify configure .t -active 0 .t notify configure .t } -result {-active 0} test notify-6.1 {notify generate: missing args} -body { .t notify generate } -returnCodes error -result {wrong # args: should be ".t notify generate pattern ?charMap? ?percentsCommand?"} test notify-6.2 {notify generate: invalid event} -body { .t notify generate Greetings } -returnCodes error -result {missing "<" in event pattern "Greetings"} test notify-6.3 {notify generate: virtual event} -body { .t notify generate <> } -returnCodes error -result {unknown event ""} test notify-6.4 {notify generate: unknown event} -body { .t notify generate } -returnCodes error -result {unknown event "Hello"} test notify-6.5 {notify generate: unknown detail} -body { .t notify generate } -returnCodes error -result {unknown detail "Prepare" for event "Greetings"} test notify-6.6 {notify generate: missing detail} -body { .t notify generate } -returnCodes error -result {cannot generate "": missing detail} test notify-6.7 {notify generate: NOW!} -body { .t notify generate } -output {Hello World} test notify-6.8 {notify generate: not active} -body { .t notify generate } -result {} test notify-6.9 {notify generate: and AGAIN!} -body { .t notify configure .t -active 1 .t notify generate } -output { } test notify-6.10 {notify generate: invalid percent char} -body { .t notify generate {foo bar} } -returnCodes error -result {invalid percent char "foo"} test notify-6.11 {notify generate: odd number of field args} -body { .t notify generate f } -returnCodes error -result {char map must have even number of elements} test notify-6.12 {notify generate: huge number of field args} -body { for {set x 1} {$x < 2048} {incr x} { lappend map f $x } .t notify generate $map } -output { } test notify-6.13 {notify generate: not so much field args} -body { .t notify generate \ {0 a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j X x} } -output { } test notify-6.14 {notify install/bind/generate: do some replacements} -body { .t notify install .t notify bind .t \ {puts -nonewline "%%W: %2 %b %| %~ %2 %b%%"} .t notify generate {2 to b be ~ not | or} } -output {%W: to be or not to be%} proc doMyOwnSubst {char object eventName detail charMap} { return [string map {2 TO b BE ~ NOT | OR} $char] } test notify-6.15 {notify install/bind/generate: my own replacements} -body { .t notify install doMyOwnSubst .t notify bind .t \ {puts -nonewline "%%W: %2 %b %| %~ %2 %b%%"} .t notify generate } -output {%W: TO BE OR NOT TO BE%} test notify-6.16 {notify install/bind/generate: standard replacements} -body { .t notify generate {2 to b be ~ not | or} } -output {%W: TO BE OR NOT TO BE%} test notify-6.17 {notify install/bind/generate: my own replacements} -body { .t notify uninstall .t notify install doMyOwnSubst .t notify bind .t \ {puts -nonewline "%%W: %2 %b %| %~ %2 %b%%"} .t notify generate } -output {%W: TO BE OR NOT TO BE%} test notify-6.18 {notify install/bind/generate: standard replacements} -body { .t notify generate {2 to b be ~ not | or} } -output {%W: TO BE OR NOT TO BE%} test notify-7.1 {notify uninstall: missing args} -body { .t notify uninstall } -returnCodes error -result {wrong # args: should be ".t notify uninstall pattern"} test notify-7.2 {notify uninstall: unknown command} -body { .t notify uninstall foo } -returnCodes error -result {missing "<" in event pattern "foo"} test notify-7.4 {notify uninstall: too much args} -body { .t notify uninstall foo bar } -returnCodes error -result {wrong # args: should be ".t notify uninstall pattern"} test notify-7.5 {notify uninstall detail: unknown event} -body { .t notify uninstall } -returnCodes error -result {unknown event "foo"} test notify-7.6 {notify uninstall detail: unknown detail} -body { .t notify uninstall } -returnCodes error -result {unknown detail "GoodBye" for event "Greetings"} test notify-7.7 {notify uninstall detail} -body { .t notify uninstall } -result {} test notify-7.8 {notify uninstall detail: double check} -body { lsearch -exact [.t notify detailnames Greetings] Sent } -result {-1} test notify-7.9 {notify uninstall detail: delete a static detail} -body { .t notify uninstall } -returnCodes error -result {can't uninstall static detail "x"} test notify-7.12 {notify uninstall event: unknown event} -body { .t notify uninstall } -returnCodes error -result {unknown event "foo"} test notify-7.13 {notify uninstall event} -body { .t notify uninstall } -result {} test notify-7.14 {notify uninstall event: double check} -body { lsearch -exact [.t notify eventnames] Greetings } -result {-1} test notify-7.15 {notify uninstall event: delete a static event} -body { .t notify uninstall } -returnCodes error -result {can't uninstall static event "Scroll"} test notify-8.1 {: set firstchild of a deleted item} -setup { .t item create -count 3 ; # item ids 1, 2 and 3 .t notify bind notify-8 { .t item firstchild %i 2 } set ::error {} proc bgerror msg {set ::error $msg} } -body { .t item delete 1 update ; # background error during set ::error } -cleanup { rename bgerror {} } -result {item 1 is being deleted} test notify-8.2 {: set firstchild to a deleted item} -setup { .t notify bind notify-8 { .t item firstchild 2 %i } set ::error {} proc bgerror msg {set ::error $msg} } -body { .t item delete 3 update ; # background error during set ::error } -cleanup { rename bgerror {} } -result {item 3 is being deleted} test notify-99.1 {some needed cleanup} -body { destroy .t } -result {} # cleanup ::tcltest::cleanupTests return tktreectrl-2.4.1/tests/style.test0000644000076400010400000005132311565025701017424 0ustar TimAdministrators# Commands covered: treectrl's widget command style # # This file contains a collection of tests for the style widget command of # the tktreectrl extension. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2000 by Scriptics Corporation. # Copyright (c) 2002 by Christian Krone. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } package require Tk package require treectrl test style-0.1 {some needed preparations} -body { pack [treectrl .t] } -result {} test style-0.2 {some other preparations} -body { .t element create eBorder border .t element create eText text .t element create eImage image .t element create eRect rect list } -result {} test style-1.1 {style: missing args} -body { .t style } -returnCodes error -result {wrong # args: should be ".t style command ?arg arg ...?"} test style-1.2 {style: invalid command} -body { .t style foo } -returnCodes error -result {bad command "foo": must be *} -match glob test style-1.3 {style names: no style exists yet} -body { .t style names } -result {} test style-2.1 {style create: missing args} -body { .t style create } -returnCodes error -result {wrong # args: should be ".t style create name ?option value ...?"} test style-2.2 {style create: invalid option} -body { .t style create testStyle -foo bar } -returnCodes error -result {unknown option "-foo"} test style-2.3 {style create} -body { .t style create testStyle } -result {testStyle} test style-2.4 {style create: already existing style} -body { .t style create testStyle } -returnCodes error -result {style "testStyle" already exists} test style-3.1 {style configure: invalid option} -body { .t style configure testStyle -foo bar } -returnCodes error -result {unknown option "-foo"} test style-3.2 {style configure: all options} -body { .t style configure testStyle } -result {{-buttony {} {} {} {}} {-orient {} {} horizontal horizontal}} test style-3.3 {style configure: the only option} -body { .t style configure testStyle -orient } -result {-orient {} {} horizontal horizontal} test style-3.4 {style configure: invalid option -orient} -body { .t style configure testStyle -orient diagonal } -returnCodes error -result {bad orient "diagonal": must be horizontal or vertical} test style-3.5 {style configure/cget: option -orient} -body { .t style configure testStyle -orient vertical .t style cget testStyle -orient } -result {vertical} test style-4.1 {style delete: unknown style} -body { .t style delete testStyle2 } -returnCodes error -result {style "testStyle2" doesn't exist} test style-4.2 {style delete: unknown style} -body { .t style names } -result {testStyle} test style-4.3 {style delete} -body { .t style delete testStyle } -result {} test style-4.4 {style names: no style defined} -body { .t style names } -result {} test style-5.1 {style elements: missing args} -body { .t style elements } -returnCodes error -result {wrong # args: should be ".t style elements name ?elementList?"} test style-5.2 {style elements: unknown style} -body { .t style elements testStyle } -returnCodes error -result {style "testStyle" doesn't exist} test style-5.3 {style elements: no element yet} -body { .t style create testStyle .t style elements testStyle } -result {} test style-5.4 {style elements: empty element list} -body { .t style elements testStyle {} } -result {} test style-5.5 {style elements: add some elements} -setup { # Create some items using the style. # FIXME: add test to ensure the item-column styles are updated. .t column create .t item create -count 100 -parent root .t item style set all 0 testStyle } -body { .t style elements testStyle {eBorder eImage eText} .t style elements testStyle } -result {eBorder eImage eText} test style-5.6 {style elements: duplicate elements are ignored} -body { .t style elements testStyle {eBorder eImage eImage eText} .t style elements testStyle } -result {eBorder eImage eText} test style-5.7 {style elements: duplicate elements are ignored} -body { .t style elements testStyle {eBorder eImage eText eImage} .t style elements testStyle } -result {eBorder eImage eText} test style-5.8 {style elements: rearrange elements} -body { .t style elements testStyle {eText eImage eBorder} .t style elements testStyle } -result {eText eImage eBorder} test style-5.9 {style elements: remove elements} -body { .t style elements testStyle {eImage} .t style elements testStyle } -result {eImage} test style-5.10 {style elements: add elements} -body { .t style elements testStyle {eBorder eText eImage} .t style elements testStyle } -result {eBorder eText eImage} test style-6.1 {style layout: missing args} -body { .t style layout } -returnCodes error -result {wrong # args: should be ".t style layout name element ?option? ?value? ?option value ...?"} test style-6.2 {style layout: no options specified} -body { .t style layout testStyle eText } -result {-center {} -detach no -draw {} *} -match glob test style-6.3 {style layout: option -padx} -body { .t style layout testStyle eText -padx 3 .t style layout testStyle eText -padx } -result {3} test style-6.4 {style layout: invalid 2 element -pady} -body { .t style layout testStyle eText -pady {3 ""} } -returnCodes error -result {bad pad amount "3 """: must be a list of 1 or 2 positive screen distances} test style-6.5 {style layout: invalid 2 element -pady} -body { .t style layout testStyle eText -pady "\{" } -returnCodes error -result {unmatched open brace in list} test style-6.6 {style layout: invalid 2 element -pady} -body { .t style layout testStyle eText -pady {3 -7} } -returnCodes error -result {bad pad amount "3 -7": must be a list of 1 or 2 positive screen distances} test style-6.7 {style layout: invalid 2 element -pady} -body { .t style layout testStyle eText -pady {3 7} .t style layout testStyle eText -pady } -result {3 7} test style-6.8 {style layout: option -expand} -body { .t style layout testStyle eText -expand "hello world" } -returnCodes error -result {bad expand value "hello world": must be a string containing zero or more of n, e, s, and w} test style-6.9 {style layout: option -expand} -body { .t style layout testStyle eText -expand ew .t style layout testStyle eText -expand } -result {we} test style-6.10 {style layout: option -squeeze} -body { .t style layout testStyle eText -squeeze xyzzy } -returnCodes error -result {bad squeeze value "xyzzy": must be a string containing zero or more of x and y} test style-6.11 {style layout: option -squeeze} -body { .t style layout testStyle eText -squeeze xy .t style layout testStyle eText -squeeze } -result {xy} test style-6.12 {style layout: option -union invalid list} -body { .t style layout testStyle eText -union "\{" } -returnCodes error -result {unmatched open brace in list} test style-6.13 {style layout: option -union unknown elements} -body { .t style layout testStyle eText -union {foo bar} } -returnCodes error -result {element "foo" doesn't exist} test style-6.14 {style layout: option -union element not in style} -body { .t style layout testStyle eText -union {eBorder eRect} } -returnCodes error -result {style testStyle does not use element eRect} test style-6.15 {style layout: option -union with itself} -body { .t style layout testStyle eText -union {eBorder eText} } -returnCodes error -result {element eText can't form union with itself} test style-6.16 {style layout: option -union} -body { .t style layout testStyle eText -union {eBorder eImage} .t style layout testStyle eText -union } -result {eBorder eImage} test style-6.17 {style layout: option invalid -detach} -body { .t style layout testStyle eText -detach {x y} } -returnCodes error -result {expected boolean value but got "x y"} test style-6.18 {style layout: option -detach} -body { .t style layout testStyle eText -detach true .t style layout testStyle eText -detach } -result {yes} test style-7.1 {layout validation} -setup { destroy .t pack [treectrl .t] .t configure -showheader no -borderwidth 0 -highlightthickness 0 .t element create e1 rect -width 20 -height 25 -fill blue .t element create e2 rect -width 40 -height 45 -fill green .t style create s1 -orient horizontal .t style elements s1 {e1 e2} .t column create -tags C0 .t item style set root C0 s1 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {20 0 60 45}} test style-7.2 {layout validation} -setup { .t colu conf C0 -width 1 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {20 0 60 45}} test style-7.3 {layout validation} -setup { .t style layout s1 e1 -squeeze x } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 0 25} {0 0 40 45}} test style-7.4 {layout validation} -setup { .t style layout s1 e1 -minwidth 10 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 10 25} {10 0 50 45}} test style-7.5 {layout validation} -setup { .t style layout s1 e2 -minwidth 20 -squeeze x } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 10 25} {10 0 30 45}} test style-7.6 {layout validation} -setup { .t column configure C0 -width "" .t style layout s1 e1 -minwidth "" -squeeze "" .t style layout s1 e2 -minwidth "" -squeeze "" .t item configure root -height 1 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {20 0 60 45}} test style-7.7 {layout validation} -setup { .t style layout s1 e1 -squeeze y .t style layout s1 e2 -squeeze "" } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {20 0 60 45}} test style-7.8 {layout validation} -setup { .t style layout s1 e1 -squeeze "" .t style layout s1 e2 -squeeze y } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {20 0 60 25}} test style-7.9 {layout validation} -setup { .t style layout s1 e1 -squeeze y .t style layout s1 e2 -squeeze y } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 1} {20 0 60 1}} test style-7.10 {layout validation} -setup { .t style layout s1 e1 -squeeze "" .t style layout s1 e2 -squeeze "" .t style configure s1 -orient vertical .t item configure root -height "" } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {0 25 40 70}} test style-7.11 {layout validation} -setup { .t column configure C0 -width 1 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {0 25 40 70}} test style-7.12 {layout validation} -setup { .t style layout s1 e2 -squeeze x } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {0 25 20 70}} test style-7.13 {layout validation} -setup { .t style layout s1 e1 -squeeze x } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 1 25} {0 25 1 70}} test style-7.14 {layout validation} -setup { .t style layout s1 e1 -minwidth 10 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 10 25} {0 25 10 70}} test style-7.15 {layout validation} -setup { .t column configure C0 -width "" } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {0 25 40 70}} test style-7.16 {layout validation} -setup { .t style layout s1 e1 -squeeze y .t item configure root -height 1 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 0} {0 0 40 45}} test style-7.17 {layout validation} -setup { .t style layout s1 e1 -minheight 10 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 10} {0 10 40 55}} test style-7.18 {layout validation} -setup { .t style layout s1 e2 -squeeze y } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 10} {0 10 40 10}} test style-7.19 {layout validation} -setup { .t style layout s1 e2 -minheight 10 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 10} {0 10 40 20}} test style-8.1 {layout validation} -setup { destroy .t pack [treectrl .t] .t configure -showheader no -borderwidth 0 -highlightthickness 0 .t element create e1 rect -width 20 -height 25 -fill blue .t element create e2 rect -width 40 -height 45 -fill green .t style create s1 -orient horizontal .t style elements s1 {e1 e2} .t column create -tags C0 .t item style set root C0 s1 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {20 0 60 45}} test style-8.2 {layout validation} -setup { .t column configure C0 -width 200 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {20 0 60 45}} test style-8.3 {layout validation} -setup { .t column configure C0 -justify right } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{140 0 160 25} {160 0 200 45}} test style-8.4 {layout validation} -setup { .t column configure C0 -justify center } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{70 0 90 25} {90 0 130 45}} test style-8.5 {layout validation} -setup { .t column configure C0 -justify left .t style layout s1 e2 -detach yes } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {0 0 40 45}} test style-8.6 {layout validation} -setup { .t column configure C0 -justify center } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{90 0 110 25} {0 0 40 45}} test style-8.7 {layout validation} -setup { .t column configure C0 -justify right } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{180 0 200 25} {0 0 40 45}} test style-8.8 {layout validation} -setup { .t column configure C0 -justify left .t style layout s1 e2 -detach no .t style configure s1 -orient vertical } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {0 25 40 70}} test style-8.9 {layout validation} -setup { .t column configure C0 -justify center } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{80 0 100 25} {80 25 120 70}} test style-8.10 {layout validation} -setup { .t column configure C0 -justify right } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{160 0 180 25} {160 25 200 70}} test style-8.11 {layout validation} -setup { .t column configure C0 -justify left .t style layout s1 e2 -detach yes } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {0 0 40 45}} test style-8.12 {layout validation} -setup { .t column configure C0 -justify center } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{90 0 110 25} {0 0 40 45}} test style-8.13 {layout validation} -setup { .t column configure C0 -justify right } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{180 0 200 25} {0 0 40 45}} test style-9.1 {layout validation} -setup { destroy .t pack [treectrl .t] .t configure -showheader no -borderwidth 0 -highlightthickness 0 .t element create e1 rect -width 20 -height 25 -fill blue .t element create e2 rect -width 40 -height 45 -fill green .t style create s1 -orient horizontal .t style elements s1 {e1 e2} .t column create -tags C0 .t item style set root C0 s1 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{0 0 20 25} {20 0 60 45}} test style-9.2 {layout validation} -setup { .t style layout s1 e1 -padx 5 .t style layout s1 e2 -padx {0 5} } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{5 0 25 25} {30 0 70 45}} test style-9.3 {layout validation} -setup { .t column configure C0 -width 200 -justify center # (200 - 75) / 2 = 62 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{67 0 87 25} {92 0 132 45}} test style-9.4 {layout validation} -setup { .t column configure C0 -justify right } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{130 0 150 25} {155 0 195 45}} test style-9.5 {layout validation} -setup { .t column configure C0 -justify left .t style configure s1 -orient vertical .t style layout s1 e1 -pady 5 .t style layout s1 e2 -padx 5 -pady {0 5} } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{5 5 25 30} {5 35 45 80}} test style-9.6 {layout validation} -setup { .t column configure C0 -justify center # (200 - 50) / 2 = 75 } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{80 5 100 30} {80 35 120 80}} test style-9.7 {layout validation} -setup { .t column configure C0 -justify right } -body { list [.t item bbox root C0 e1] [.t item bbox root C0 e2] } -result {{155 5 175 30} {155 35 195 80}} test style-10.1 {style layout -center: invalid value} -setup { .t style create testStyle -orient horizontal .t element create testElem rect -width 20 -height 20 .t style elements testStyle testElem } -body { .t style layout testStyle testElem -center xyzzy } -returnCodes error -result {bad center value "xyzzy": must be a string containing zero or more of x and y} test style-10.2 {style layout -center: valid value} -body { .t style layout testStyle testElem -center xy .t style layout testStyle testElem -center } -result {xy} test style-10.3 {style layout -center: column width is unspecified, no centering} -setup { .t column configure C0 -width "" .t item style set root C0 testStyle } -body { .t item bbox root C0 testElem } -result {0 0 20 20} test style-10.4 {style layout -center: equal space on both sides} -setup { .t column configure C0 -width 100 } -body { # (100 - 20) / 2 = 40 .t item bbox root C0 testElem } -result {40 0 60 20} test style-10.5 {style layout -center: -expand does nothing} -body { .t style layout testStyle testElem -expand w .t item bbox root C0 testElem } -result {40 0 60 20} test style-10.6 {style layout -center: -expand does nothing} -body { .t style layout testStyle testElem -expand e .t item bbox root C0 testElem } -result {40 0 60 20} test style-10.7 {style layout -center: padding is still respected} -setup { .t column configure C0 -width "" } -body { .t style layout testStyle testElem -padx {15 25} .t item bbox root C0 testElem } -result {15 0 35 20} test style-10.8 {style layout -center: padding is still respected} -setup { # 15 + 20 + 25 = 60 .t column configure C0 -width 60 } -body { .t item bbox root C0 testElem } -result {15 0 35 20} test style-10.9 {style layout -center: padding is still respected} -setup { # 8 more pixels than needed, should result in (68-20)/2=24 on each side # but that would push it too far right, so: 23 + 20 + 25 = 68 .t column configure C0 -width 68 } -body { .t item bbox root C0 testElem } -result {23 0 43 20} test style-10.10 {style layout -center: 2 centered elements} -setup { .t column configure C0 -width 100 .t element create testElem2 rect -width 20 -height 20 .t style elements testStyle {testElem testElem2} .t style layout testStyle testElem2 -center xy -padx 5 } -body { # (100 - (20 + 25 + 5 + 20)) / 2 = (100 - 70) / 2 = 15 list [.t item bbox root C0 testElem] [.t item bbox root C0 testElem2] } -result {{15 0 35 20} {65 0 85 20}} test style-10.11 {style layout -center: 2 centered elements} -body { .t style layout testStyle testElem -padx 5 # (100 - (20 + 5 + 5 + 20)) / 2 = 25 list [.t item bbox root C0 testElem] [.t item bbox root C0 testElem2] } -result {{25 0 45 20} {55 0 75 20}} test style-10.12 {style layout -center: 1 centered, 1 not centered} -setup { .t style layout testStyle testElem2 -center "" } -body { # (100 - 20) / 2 = 40 list [.t item bbox root C0 testElem] [.t item bbox root C0 testElem2] } -result {{40 0 60 20} {70 0 90 20}} test style-10.13 {style layout -center: 1 centered, 1 not centered} -setup { .t style layout testStyle testElem2 -expand w } -body { list [.t item bbox root C0 testElem] [.t item bbox root C0 testElem2] } -result {{40 0 60 20} {75 0 95 20}} test style-99.1 {some needed cleanup} -body { destroy .t } -result {} # cleanup ::tcltest::cleanupTests return tktreectrl-2.4.1/tests/treectrl.test0000644000076400010400000011505211570577330020116 0ustar TimAdministrators# Commands covered: treectrl # # This file contains a collection of tests for the treectrl command of # the tktreectrl extension. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 2000 by Scriptics Corporation. # Copyright (c) 2002 by Christian Krone. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 namespace import ::tcltest::* } package require Tk package require treectrl test treectrl-1.1 {Usage} -body { treectrl } -returnCodes error -result {wrong # args: should be "treectrl pathName ?options?"} test treectrl-1.2 {Unknown option} -body { treectrl .t -foo bar } -returnCodes error -result {unknown option "-foo"} test treectrl-1.3 {Create a tree} -body { # The default borderwidth in Tk 8.4 is "2" while in Tk 8.5 it is "1" # The default highlightthickness is "0" Mac OS X but "1" on other platforms. treectrl .t -borderwidth 1 -highlightthickness 1 } -result {.t} test treectrl-1.4 {configure: List all options} -body { .t configure } -result {{-background background Background white *}*} -match glob test treectrl-1.5 {configure -background with totally empty visible tree} -body { pack .t -expand yes -fill both update .t configure -background white update idletasks } -result {} test treectrl-1.6 {configure: -background option} -body { .t configure -background yellow .t configure -background } -result {-background background Background white yellow} test treectrl-1.7 {configure: invalid -backgroundmode option} -body { .t configure -backgroundmode foo } -returnCodes error -result {bad backgroundmode "foo": must be column, order, ordervisible, row, index, or visindex} test treectrl-1.8 {configure: -backgroundmode option} -body { .t configure -backgroundmode column .t configure -backgroundmode } -result {-backgroundmode backgroundMode BackgroundMode row column} test treectrl-1.9 {configure: invalid -buttonsize option} -body { .t configure -buttonsize foo } -returnCodes error -result {bad screen distance "foo"} test treectrl-1.10 {configure: -buttonsize option} -body { .t configure -buttonsize 1c .t configure -buttonsize } -result {-buttonsize buttonSize ButtonSize 9 1c} test treectrl-1.11 {configure: invalid -buttoncolor option} -body { .t configure -buttoncolor foo } -returnCodes error -result {unknown color name "foo"} test treectrl-1.12 {configure: -buttoncolor option} -body { .t configure -buttoncolor red .t configure -buttoncolor } -result {-buttoncolor buttonColor ButtonColor #808080 red} test treectrl-1.13 {configure: invalid -buttonbitmap option} -body { .t configure -buttonbitmap no-such-bitmap } -returnCodes error -result {bitmap "no-such-bitmap" not defined} test treectrl-1.14 {configure: -buttonbitmap option} -body { .t configure -buttonbitmap hourglass .t configure -buttonbitmap } -result {-buttonbitmap buttonBitmap ButtonBitmap {} hourglass} test treectrl-1.17 {configure: invalid -buttonimage option} -body { .t configure -buttonimage foo } -returnCodes error -result {image "foo" doesn't exist} test treectrl-1.18 {configure: -buttonimage option} -body { image create photo emptyImg .t configure -buttonimage emptyImg .t configure -buttonimage } -result {-buttonimage buttonImage ButtonImage {} emptyImg} test treectrl-1.21 {configure: invalid -doublebuffer option} -body { .t configure -doublebuffer foo } -returnCodes error -result {bad doublebuffer "foo": must be none, item, or window} test treectrl-1.22 {configure: -doublebuffer option} -body { .t configure -doublebuffer window .t configure -doublebuffer } -result {-doublebuffer doubleBuffer DoubleBuffer item window} test treectrl-1.23 {configure: invalid -indent option} -body { .t configure -indent foo } -returnCodes error -result {bad screen distance "foo"} test treectrl-1.24 {configure: -indent option} -body { .t configure -indent 2c .t configure -indent } -result {-indent indent Indent 19 2c} test treectrl-1.25 {configure: invalid -itemheight option} -body { .t configure -itemheight foo } -returnCodes error -result {bad screen distance "foo"} test treectrl-1.26 {configure: -itemheight option} -body { .t configure -itemheight 18m .t configure -itemheight } -result {-itemheight itemHeight ItemHeight 0 18m} test treectrl-1.27 {configure: invalid -linestyle option} -body { .t configure -linestyle foo } -returnCodes error -result {bad linestyle "foo": must be dot or solid} test treectrl-1.28 {configure: -linestyle option} -body { .t configure -linestyle solid .t configure -linestyle } -result {-linestyle lineStyle LineStyle dot solid} test treectrl-1.29 {configure: invalid -linethickness option} -body { .t configure -linethickness foo } -returnCodes error -result {bad screen distance "foo"} test treectrl-1.30 {configure: -linethickness option} -body { .t configure -linethickness 3m .t configure -linethickness } -result {-linethickness lineThickness LineThickness 1 3m} test treectrl-1.31 {configure: invalid -linecolor option} -body { .t configure -linecolor #foo } -returnCodes error -result {invalid color name "#foo"} test treectrl-1.32 {configure: -linethickness option} -body { .t configure -linecolor gray20 .t configure -linecolor } -result {-linecolor lineColor LineColor #808080 gray20} test treectrl-1.33 {configure: invalid -orient option} -body { .t configure -orient foo } -returnCodes error -result {bad orient "foo": must be horizontal or vertical} test treectrl-1.34 {configure: -orient option} -body { .t configure -orient h .t configure -orient } -result {-orient orient Orient vertical horizontal} test treectrl-1.35 {configure: invalid -relief option} -body { .t configure -relief foo } -returnCodes error -result {bad relief "foo": must be flat, groove, raised, ridge, solid, or sunken} test treectrl-1.36 {configure: -relief option} -body { .t configure -relief flat .t configure -relief } -result {-relief relief Relief sunken flat} test treectrl-1.37 {configure: invalid -showbuttons option} -body { .t configure -showbuttons foo } -returnCodes error -result {expected boolean value but got "foo"} test treectrl-1.38 {configure: -showbuttons option} -body { .t configure -showbuttons off .t configure -showbuttons } -result {-showbuttons showButtons ShowButtons 1 0} test treectrl-1.39 {configure: invalid -showheader option} -body { .t configure -showheader foo } -returnCodes error -result {expected boolean value but got "foo"} test treectrl-1.40 {configure: -showheader option} -body { .t configure -showheader off .t configure -showheader } -result {-showheader showHeader ShowHeader 1 0} test treectrl-1.41 {configure: invalid -showlines option} -body { .t configure -showlines foo } -returnCodes error -result {expected boolean value but got "foo"} test treectrl-1.42 {configure: -showlines option} -body { .t configure -showlines false .t configure -showlines } -result {-showlines showLines ShowLines * 0} -match glob test treectrl-1.43 {configure: invalid -showroot option} -body { .t configure -showroot foo } -returnCodes error -result {expected boolean value but got "foo"} test treectrl-1.44 {configure: -showroot option} -body { .t configure -showroot no .t configure -showroot } -result {-showroot showRoot ShowRoot 1 0} test treectrl-1.45 {configure: invalid -showrootbutton option} -body { .t configure -showrootbutton foo } -returnCodes error -result {expected boolean value but got "foo"} test treectrl-1.46 {configure: -showrootbutton option} -body { .t configure -showrootbutton True .t configure -showrootbutton } -result {-showrootbutton showRootButton ShowRootButton 0 1} test treectrl-1.47 {configure: invalid -treecolumn option} -body { .t configure -treecolumn foo } -returnCodes error -result {column "foo" doesn't exist} test treectrl-1.49 {configure: -treecolumn option with known column} -body { .t column create -tag column0 .t column create -tag column2 .t configure -treecolumn 1 .t configure -treecolumn } -result {-treecolumn treeColumn TreeColumn {} 1} test treectrl-1.50 {configure: invalid -wrap mode} -body { .t configure -wrap foo } -returnCodes error -result {bad wrap "foo"} test treectrl-1.51 {configure: invalid -wrap option: bogus width} -body { .t configure -wrap {item bar} } -returnCodes error -result {bad wrap "item bar"} test treectrl-1.52 {configure: invalid -wrap option: superflous width} -body { .t configure -wrap {1 window} } -returnCodes error -result {bad wrap "1 window"} test treectrl-1.53 {configure: -wrap option} -body { .t configure -wrap {7 items} .t configure -wrap } -result {-wrap wrap Wrap {} {7 items}} test treectrl-1.54 {configure: -wrap empty option} -body { .t configure -wrap {} .t configure -wrap } -result {-wrap wrap Wrap {} {}} # Before continuing to test the item descriptions and their modifiers, # lets create some items with this hierarchy: # 0 # + 1 # | + 2 # | + 3 # | + 4 # + 5 # | + 6 # | + 7 # + 8 test treectrl-2.16 {create some items} -body { .t configure -showroot 1 -orient vertical set n1 [.t item create]; .t item lastchild 0 $n1 set n2 [.t item create]; .t item lastchild $n1 $n2 set n3 [.t item create]; .t item lastchild $n1 $n3 set n4 [.t item create]; .t item lastchild $n3 $n4 set n5 [.t item create]; .t item lastchild 0 $n5 set n6 [.t item create]; .t item lastchild $n5 $n6 set n7 [.t item create]; .t item lastchild $n5 $n7 set n8 [.t item create]; .t item lastchild 0 $n8 } -result {8} test treectrl-5.1 {state: missing args} -body { .t state } -returnCodes error -result {wrong # args: should be ".t state command ?arg arg ...?"} test treectrl-5.2 {state: invalid command} -body { .t state foo } -returnCodes error -result {bad command "foo": must be *} -match glob test treectrl-5.3 {state names: too many args} -body { .t state names foo bar } -returnCodes error -result {wrong # args: should be ".t state names"} test treectrl-5.4 {state names: no states defined yet} -body { .t state names } -result {} test treectrl-5.5 {state define: missing args} -body { .t state define } -returnCodes error -result {wrong # args: should be ".t state define stateName"} test treectrl-5.6 {state define: overflow check} -body { set msg "" set ret 0 for {set ix 0} {$ix < 1000} {incr ix} { set ret [catch {.t state define state$ix} msg] if {$ret} {break} } list $ret $ix $msg } -result {1 27 {cannot define any more states}} test treectrl-5.7 {state names} -body { .t state names } -result {state0 state1 state2 state3 state4 state5 state6 state7 state8 state9 state10 state11 state12 state13 state14 state15 state16 state17 state18 state19 state20 state21 state22 state23 state24 state25 state26} test treectrl-5.8 {state undefine: missing args is ok} -body { .t state undefine } -result {} test treectrl-5.9 {state undefine: too many args} -body { eval {.t state undefine} [lrange [.t state names] 3 end] .t state names } -result {state0 state1 state2} test treectrl-5.10 {state undefine} -body { foreach state [lrange [.t state names] 1 end] { .t state undefine $state } .t state names } -result {state0} test treectrl-5.11 {state linkage: missing args} -body { .t state linkage } -returnCodes error -result {wrong # args: should be ".t state linkage state"} test treectrl-5.12 {state linkage: unknown state} -body { .t state linkage foo } -returnCodes error -result {unknown state "foo"} test treectrl-5.13 {state linkage: predefined state} -body { .t state linkage open } -result {static} test treectrl-5.14 {state linkage: user defined state} -body { .t state linkage state0 } -result {dynamic} test treectrl-5.15 {state define: strange state name} -body { .t state define ~user } -returnCodes error -result {invalid state name "~user"} test treectrl-5.17 {state define: strange state name} -body { .t state linkage ~user } -returnCodes error -result {can't specify '~' for this command} test treectrl-5.18 {state undefine: strange state name} -body { .t state undefine ~user } -returnCodes error -result {can't specify '~' for this command} test treectrl-5.19 {state define: strange state name} -body { .t state define !WatchIt! } -returnCodes error -result {invalid state name "!WatchIt!"} test treectrl-5.20 {state define: strange state name} -body { .t state define "" } -returnCodes error -result {invalid state name ""} test treectrl-7.0 {some prerequisites for the marquee test} -body { .t element create eImage image -width 202 -height 18m .t element create eRect rect -width 10c -height 18m .t style create testStyle2 .t style elements testStyle2 {eImage eRect} .t item style set 2 .t item style set 8 0 testStyle2 update idletasks } -result {} test treectrl-7.1 {marquee: missing args} -body { .t marquee } -returnCodes error -result {wrong # args: should be ".t marquee command ?arg arg ...?"} test treectrl-7.2 {marquee: unknown command} -body { .t marquee foo } -returnCodes error -result {bad command "foo": must be *} -match glob test treectrl-7.3 {marquee anchor: not yet modified} -body { .t marquee anchor } -result {0 0} test treectrl-7.4 {marquee anchor: odd arguments} -body { .t marquee anchor 1 } -returnCodes error -result {wrong # args: should be ".t marquee anchor ?x y?"} test treectrl-7.5 {marquee identify: should be empty} -body { .t marquee identify } -result {} test treectrl-7.6 {marquee anchor: set it} -body { .t marquee anchor 5 5 } -result {} test treectrl-7.7 {marquee coords: retrieve them} -body { .t marquee coords } -result {5 5 0 0} test treectrl-7.8 {marquee identify: just the root} -body { .t marquee identify } -result {{0 0}} test treectrl-7.9 {marquee corner: set it} -body { .t marquee corner 600 600 .t marquee coords } -result {5 5 600 600} test treectrl-7.10 {marquee identify} -body { .t marquee identify } -result {{0 0} {1 0} {2 0} {3 0} {4 0} {5 0} {6 0} {7 0} {8 {0 eRect eImage}}} test treectrl-7.11 {marquee identify: after invalid item style map} -body { catch {.t item style map 1 0 noStyle {foo bar}} .t marquee identify } -result {{0 0} {1 0} {2 0} {3 0} {4 0} {5 0} {6 0} {7 0} {8 {0 eRect eImage}}} test treectrl-7.12 {marquee visible} -body { list [.t marquee configure -visible] \ [.t marquee cget -visible] \ [.t marquee configure -visible 1] \ [.t marquee cget -visible] } -result {{-visible {} {} 0 0} 0 {} 1} test treectrl-8.1 {selection: missing args} -body { .t selection } -returnCodes error -result {wrong # args: should be ".t selection command ?arg arg ...?"} test treectrl-8.2 {selection: unknown command} -body { .t selection foo } -returnCodes error -result {bad command "foo": must be *} -match glob test treectrl-8.3 {selection count/get: nothing selected yet} -body { list [.t selection count] [.t selection get] } -result {0 {}} test treectrl-8.4 {selection anchor: always defined} -body { .t selection anchor } -result {0} test treectrl-8.5 {selection anchor: modifies the anchor item} -body { .t selection anchor "root lastchild" .t item id anchor } -result {8} test treectrl-8.6 {selection count/get: still nothing selected} -body { list [.t selection count] [.t selection get] } -result {0 {}} test treectrl-8.7 {selection add: all children of an item} -body { .t selection add "1 firstchild" "1 lastchild" list [.t selection count] [lsort -integer [.t selection get]] } -result {2 {2 3}} test treectrl-8.8 {selection add: all items and then some} -body { .t selection add all "1 lastchild" list [.t selection count] [lsort -integer [.t selection get]] } -result {9 {0 1 2 3 4 5 6 7 8}} test treectrl-8.9 {selection clear} -body { .t selection add all .t selection clear "root firstchild" list [.t selection count] [lsort -integer [.t selection get]] } -result {8 {0 2 3 4 5 6 7 8}} test treectrl-8.10 {selection clear: some items and then all} -body { .t selection clear "root lastchild" all list [.t selection count] [.t selection get] } -result {0 {}} test treectrl-8.11 {selection modify: to be or not to be?} -body { .t selection modify all all list [.t selection count] [lsort -integer [.t selection get]] } -result {9 {0 1 2 3 4 5 6 7 8}} test treectrl-8.12 {selection clear: totally empty} -body { .t selection clear list [.t selection count] [lsort -integer [.t selection get]] } -result {0 {}} test treectrl-8.12 {selection modify: to be or not to be?} -body { .t selection modify {{root firstchild} {root lastchild}} {{root lastchild}} list [.t selection count] [lsort -integer [.t selection get]] } -result {2 {1 8}} test treectrl-8.13 {selection includes: missing args} -body { .t selection includes } -returnCodes error -result {wrong # args: should be ".t selection includes item"} test treectrl-8.14 {selection includes: invalid item} -body { .t selection includes {foo bar} } -returnCodes error -result {item "foo bar" doesn't exist} test treectrl-8.15 {selection includes: item is selected} -body { .t selection includes {root child 2} } -result {1} test treectrl-8.16 {selection includes: item is not selected} -body { .t selection includes {root child 0 firstchild} } -result {0} test treectrl-9.1 {see: missing args} -body { .t see } -returnCodes error -result {wrong # args: should be ".t see item ?column? ?option value ...?"} test treectrl-9.2 {see: bogus option} -body { .t see first -bar } -returnCodes error -result {bad option "-bar": must be -center} test treectrl-9.3 {see: invalid item} -body { .t see foo } -returnCodes error -result {item "foo" doesn't exist} test treectrl-9.4 {see: bottom most item} -body { .t see "root bottom" } -result {} test treectrl-9.5 {see: last item, bad column} -body { .t see last foo } -returnCodes error -result {column "foo" doesn't exist} test treectrl-9.6 {see: missing option value} -body { .t see first -center } -returnCodes error -result {missing value for "-center" option} test treectrl-9.7 {see: bogus option value} -body { .t see first -center xz } -returnCodes error -result {bad -center value "xz": *} -match glob test treectrl-9.8 {see: -center xy} -body { .t see first -center xy } -result {} test treectrl-10.1 {range: missing args} -body { .t item range } -returnCodes error -result {wrong # args: should be ".t item range first last"} test treectrl-10.2 {range: too many args} -body { .t item range foo bar baz } -returnCodes error -result {wrong # args: should be ".t item range first last"} test treectrl-10.3 {range: select all from top to bottom} -body { .t item range "root top" "root bottom" } -result {0 1 2 3 4 5 6 7 8} test treectrl-10.4 {range: select all from bottom to top} -body { .t item range "root bottom" "root top" } -result {0 1 2 3 4 5 6 7 8} test treectrl-11.1 {orphans: too many args} -body { .t orphans foo } -returnCodes error -result {wrong # args: should be ".t orphans"} test treectrl-11.2 {orphans: lets make one} -body { .t item remove 8 .t orphans } -result {8} test treectrl-11.3 {orphans: no orphans} -body { .t item lastchild 0 8 .t orphans } -result {} test treectrl-12.1 {contentbox: too many args} -body { .t contentbox foo } -returnCodes error -result {wrong # args: should be ".t contentbox"} test treectrl-12.2 {contentbox} -body { .t contentbox } -result {2 2 202 202} test treectrl-12.3 {contentbox: simple double check with borders} -body { expr {[lindex [.t contentbox] 0] \ == ([.t cget -bd]+[.t cget -highlightthickness])} } -result {1} test treectrl-12.4 {element delete while item is still displayed} -body { .t element create elText text -text hallo .t style create stText .t style element stText elText set new [.t item create] .t item style set $new 0 stText .t item lastchild 0 $new .t element delete elText place [frame .obscure] -in .t -relwidth 1.0 -relheight 1.0 update destroy .obscure update } -result {} test treectrl-13.1 {depth: too many args} -body { .t depth foo bar } -returnCodes error -result {wrong # args: should be ".t depth ?item?"} test treectrl-13.2 {depth of the root item} -body { .t depth root } -result {0} test treectrl-13.3 {depth of a deeper item} -body { .t depth "root firstchild lastchild" } -result {2} test treectrl-13.4 {depth of the tree} -body { .t depth } -result {3} test treectrl-13.5 {depth of the tree} -body { .t depth } -setup { set rootKids [.t item children root] foreach i $rootKids {.t item remove $i} } -cleanup { foreach i $rootKids {.t item lastchild root $i} } -result {0} test treectrl-14.1 {rename and change some columns} -body { .t column delete column0 .t column create -tag column1 .t column create -tag column3 .t column move "order 0" "order 2" .t column move "order 0" tail .t element create eRect2 rect -fill blue -height 20 -width 150 .t style create testStyle3 .t style elements testStyle3 eRect2 .t item style set 1 column1 testStyle3 } -result {} test treectrl-15.1 {identify: missing args} -body { wm geometry . 400x200 ; update .t identify } -returnCodes error -result {wrong # args: should be ".t identify ?switches? x y"} test treectrl-15.2 {identify: negative coords} -body { .t configure -showheader 1 -showlines 1 -showbuttons 1 \ -borderwidth 2 -highlightthickness 1 -treecolumn 2 \ -itemheight 0 -linethickness 1 -indent 40 .t item configure 1 -button true update idletasks .t identify -5 -5 } -result {} test treectrl-15.3 {identify: header left} -body { # column 0 has width 0 # column 1 has width 0 # column 2 has width 40 + 40 + 150 = 230 # borders are 2 + 1 = 3 .t identify 3 4 } -result {header 2 left} test treectrl-15.4 {identify: header} -body { .t identify 40 4 } -result {header 2} test treectrl-15.5 {identify: header right} -body { .t identify 232 4 } -result {header 2 right} test treectrl-15.6 {identify: tail left} -body { .t identify 233 4 } -result {header tail left} test treectrl-15.7 {identify: tail} -body { .t identify 250 4 } -result {header tail} test treectrl-15.8 {identify: item (to the left)} -body { scan [.t bbox header] "%d %d %d %d" left top right bottom .t identify 4 $bottom } -result {item 1} test treectrl-15.9 {identify: button} -body { scan [.t bbox header] "%d %d %d %d" left top right bottom .t identify 60 $bottom } -result {item 1 button} test treectrl-15.10 {identify: over element} -body { scan [.t bbox header] "%d %d %d %d" left top right bottom .t identify 150 $bottom } -result {item 1 column 2 elem eRect2} test treectrl-15.11 {identify: item (to the right)} -body { # first make column wider, otherwise we can't get right of the item .t column configure column1 -width 250 update idletasks scan [.t bbox header] "%d %d %d %d" left top right bottom .t identify 233 $bottom } -result {item 1 column 2} test treectrl-15.12 {identify: negative coords} -body { .t column configure column1 -width "" .t identify -array id -5 -5 parray id } -output {id(where) = } -cleanup {array unset id} test treectrl-15.13 {identify: header left} -body { # column 0 has width 0 # column 1 has width 0 # column 2 has width 40 + 40 + 150 = 230 # borders are 2 + 1 = 3 .t identify -array id 3 4 parray id } -output {id(column) = 2 id(element) = id(header) = 0 id(side) = left id(where) = header } -cleanup {array unset id} test treectrl-15.14 {identify: header} -body { .t identify -array id 40 4 parray id } -output {id(column) = 2 id(element) = id(header) = 0 id(side) = id(where) = header } -cleanup {array unset id} test treectrl-15.15 {identify: header right} -body { .t identify -array id 232 4 parray id } -output {id(column) = 2 id(element) = id(header) = 0 id(side) = right id(where) = header } -cleanup {array unset id} test treectrl-15.16 {identify: tail left} -body { .t identify -array id 233 4 parray id } -output {id(column) = tail id(element) = id(header) = 0 id(side) = left id(where) = header } -cleanup {array unset id} test treectrl-15.17 {identify: tail} -body { .t identify -array id 250 4 parray id } -output {id(column) = tail id(element) = id(header) = 0 id(side) = id(where) = header } -cleanup {array unset id} test treectrl-15.18 {identify: item (to the left)} -body { scan [.t bbox header] "%d %d %d %d" left top right bottom .t identify -array id 4 $bottom parray id } -output {id(button) = no id(column) = 2 id(element) = id(item) = 1 id(line) = id(where) = item } -cleanup {array unset id} test treectrl-15.19 {identify: button} -body { scan [.t bbox header] "%d %d %d %d" left top right bottom .t identify -array id 60 $bottom parray id } -output {id(button) = yes id(column) = 2 id(element) = id(item) = 1 id(line) = id(where) = item } -cleanup {array unset id} test treectrl-15.20 {identify: over element} -body { scan [.t bbox header] "%d %d %d %d" left top right bottom .t identify -array id 150 $bottom parray id } -output {id(button) = no id(column) = 2 id(element) = eRect2 id(item) = 1 id(line) = id(where) = item } -cleanup {array unset id} test treectrl-15.21 {identify: item (to the right)} -body { # first make column wider, otherwise we can't get right of the item .t column configure column1 -width 250 update idletasks scan [.t bbox header] "%d %d %d %d" left top right bottom .t identify -array id 233 $bottom parray id } -output {id(button) = no id(column) = 2 id(element) = id(item) = 1 id(line) = id(where) = item } -cleanup {array unset id} test treectrl-16.1 {dragimage: missing args} -body { .t dragimage } -returnCodes error -result {wrong # args: should be ".t dragimage command ?arg arg ...?"} test treectrl-16.2 {dragimage: unknown command} -body { .t dragimage foo } -returnCodes error -result {bad command "foo": must be *} -match glob test treectrl-16.3 {dragimage configure} -body { .t dragimage configure } -result {{-visible {} {} 0 0}} test treectrl-16.4 {dragimage configure -visible} -body { .t dragimage configure -visible } -result {-visible {} {} 0 0} test treectrl-16.5 {dragimage cget -visible} -body { .t dragimage cget -visible } -result {0} test treectrl-16.6 {dragimage offset: without preceding add} -body { .t dragimage offset } -result {0 0} test treectrl-16.7 {dragimage add: invalid item} -body { .t dragimage add foo } -returnCodes error -result {item "foo" doesn't exist} test treectrl-16.8 {dragimage add: invalid column} -body { .t dragimage add 1 foo } -returnCodes error -result {column "foo" doesn't exist} test treectrl-16.9 {dragimage add: invalid element} -body { .t dragimage add 1 2 foo } -returnCodes error -result {element "foo" doesn't exist} test treectrl-16.10 {dragimage add: is still not visible} -body { .t dragimage add 1 2 .t dragimage cget -visible } -result {0} test treectrl-16.11 {dragimage visible} -body { .t dragimage configure -visible 1 .t dragimage cget -visible } -result {1} test treectrl-16.12 {dragimage offset} -body { .t dragimage offset 10 10 .t dragimage offset } -result {10 10} test treectrl-16.13 {dragimage clear: too many args} -body { .t dragimage clear 1 } -returnCodes error -result {wrong # args: should be ".t dragimage clear"} test treectrl-16.14 {dragimage clear: doesn't modify the offset} -body { .t dragimage clear .t dragimage offset } -result {10 10} test treectrl-17.1 {columnproxy: Normally left blank} -body { # BTW: This shouldn't be an option... .t cget -columnproxy } -result {} test treectrl-17.2 {columnproxy: Normally left blank} -body { .t configure -columnproxy foo } -returnCodes error -result {bad screen distance "foo"} test treectrl-17.3 {columnproxy: Negative screen distance} -body { # It is unclear if this should be forbiden... .t configure -columnproxy -1c update idletasks .t cget -columnproxy } -result {-1c} test treectrl-17.4 {columnproxy: screen distance bigger than width} -body { # It is unclear if this should be forbiden... set x [expr {[winfo width .t] + 10}] .t configure -columnproxy $x update idletasks expr {[.t cget -columnproxy] == $x} } -result {1} test treectrl-17.5 {columnproxy} -body { .t configure -columnproxy 100 update idletasks .t cget -columnproxy } -result {100} test treectrl-18.1 {-defaultstyle: setup} -body { .t column delete all .t column create -tags a .t column create -tags b .t column create -tags c .t column create -tags d .t item delete all .t style create a .t style create b .t style create c .t style create d } -result {d} test treectrl-18.2 {-defaultstyle: set} -constraints { deprecated } -body { .t configure -defaultstyle {a b c d} .t cget -defaultstyle } -result {a b c d} test treectrl-18.3 {-defaultstyle: new items get default styles} -constraints { deprecated } -body { set I [.t item create] .t item style set $I } -result {a b c d} test treectrl-18.4 {-defaultstyle: moving column updates -defaultstyle} -constraints { deprecated } -body { .t column move "tag a" "tag c" .t cget -defaultstyle } -result {b a c d} test treectrl-18.5 {-defaultstyle: moving column updates -defaultstyle} -constraints { deprecated } -body { .t column move "tag a" tail .t cget -defaultstyle } -result {b c d a} test treectrl-18.6 {-defaultstyle: moving column updates -defaultstyle} -constraints { deprecated } -body { .t column move "tag a" "tag b" .t cget -defaultstyle } -result {a b c d} test treectrl-18.7 {-defaultstyle: moving column updates -defaultstyle} -constraints { deprecated } -body { .t column create -tags e .t column move "tag e" "tag d" .t cget -defaultstyle } -result {a b c {} d} test treectrl-18.8 {-defaultstyle: moving column updates -defaultstyle} -constraints { deprecated } -body { .t column create -tags f .t column move "tag c" tail .t cget -defaultstyle } -result {a b {} d {} c} test treectrl-18.9 {-defaultstyle: deleting column does not update -defaultstyle} -constraints { deprecated } -body { .t column delete "tag e" .t cget -defaultstyle } -result {a b {} d {} c} test treectrl-19.1 {gradient: missing args} -body { .t gradient } -returnCodes error -result {wrong # args: should be ".t gradient command ?arg arg ...?"} test treectrl-19.3 {gradient: unknown command} -body { .t gradient foo } -returnCodes error -result {bad command "foo": must be *} -match glob test treectrl-19.9 {gradient create: missing args} -body { .t gradient create } -returnCodes error -result {wrong # args: should be ".t gradient create name ?option value ...?"} test treectrl-19.10 {gradient create: empty gradient name} -body { .t gradient create "" } -returnCodes error -result {invalid gradient name ""} test treectrl-19.11 {gradient create: valid name} -body { .t gradient create G1 } -result {G1} test treectrl-19.12 {gradient create: duplicate name} -body { .t gradient create G1 } -returnCodes error -result {gradient "G1" already exists} test treectrl-19.13 {gradient create: missing argument option} -body { .t gradient create G2 -stops } -returnCodes error -result {value for "-stops" missing} test treectrl-19.14 {gradient create: unknown option} -body { .t gradient create G2 -foo } -returnCodes error -result {unknown option "-foo"} test treectrl-19.15 {gradient configure: missing args} -body { .t gradient configure } -returnCodes error -result {wrong # args: should be ".t gradient configure name ?option? ?value option value ...?"} test treectrl-19.16 {gradient configure: unknown gradient} -body { .t gradient configure foo } -returnCodes error -result {gradient "foo" doesn't exist} test treectrl-19.17 {gradient configure -steps: default} -body { .t gradient configure G1 -steps } -result {-steps {} {} 1 1} test treectrl-19.18 {gradient configure -steps: invalid} -body { .t gradient configure G1 -steps foo } -returnCodes error -result {expected integer but got "foo"} test treectrl-19.19 {gradient configure -steps: out of bounds} -body { .t gradient configure G1 -steps 0 } -returnCodes error -result {steps must be >= 1 and <= 25} test treectrl-19.20 {gradient configure -steps: out of bounds} -body { .t gradient configure G1 -steps 100 } -returnCodes error -result {steps must be >= 1 and <= 25} test treectrl-19.21 {gradient configure -steps: valid, lower limit} -body { .t gradient configure G1 -steps 1 } -result {} test treectrl-19.22 {gradient configure -steps: valid, upper limit} -body { .t gradient configure G1 -steps 25 } -result {} test treectrl-19.23 {gradient configure -stops: invalid} -body { .t gradient configure G1 -stops foo } -returnCodes error -result {at least 2 stops required, 1 given} test treectrl-19.24 {gradient configure -stops: invalid} -body { .t gradient configure G1 -stops {foo bar} } -returnCodes error -result {stop list not {offset color ?opacity?}} test treectrl-19.25 {gradient configure -stops: 0.0 must be first} -body { .t gradient configure G1 -stops {{1.0 foo} {2.0 bar}} } -returnCodes error -result {first stop offset must be 0.0, got 1} test treectrl-19.26 {gradient configure -stops: unknown color} -body { .t gradient configure G1 -stops {{0.0 foo} {2.0 bar}} } -returnCodes error -result {unknown color name "foo"} test treectrl-19.27 {gradient configure -stops: 1.0 must be last} -body { .t gradient configure G1 -stops {{0.0 blue} {0.5 bar}} } -returnCodes error -result {last stop offset must be 1.0, got 0.5} test treectrl-19.28 {gradient configure -stops: must be ordered} -body { .t gradient configure G1 -stops {{0.0 red} {0.5 green} {0.4 yellow} {1.0 blue}} } -returnCodes error -result {stop offsets must be ordered} test treectrl-20.1 {gradient coords: default} -body { .t gradient configure G1 -left } -result {-left {} {} {} {}} test treectrl-20.2 {gradient coords: invalid} -body { .t gradient configure G1 -left foo } -returnCodes error -result {expected list {offset coordType ?arg ...?}} test treectrl-20.3 {gradient coords: invalid} -body { .t gradient configure G1 -left {a b} } -returnCodes error -result {bad coordinate type "b": must be *} -match glob test treectrl-20.4 {gradient coords: invalid} -body { .t gradient configure G1 -left {a item} } -returnCodes error -result {expected floating-point number but got "a"} test treectrl-20.5 {gradient coords, area: missing arg} -body { .t gradient configure G1 -left {0.5 area} } -returnCodes error -result {wrong # args after "area": must be 1} test treectrl-20.6 {gradient coords, area: too many args} -body { .t gradient configure G1 -left {0.5 area a b} } -returnCodes error -result {wrong # args after "area": must be 1} test treectrl-20.7 {gradient coords, area: unknown area} -body { .t gradient configure G1 -left {0.5 area foo} } -returnCodes error -result {bad area "foo": must be *} -match glob test treectrl-20.8 {gradient coords, area: valid} -body { .t gradient configure G1 -left {0.5 area content} } -result {} test treectrl-20.9 {gradient coords, column: too many args} -body { .t gradient configure G1 -left {0.5 column a b} } -returnCodes error -result {wrong # args after "column": must be 0 or 1} test treectrl-20.10 {gradient coords, column: invalid column} -body { .t gradient configure G1 -left {0.5 column foo} } -returnCodes error -result {column "foo" doesn't exist} test treectrl-20.11 {gradient coords, column: valid w/o column} -body { .t gradient configure G1 -left {0.5 column} } -result {} test treectrl-20.12 {gradient coords, column: valid w/ column} -body { .t gradient configure G1 -left {0.5 column first} } -result {} test treectrl-20.13 {gradient coords, column: delete a column} -setup { .t column create -tags C1 .t gradient configure G1 -left {0.5 column C1} } -body { .t column delete C1 .t gradient cget G1 -left } -result {} test treectrl-20.20 {gradient coords, item: too many args} -body { .t gradient configure G1 -left {0.5 item a b} } -returnCodes error -result {wrong # args after "item": must be 0 or 1} test treectrl-20.21 {gradient coords, item: invalid item} -body { .t gradient configure G1 -left {0.5 item foo} } -returnCodes error -result {item "foo" doesn't exist} test treectrl-20.22 {gradient coords, item: valid w/o item} -body { .t gradient configure G1 -left {0.5 item} } -result {} test treectrl-20.23 {gradient coords, item: valid w/ item} -body { .t gradient configure G1 -left {0.5 item first} } -result {} test treectrl-20.24 {gradient coords, item: delete an item} -setup { .t item create -tags I1 .t gradient configure G1 -left {0.5 item I1} } -body { .t item delete I1 .t gradient cget G1 -left } -result {} test treectrl-21.1 {gradient delete: no args} -body { .t gradient delete } -result {} test treectrl-21.2 {gradient delete: unknown gradient} -body { .t gradient delete foo } -returnCodes error -result {gradient "foo" doesn't exist} test treectrl-21.3 {gradient delete: success} -body { set result [.t gradient names] .t gradient delete G1 lappend result [.t gradient names] } -result {G1 {}} test treectrl-21.4 {gradient delete: in use} -setup { .t gradient create G1 .t column create -tags C1 -itembackground G1 } -body { set result [.t gradient names] .t gradient delete G1 lappend result [.t gradient names] lappend result [.t column cget C1 -itembackground] } -result {G1 {} G1} test treectrl-21.5 {gradient delete: deleted gradient recreated} -body { .t gradient create G1 .t gradient names } -result {G1} test treectrl-21.6 {gradient delete: deleted gradient no longer referenced} -setup { .t gradient delete G1 .t column configure C1 -itembackground {} } -body { # now the gradient is freed } -result {} test treectrl-22.1 {gradient native: no args} -body { string is boolean -strict [.t gradient native] } -result {1} test treectrl-22.2 {gradient native: too many args} -body { .t gradient native foo bar } -returnCodes error -result {wrong # args: should be ".t gradient native ?preference?"} test treectrl-22.3 {gradient native: result doesn't change} -body { set r1 [.t gradient native] .t gradient native [expr {!$r1}] set r2 [.t gradient native] expr {$r1 eq $r2} } -result {1} test treectrl-99.1 {some needed cleanup} -body { destroy .t } -result {} # cleanup image delete emptyImg ::tcltest::cleanupTests return tktreectrl-2.4.1/treectrl.dll.manifest.in0000644000076400010400000000060610753133103020744 0ustar TimAdministrators tktreectrl-2.4.1/treectrl.rc0000644000076400010400000000045210753154727016401 0ustar TimAdministrators// // This enables themed headers in XP by trying to use comctl32 v6. // #ifndef RT_MANIFEST #define RT_MANIFEST 24 #endif #ifndef ISOLATIONAWARE_MANIFEST_RESOURCE_ID #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2 #endif ISOLATIONAWARE_MANIFEST_RESOURCE_ID RT_MANIFEST "treectrl.dll.manifest" tktreectrl-2.4.1/unix/0000755000076400010400000000000011646706171015207 5ustar TimAdministratorstktreectrl-2.4.1/unix/tkUnixTree.c0000644000076400010400000024045511565554065017472 0ustar TimAdministrators/* * tkUnixTree.c -- * * Platform-specific parts of TkTreeCtrl for X11. * * Copyright (c) 2011 Tim Baker */ #include "tkTreeCtrl.h" /* *---------------------------------------------------------------------- * * Tree_HDotLine -- * * Draws a horizontal 1-pixel-tall dotted line. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_HDotLine( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ int x1, int y1, int x2 /* Left, top and right coordinates. */ ) { int wx = x1 + tree->drawableXOrigin; int wy = y1 + tree->drawableYOrigin; int nw = !(wx & 1) == !(wy & 1); XDrawLine(tree->display, drawable, tree->lineGC[!nw], x1, y1, x2, y1); } /* *---------------------------------------------------------------------- * * Tree_VDotLine -- * * Draws a vertical 1-pixel-wide dotted line. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_VDotLine( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ int x1, int y1, int y2) /* Left, top, and bottom coordinates. */ { int wx = x1 + tree->drawableXOrigin; int wy = y1 + tree->drawableYOrigin; int nw = !(wx & 1) == !(wy & 1); XDrawLine(tree->display, drawable, tree->lineGC[!nw], x1, y1, x1, y2); } /* *---------------------------------------------------------------------- * * Tree_DrawActiveOutline -- * * Draws 0 or more sides of a rectangle, dot-on dot-off, XOR style. * This is used by rectangle Elements to indicate the "active" * item. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_DrawActiveOutline( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ int x, int y, /* Left and top coordinates. */ int width, int height, /* Size of rectangle. */ int open /* RECT_OPEN_x flags */ ) { int wx = x + tree->drawableXOrigin; int wy = y + tree->drawableYOrigin; int w = !(open & RECT_OPEN_W); int n = !(open & RECT_OPEN_N); int e = !(open & RECT_OPEN_E); int s = !(open & RECT_OPEN_S); int nw, ne, sw, se; #if 0 int i; #endif XGCValues gcValues; unsigned long gcMask; #if 1 GC gc[2]; /* Dots on even pixels only */ nw = !(wx & 1) == !(wy & 1); ne = !((wx + width - 1) & 1) == !(wy & 1); sw = !(wx & 1) == !((wy + height - 1) & 1); se = !((wx + width - 1) & 1) == !((wy + height - 1) & 1); gcValues.function = GXinvert; gcValues.line_style = LineOnOffDash; gcValues.dashes = 1; gcValues.dash_offset = 0; gcMask = GCFunction | GCLineStyle | GCDashList | GCDashOffset; gc[0] = Tree_GetGC(tree, gcMask, &gcValues); gcValues.dash_offset = 1; gc[1] = Tree_GetGC(tree, gcMask, &gcValues); if (w) { XDrawLine(tree->display, drawable, gc[!nw], x, y, x, y + height - 1); } if (n) { if (w) XDrawLine(tree->display, drawable, gc[nw], x + 1, y, x + width - 1, y); else XDrawLine(tree->display, drawable, gc[!nw], x, y, x + width - 1, y); } if (e) { if (n) XDrawLine(tree->display, drawable, gc[ne], x + width - 1, y + 1, x + width - 1, y + height - 1); else XDrawLine(tree->display, drawable, gc[!ne], x + width - 1, y, x + width - 1, y + height - 1); } if (s) { if (w) XDrawLine(tree->display, drawable, gc[sw], x + 1, y + height - 1, x + width - 1 - e, y + height - 1); else XDrawLine(tree->display, drawable, gc[!sw], x, y + height - 1, x + width - 1 - e, y + height - 1); } #else GC gc; /* Dots on even pixels only */ nw = !(wx & 1) == !(wy & 1); ne = !((wx + width - 1) & 1) == !(wy & 1); sw = !(wx & 1) == !((wy + height - 1) & 1); se = !((wx + width - 1) & 1) == !((wy + height - 1) & 1); gcValues.function = GXinvert; gcMask = GCFunction; gc = Tree_GetGC(tree, gcMask, &gcValues); if (w) /* left */ { for (i = !nw; i < height; i += 2) { XDrawPoint(tree->display, drawable, gc, x, y + i); } } if (n) /* top */ { for (i = nw ? w * 2 : 1; i < width; i += 2) { XDrawPoint(tree->display, drawable, gc, x + i, y); } } if (e) /* right */ { for (i = ne ? n * 2 : 1; i < height; i += 2) { XDrawPoint(tree->display, drawable, gc, x + width - 1, y + i); } } if (s) /* bottom */ { for (i = sw ? w * 2 : 1; i < width - (se && e); i += 2) { XDrawPoint(tree->display, drawable, gc, x + i, y + height - 1); } } #endif } /* * The following structure is used when drawing a number of dotted XOR * rectangles. */ struct DotStatePriv { TreeCtrl *tree; Drawable drawable; GC gc; TkRegion rgn; }; /* *---------------------------------------------------------------------- * * TreeDotRect_Setup -- * * Prepare a drawable for drawing a series of dotted XOR rectangles. * * Results: * State info is returned to be used by the other TreeDotRect_xxx() * procedures. * * Side effects: * On Win32 and OSX the device context/graphics port is altered * in preparation for drawing. On X11 a new graphics context is * created. * *---------------------------------------------------------------------- */ void TreeDotRect_Setup( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ DotState *p /* Where to save state info. */ ) { struct DotStatePriv *dotState = (struct DotStatePriv *) p; XGCValues gcValues; unsigned long mask; XRectangle xrect; dotState->tree = tree; dotState->drawable = drawable; gcValues.line_style = LineOnOffDash; gcValues.line_width = 1; gcValues.dash_offset = 0; gcValues.dashes = 1; gcValues.function = GXinvert; mask = GCLineWidth | GCLineStyle | GCDashList | GCDashOffset | GCFunction; dotState->gc = Tk_GetGC(tree->tkwin, mask, &gcValues); /* Keep drawing inside the contentbox. */ dotState->rgn = Tree_GetRegion(tree); xrect.x = Tree_ContentLeft(tree); xrect.y = Tree_ContentTop(tree); xrect.width = Tree_ContentRight(tree) - xrect.x; xrect.height = Tree_ContentBottom(tree) - xrect.y; TkUnionRectWithRegion(&xrect, dotState->rgn, dotState->rgn); TkSetRegion(tree->display, dotState->gc, dotState->rgn); } /* *---------------------------------------------------------------------- * * TreeDotRect_Draw -- * * Draw a dotted XOR rectangle. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void TreeDotRect_Draw( DotState *p, /* Info returned by TreeDotRect_Setup(). */ int x, int y, /* Left and top coordinates. */ int width, int height /* Size of rectangle. */ ) { struct DotStatePriv *dotState = (struct DotStatePriv *) p; XDrawRectangle(dotState->tree->display, dotState->drawable, dotState->gc, x, y, width - 1, height - 1); } /* *---------------------------------------------------------------------- * * TreeDotRect_Restore -- * * Restore the drawing environment. * * Results: * None. * * Side effects: * On Win32 and OSX the device context/graphics port is restored. * On X11 a new graphics context is freed. * *---------------------------------------------------------------------- */ void TreeDotRect_Restore( DotState *p /* Info returned by TreeDotRect_Setup(). */ ) { struct DotStatePriv *dotState = (struct DotStatePriv *) p; XSetClipMask(dotState->tree->display, dotState->gc, None); Tree_FreeRegion(dotState->tree, dotState->rgn); Tk_FreeGC(dotState->tree->display, dotState->gc); } /* *---------------------------------------------------------------------- * * Tree_FillRegion -- * * Paint a region with the foreground color of a graphics context. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_FillRegion( Display *display, /* Display. */ Drawable drawable, /* Where to draw. */ GC gc, /* Foreground color. */ TkRegion rgn /* Region to paint. */ ) { XRectangle box; TkClipBox(rgn, &box); TkSetRegion(display, gc, rgn); XFillRectangle(display, drawable, gc, box.x, box.y, box.width, box.height); XSetClipMask(display, gc, None); } /* *---------------------------------------------------------------------- * * Tree_OffsetRegion -- * * Offset a region. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_OffsetRegion( TkRegion region, /* Region to modify. */ int xOffset, int yOffset /* Horizontal and vertical offsets. */ ) { XOffsetRegion((Region) region, xOffset, yOffset); } /* *---------------------------------------------------------------------- * * Tree_UnionRegion -- * * Compute the union of 2 regions. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_UnionRegion( TkRegion rgnA, TkRegion rgnB, TkRegion rgnOut) { XUnionRegion((Region) rgnA, (Region) rgnB, (Region) rgnOut); } /* *---------------------------------------------------------------------- * * Tree_ScrollWindow -- * * Wrapper around TkScrollWindow() to fix an apparent bug with the * Mac/OSX versions. * * Results: * None. * * Side effects: * Stuff is scrolled in a drawable. * *---------------------------------------------------------------------- */ int Tree_ScrollWindow( TreeCtrl *tree, /* Widget info. */ GC gc, /* Arg to TkScrollWindow(). */ int x, int y, /* Arg to TkScrollWindow(). */ int width, int height, /* Arg to TkScrollWindow(). */ int dx, int dy, /* Arg to TkScrollWindow(). */ TkRegion damageRgn /* Arg to TkScrollWindow(). */ ) { int result = TkScrollWindow(tree->tkwin, gc, x, y, width, height, dx, dy, damageRgn); return result; } /* *---------------------------------------------------------------------- * * Tree_UnsetClipMask -- * * Wrapper around XSetClipMask(). On Win32 Tk_DrawChars() does * not clear the clipping region. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_UnsetClipMask( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ GC gc /* Graphics context to modify. */ ) { XSetClipMask(tree->display, gc, None); } /* *---------------------------------------------------------------------- * * Tree_DrawBitmapWithGC -- * * Draw part of a bitmap. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_DrawBitmapWithGC( TreeCtrl *tree, /* Widget info. */ Pixmap bitmap, /* Bitmap to draw. */ Drawable drawable, /* Where to draw. */ GC gc, /* Graphics context. */ int src_x, int src_y, /* Left and top of part of bitmap to copy. */ int width, int height, /* Width and height of part of bitmap to * copy. */ int dest_x, int dest_y /* Left and top coordinates to copy part of * the bitmap to. */ ) { XSetClipOrigin(tree->display, gc, dest_x, dest_y); XCopyPlane(tree->display, bitmap, drawable, gc, src_x, src_y, (unsigned int) width, (unsigned int) height, dest_x, dest_y, 1); XSetClipOrigin(tree->display, gc, 0, 0); } /* * TIP #116 altered Tk_PhotoPutBlock API to add interp arg. * We need to remove that for compiling with 8.4. */ #if (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 5) #define TK_PHOTOPUTBLOCK(interp, hdl, blk, x, y, w, h, cr) \ Tk_PhotoPutBlock(hdl, blk, x, y, w, h, cr) #define TK_PHOTOPUTZOOMEDBLOCK(interp, hdl, blk, x, y, w, h, \ zx, zy, sx, sy, cr) \ Tk_PhotoPutZoomedBlock(hdl, blk, x, y, w, h, \ zx, zy, sx, sy, cr) #else #define TK_PHOTOPUTBLOCK Tk_PhotoPutBlock #define TK_PHOTOPUTZOOMEDBLOCK Tk_PhotoPutZoomedBlock #endif /* *---------------------------------------------------------------------- * * Tree_XImage2Photo -- * * Copy pixels from an XImage to a Tk photo image. * * Results: * None. * * Side effects: * The given photo image is blanked and all the pixels from the * XImage are put into the photo image. * *---------------------------------------------------------------------- */ void Tree_XImage2Photo( Tcl_Interp *interp, /* Current interpreter. */ Tk_PhotoHandle photoH, /* Existing photo image. */ XImage *ximage, /* XImage to copy pixels from. */ unsigned long trans, /* Pixel value in ximage that should be * considered transparent. */ int alpha /* Desired transparency of photo image.*/ ) { Tk_Window tkwin = Tk_MainWindow(interp); Display *display = Tk_Display(tkwin); Visual *visual = Tk_Visual(tkwin); Tk_PhotoImageBlock photoBlock; unsigned char *pixelPtr; int x, y, w = ximage->width, h = ximage->height; int i, ncolors; XColor *xcolors; unsigned long red_shift, green_shift, blue_shift; int separated = 0; Tk_PhotoBlank(photoH); /* See TkPoscriptImage */ ncolors = visual->map_entries; xcolors = (XColor *) ckalloc(sizeof(XColor) * ncolors); if ((visual->class == DirectColor) || (visual->class == TrueColor)) { separated = 1; red_shift = green_shift = blue_shift = 0; /* ximage->red_mask etc are zero */ while ((0x0001 & (visual->red_mask >> red_shift)) == 0) red_shift++; while ((0x0001 & (visual->green_mask >> green_shift)) == 0) green_shift++; while ((0x0001 & (visual->blue_mask >> blue_shift)) == 0) blue_shift++; for (i = 0; i < ncolors; i++) { xcolors[i].pixel = ((i << red_shift) & visual->red_mask) | ((i << green_shift) & visual->green_mask) | ((i << blue_shift) & visual->blue_mask); } } else { red_shift = green_shift = blue_shift = 0; for (i = 0; i < ncolors; i++) xcolors[i].pixel = i; } XQueryColors(display, Tk_Colormap(tkwin), xcolors, ncolors); pixelPtr = (unsigned char *) Tcl_Alloc(ximage->width * ximage->height * 4); photoBlock.pixelPtr = pixelPtr; photoBlock.width = ximage->width; photoBlock.height = ximage->height; photoBlock.pitch = ximage->width * 4; photoBlock.pixelSize = 4; photoBlock.offset[0] = 0; photoBlock.offset[1] = 1; photoBlock.offset[2] = 2; photoBlock.offset[3] = 3; for (y = 0; y < ximage->height; y++) { for (x = 0; x < ximage->width; x++) { int r, g, b; unsigned long pixel; pixel = XGetPixel(ximage, x, y); /* Set alpha=0 for transparent pixel in the source XImage */ if (trans != 0 && pixel == trans) { pixelPtr[y * photoBlock.pitch + x * 4 + 3] = 0; continue; } if (separated) { r = (pixel & visual->red_mask) >> red_shift; g = (pixel & visual->green_mask) >> green_shift; b = (pixel & visual->blue_mask) >> blue_shift; r = ((double) xcolors[r].red / USHRT_MAX) * 255; g = ((double) xcolors[g].green / USHRT_MAX) * 255; b = ((double) xcolors[b].blue / USHRT_MAX) * 255; } else { r = ((double) xcolors[pixel].red / USHRT_MAX) * 255; g = ((double) xcolors[pixel].green / USHRT_MAX) * 255; b = ((double) xcolors[pixel].blue / USHRT_MAX) * 255; } pixelPtr[y * photoBlock.pitch + x * 4 + 0] = r; pixelPtr[y * photoBlock.pitch + x * 4 + 1] = g; pixelPtr[y * photoBlock.pitch + x * 4 + 2] = b; pixelPtr[y * photoBlock.pitch + x * 4 + 3] = alpha; } } TK_PHOTOPUTBLOCK(interp, photoH, &photoBlock, 0, 0, w, h, TK_PHOTO_COMPOSITE_SET); Tcl_Free((char *) pixelPtr); ckfree((char *) xcolors); } typedef struct { TreeCtrl *tree; TreeClip *clip; GC gc; TkRegion region; } TreeClipStateGC; void TreeClip_ToGC( TreeCtrl *tree, /* Widget info. */ TreeClip *clip, /* Clipping area or NULL. */ GC gc, /* Graphics context. */ TreeClipStateGC *state ) { state->tree = tree; state->clip = clip; state->gc = gc; state->region = None; if (clip && clip->type == TREE_CLIP_RECT) { state->region = Tree_GetRectRegion(tree, &clip->tr); TkSetRegion(tree->display, gc, state->region); } if (clip && clip->type == TREE_CLIP_AREA) { TreeRectangle tr; if (Tree_AreaBbox(tree, clip->area, &tr) == 0) return; state->region = Tree_GetRectRegion(tree, &tr); TkSetRegion(tree->display, gc, state->region); } if (clip && clip->type == TREE_CLIP_REGION) { TkSetRegion(tree->display, gc, clip->region); } } void TreeClip_FinishGC( TreeClipStateGC *state ) { XSetClipMask(state->tree->display, state->gc, None); if (state->region != None) /* only if TreeClip_ToGC allocated it */ Tree_FreeRegion(state->tree, state->region); } /* *---------------------------------------------------------------------- * * Tree_FillRectangle -- * * Wrapper around XFillRectangle() because the clip region is * ignored on Win32. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ void Tree_FillRectangle( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ GC gc, /* Graphics context. */ TreeRectangle tr /* Rectangle to paint. */ ) { TreeClipStateGC clipState; TreeRectangle tr2; /* X11 coordinates are 16-bit. */ TreeRect_SetXYWH(tr2, 0, 0, td.width, td.height); TreeRect_Intersect(&tr, &tr, &tr2); TreeClip_ToGC(tree, clip, gc, &clipState); XFillRectangle(tree->display, td.drawable, gc, tr.x, tr.y, tr.width, tr.height); TreeClip_FinishGC(&clipState); } #if USE_ITEM_PIXMAP == 0 /* *---------------------------------------------------------------------- * * Tree_Draw3DRectangle -- * * Wrapper around Tk_Draw3DRectangle() because the clip region is * ignored on Win32. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ void Tree_Draw3DRectangle( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ Tk_3DBorder border, /* Token for border to draw. */ int x, int y, int width, int height, /* Outside area of region in which border will * be drawn. */ int borderWidth, /* Desired width for border, in pixels. */ int relief /* Type of relief: TK_RELIEF_RAISED, * TK_RELIEF_SUNKEN, TK_RELIEF_GROOVE, etc. */ ) { TreeClipStateGC clipState[3]; GC gc[3]; int i; gc[0] = Tk_3DBorderGC(tree->tkwin, border, TK_3D_LIGHT_GC); gc[1] = Tk_3DBorderGC(tree->tkwin, border, TK_3D_DARK_GC); gc[2] = Tk_3DBorderGC(tree->tkwin, border, TK_3D_FLAT_GC); /* FIXME: will allocate 3 identical regions unless TREE_CLIP_REGION is used. */ for (i = 0; i < 3; i++) TreeClip_ToGC(tree, clip, gc[i], &clipState[i]); Tk_Draw3DRectangle(tree->tkwin, td.drawable, border, x, y, width, height, borderWidth, relief); for (i = 0; i < 3; i++) TreeClip_FinishGC(&clipState[i]); } /* *---------------------------------------------------------------------- * * Tree_Fill3DRectangle -- * * Wrapper around Tree_Fill3DRectangle() because the clip region is * ignored on Win32. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ void Tree_Fill3DRectangle( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ Tk_3DBorder border, /* Token for border to draw. */ int x, int y, int width, int height, /* Outside area of rectangular region. */ int borderWidth, /* Desired width for border, in pixels. Border * will be *inside* region. */ int relief /* Indicates 3D effect: TK_RELIEF_FLAT, * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */ ) { TreeClipStateGC clipState[3]; GC gc[3]; int i; gc[0] = Tk_3DBorderGC(tree->tkwin, border, TK_3D_LIGHT_GC); gc[1] = Tk_3DBorderGC(tree->tkwin, border, TK_3D_DARK_GC); gc[2] = Tk_3DBorderGC(tree->tkwin, border, TK_3D_FLAT_GC); /* FIXME: will allocate 3 identical regions unless TREE_CLIP_REGION is used. */ for (i = 0; i < 3; i++) TreeClip_ToGC(tree, clip, gc[i], &clipState[i]); Tk_Fill3DRectangle(tree->tkwin, td.drawable, border, x, y, width, height, borderWidth, relief); for (i = 0; i < 3; i++) TreeClip_FinishGC(&clipState[i]); } #endif /* USE_ITEM_PIXMAP == 0 */ /*** Themes ***/ #ifdef TREECTRL_GTK #ifdef TREECTRL_DEBUG /* FIXME: This errors out, even with a small Gtk+ app (no Tcl) */ /* gtk_init_check() gdk_display_open_default_libgtk_only() gdk_display_manager_set_default_display() g_object_notify() ... link_is_locked() in /usr/lib/libORBit-2.so.0 link_mutex_is_locked() in /usr/lib/libORBit-2.so.0 */ /*#define G_ERRORCHECK_MUTEXES*/ #endif #include #include #include #include #include #include TCL_DECLARE_MUTEX(themeMutex) /* Per-interp data */ struct TreeThemeData_ { TreeItem animButtonItem; Tcl_TimerToken animButtonTimer; GtkExpanderStyle animButtonStyle; int animButtonExpanding; }; /* Per-application data */ typedef struct { gboolean gtk_init; int pixbuf_init; GtkWidget *gtkWindow; GtkWidget *protoLayout; GtkWidget *gtkArrow; GtkWidget *gtkTreeView; GtkWidget *gtkTreeHeader; /* Cached theme parameters */ int buttonWidth, buttonHeight; int arrowWidth, arrowHeight; XColor *textColor[3]; } TreeThemeAppData; static TreeThemeAppData *appThemeData = NULL; #define IsGtkUnavailable() ( appThemeData == NULL || appThemeData->gtk_init == 0) /* *---------------------------------------------------------------------- * * TreeTheme_DrawHeaderItem -- * * Draws the background of a single column header. On Mac OS X * this also draws the sort arrow, if any. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawHeaderItem( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ int state, /* COLUMN_STATE_xxx flags. */ int arrow, /* COLUMN_ARROW_xxx flags. */ int visIndex, /* 0-based index in list of visible columns. */ int x, int y, /* Bounds of the header. */ int width, int height /* Bounds of the header. */ ) { GtkWidget *widget; GtkStyle *style; GtkStateType state_type = GTK_STATE_NORMAL; GtkShadowType shadow_type = GTK_SHADOW_OUT; GdkRectangle area = {0, 0, width, height}; /* clip */ GdkPixmap *gdkPixmap; GdkPixbuf *pixbuf; if (IsGtkUnavailable() || appThemeData->gtkTreeHeader == NULL) return TCL_ERROR; gdk_threads_enter(); /* +++ grab global mutex +++ */ widget = appThemeData->gtkTreeHeader; style = gtk_widget_get_style(widget); switch (state) { case COLUMN_STATE_ACTIVE: state_type = GTK_STATE_PRELIGHT; break; case COLUMN_STATE_PRESSED: state_type = GTK_STATE_ACTIVE; shadow_type = GTK_SHADOW_IN; break; case COLUMN_STATE_NORMAL: break; } /* Allocate GdkPixmap to draw background in */ gdkPixmap = gdk_pixmap_new(appThemeData->gtkWindow->window, width, height, -1); if (gdkPixmap == NULL) { goto ret_error; } /* Paint the background */ gtk_paint_box (style, gdkPixmap, state_type, shadow_type, &area, widget, "button", 0, 0, width, height); /* Copy GdkPixmap to Tk Pixmap */ pixbuf = gdk_pixbuf_get_from_drawable(NULL, gdkPixmap, NULL, 0, 0, 0, 0, width, height); if (pixbuf == NULL) { g_object_unref(gdkPixmap); goto ret_error; } gdk_pixbuf_xlib_render_to_drawable(pixbuf, td.drawable, tree->copyGC, 0, 0, x, y, width, height, XLIB_RGB_DITHER_NONE, 0, 0); gdk_pixbuf_unref(pixbuf); g_object_unref(gdkPixmap); gdk_threads_leave(); /* +++ release global mutex +++ */ return TCL_OK; ret_error: gdk_threads_leave(); /* +++ release global mutex +++ */ return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_GetHeaderContentMargins -- * * Returns the padding inside the column header borders where * text etc may be displayed. * * Results: * TCL_OK if 'bounds' was set, TCL_ERROR otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetHeaderContentMargins( TreeCtrl *tree, /* Widget info. */ int state, /* COLUMN_STATE_xxx flags. */ int arrow, /* COLUMN_ARROW_xxx flags. */ int bounds[4] /* Returned left-top-right-bottom padding. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawHeaderArrow -- * * Draws the sort arrow in a column header. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawHeaderArrow( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ int state, /* COLUMN_STATE_xxx flags. */ int up, /* TRUE if up arrow, FALSE otherwise. */ int x, int y, /* Bounds of arrow. Width and */ int width, int height /* height are the same as that returned */ /* by TreeTheme_GetArrowSize(). */ ) { GtkWidget *widget; GtkStyle *style; GtkStateType state_type = GTK_STATE_NORMAL; GdkRectangle area = {0, 0, width, height}; /* clip */ const gchar *detail = "arrow"; GtkShadowType shadow_type; GtkArrowType effective_arrow_type = up ? GTK_ARROW_DOWN : GTK_ARROW_UP; /* INVERTED!!! */ GdkPixmap *gdkPixmap; TreeRectangle trClipped, trDrawable; GdkPixbuf *pixbuf; if (IsGtkUnavailable() || appThemeData->gtkArrow == NULL) return TCL_ERROR; TreeRect_SetXYWH(trDrawable, 0, 0, td.width, td.height); TreeRect_SetXYWH(trClipped, x, y, width, height); if (TreeRect_Intersect(&trClipped, &trClipped, &trDrawable) == 0) return TCL_OK; gdk_threads_enter(); /* +++ grab global mutex +++ */ widget = appThemeData->gtkArrow; style = gtk_widget_get_style(widget); shadow_type = GTK_ARROW(widget)->shadow_type; switch (state) { case COLUMN_STATE_ACTIVE: state_type = GTK_STATE_PRELIGHT; break; case COLUMN_STATE_PRESSED: state_type = GTK_STATE_ACTIVE; break; case COLUMN_STATE_NORMAL: break; } if (appThemeData->gtkTreeView != NULL) { gboolean alternative = FALSE; GtkSettings *settings = gtk_widget_get_settings(appThemeData->gtkTreeView); g_object_get(settings, "gtk-alternative-sort-arrows", &alternative, NULL); if (alternative) effective_arrow_type = up ? GTK_ARROW_UP : GTK_ARROW_DOWN; } /* This gives warning "widget class `GtkArrow' has no property named `shadow-type'" */ /* gtk_widget_style_get(widget, "shadow-type", &shadow_type, NULL); */ /* Copy background from Tk Pixmap -> GdkPixbuf */ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 1, 8, width, height); if (pixbuf == NULL) goto ret_error; pixbuf = gdk_pixbuf_xlib_get_from_drawable(pixbuf, td.drawable, Tk_Colormap(tree->tkwin), Tk_Visual(tree->tkwin), trClipped.x, trClipped.y, x < 0 ? -x : 0, y < 0 ? -y : 0, trClipped.width, trClipped.height); if (pixbuf == NULL) goto ret_error; /* Allocate GdkPixmap to draw button in */ gdkPixmap = gdk_pixmap_new(appThemeData->gtkWindow->window, width, height, -1); if (gdkPixmap == NULL) { gdk_pixbuf_unref(pixbuf); goto ret_error; } /* Copy GdkPixbuf containing background to GdkPixmap */ gdk_pixbuf_render_to_drawable(pixbuf, gdkPixmap, NULL, 0, 0, 0, 0, width, height, GDK_RGB_DITHER_NONE, 0, 0); /* Draw the button */ gtk_paint_arrow(style, gdkPixmap, state_type, shadow_type, &area, widget, detail, effective_arrow_type, TRUE, 0, 0, width, height); /* Copy GdkPixmap to Tk Pixmap */ pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, gdkPixmap, NULL, 0, 0, 0, 0, width, height); if (pixbuf == NULL) { g_object_unref(gdkPixmap); goto ret_error; } gdk_pixbuf_xlib_render_to_drawable(pixbuf, td.drawable, tree->copyGC, 0, 0, x, y, width, height, XLIB_RGB_DITHER_MAX, 0, 0); gdk_pixbuf_unref(pixbuf); g_object_unref(gdkPixmap); gdk_threads_leave(); /* +++ release global mutex +++ */ return TCL_OK; ret_error: gdk_threads_leave(); /* +++ release global mutex +++ */ return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawButton -- * * Draws a single expand/collapse item button. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawButton( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeItem item, /* Needed for animating. */ int state, /* STATE_xxx | BUTTON_STATE_xxx flags. */ int x, int y, /* Bounds of the button. Width and height */ int width, int height /* are the same as that returned by */ /* TreeTheme_GetButtonSize(). */ ) { int open = state & STATE_ITEM_OPEN; GtkWidget *widget; GtkStyle *style; GtkStateType state_type = GTK_STATE_NORMAL; GdkRectangle area = {0, 0, width + 2, height + 2}; /* clip */ const gchar *detail = "treeview"; GtkExpanderStyle expander_style = open ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED; GdkPixmap *gdkPixmap; TreeRectangle trClipped, trDrawable; GdkPixbuf *pixbuf; if (IsGtkUnavailable() || appThemeData->gtkTreeView == NULL) return TCL_ERROR; TreeRect_SetXYWH(trDrawable, 0, 0, td.width, td.height); TreeRect_SetXYWH(trClipped, x - 1, y - 1, width + 2, height + 2); if (TreeRect_Intersect(&trClipped, &trClipped, &trDrawable) == 0) return TCL_OK; if (state & BUTTON_STATE_ACTIVE) state_type = GTK_STATE_PRELIGHT; else if (state & BUTTON_STATE_PRESSED) state_type = GTK_STATE_ACTIVE; if (item == tree->themeData->animButtonItem) { expander_style = tree->themeData->animButtonStyle; } gdk_threads_enter(); /* +++ grab global mutex +++ */ widget = appThemeData->gtkTreeView; style = gtk_widget_get_style(widget); /* Copy background from Tk Pixmap -> GdkPixbuf */ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 1, 8, width + 2, height + 2); if (pixbuf == NULL) goto ret_error; pixbuf = gdk_pixbuf_xlib_get_from_drawable(pixbuf, td.drawable, Tk_Colormap(tree->tkwin), Tk_Visual(tree->tkwin), trClipped.x, trClipped.y, (x - 1) < 0 ? -(x - 1) : 0, (y - 1) < 0 ? -(y - 1) : 0, trClipped.width, trClipped.height); if (pixbuf == NULL) goto ret_error; /* Allocate GdkPixmap to draw button in */ gdkPixmap = gdk_pixmap_new(appThemeData->gtkWindow->window, width + 2, height + 2, -1); if (gdkPixmap == NULL) { gdk_pixbuf_unref(pixbuf); goto ret_error; } /* Copy GdkPixbuf containing background to GdkPixmap */ gdk_pixbuf_render_to_drawable(pixbuf, gdkPixmap, NULL, 0, 0, 0, 0, width + 2, height + 2, GDK_RGB_DITHER_NONE, 0, 0); /* Draw the button */ gtk_paint_expander(style, gdkPixmap, state_type, &area, widget, detail, width / 2 + 1, height / 2 + 1, expander_style); /* Copy GdkPixmap to Tk Pixmap */ pixbuf = gdk_pixbuf_get_from_drawable(pixbuf, gdkPixmap, NULL, 0, 0, 0, 0, width + 2, height + 2); if (pixbuf == NULL) { g_object_unref(gdkPixmap); goto ret_error; } gdk_pixbuf_xlib_render_to_drawable(pixbuf, td.drawable, tree->copyGC, 0, 0, x - 1, y - 1, width + 2, height + 2, XLIB_RGB_DITHER_MAX, 0, 0); gdk_pixbuf_unref(pixbuf); g_object_unref(gdkPixmap); gdk_threads_leave(); /* +++ release global mutex +++ */ return TCL_OK; ret_error: gdk_threads_leave(); /* +++ release global mutex +++ */ return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_GetButtonSize -- * * Returns the width and height of an expand/collapse item button. * * Results: * TCL_OK if *widthPtr and *heightPtr were set, TCL_ERROR * if themed buttons can't be drawn. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetButtonSize( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Needed on MS Windows. */ int open, /* TRUE if expanded button. */ int *widthPtr, /* Returned width of button. */ int *heightPtr /* Returned height of button. */ ) { GtkWidget *widget; const gchar *property_name = "expander-size"; gint expander_size; if (IsGtkUnavailable() || appThemeData->gtkTreeView == NULL) return TCL_ERROR; /* Use the cached value if available */ if (appThemeData->buttonWidth > 0) { (*widthPtr) = appThemeData->buttonWidth; (*heightPtr) = appThemeData->buttonHeight; return TCL_OK; } gdk_threads_enter(); /* +++ grab global mutex +++ */ widget = appThemeData->gtkTreeView; gtk_widget_style_get(widget, property_name, &expander_size, NULL); gdk_threads_leave(); /* +++ release global mutex +++ */ appThemeData->buttonWidth = appThemeData->buttonHeight = expander_size; (*widthPtr) = (*heightPtr) = expander_size; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_GetArrowSize -- * * Returns the width and height of a column header sort arrow. * * Results: * TCL_OK if *widthPtr and *heightPtr were set, TCL_ERROR * if themed sort arrows can't be drawn. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetArrowSize( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Needed on MS Windows. */ int up, /* TRUE if up arrow. */ int *widthPtr, /* Returned width of arrow. */ int *heightPtr /* Returned height of arrow. */ ) { GtkWidget *widget; GtkRequisition requisition; gfloat arrow_scaling = 1.0f; GtkMisc *misc; gint width, height, extent; if (IsGtkUnavailable() || appThemeData->gtkArrow == NULL) return TCL_ERROR; /* Use the cached value if available */ if (appThemeData->arrowWidth > 0) { (*widthPtr) = appThemeData->arrowWidth; (*heightPtr) = appThemeData->arrowHeight; return TCL_OK; } gdk_threads_enter(); /* +++ grab global mutex +++ */ widget = appThemeData->gtkArrow; misc = GTK_MISC(widget); gtk_widget_size_request(widget, &requisition); gtk_widget_style_get(widget, "arrow-scaling", &arrow_scaling, NULL); width = requisition.width - misc->xpad * 2; height = requisition.height - misc->ypad * 2; extent = MIN(width, height) * arrow_scaling; gdk_threads_leave(); /* +++ release global mutex +++ */ appThemeData->arrowWidth = appThemeData->arrowHeight = extent; (*widthPtr) = (*heightPtr) = extent; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_SetBorders -- * * Sets the TreeCtrl.inset pad values according to the needs of * the system theme. * * Results: * TCL_OK if the inset was set, TCL_ERROR if the -highlightthickness * and -borderwidth values should be used. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_SetBorders( TreeCtrl *tree /* Widget info. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawBorders -- * * Draws themed borders around the edges of the treectrl. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the Tk focus rectangle * and 3D border should be drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawBorders( TreeCtrl *tree, /* Widget info. */ Drawable drawable /* Where to draw. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_GetHeaderTextColor -- * * Returns the text fill color to display a column title with. * * Results: * TCL_OK if the *colorPtrPtr was set, TCL_ERROR if a non-theme * color should be used. * * Side effects: * May allocate a new XColor. * *---------------------------------------------------------------------- */ int TreeTheme_GetHeaderTextColor( TreeCtrl *tree, /* Widget info. */ int columnState, /* COLUMN_STATE_xxx flags. */ XColor **colorPtrPtr /* Returned text color. */ ) { GtkWidget *widget; GtkStyle *style; GtkStateType state_type = GTK_STATE_NORMAL; int colorIndex = 0; GdkColor *gdkColor; XColor pref; if (IsGtkUnavailable() || appThemeData->gtkTreeHeader == NULL) return TCL_ERROR; switch (columnState) { case COLUMN_STATE_ACTIVE: state_type = GTK_STATE_PRELIGHT; colorIndex = 1; break; case COLUMN_STATE_PRESSED: state_type = GTK_STATE_ACTIVE; colorIndex = 2; break; case COLUMN_STATE_NORMAL: break; } /* Use the cached value if available */ if (appThemeData->textColor[colorIndex] != NULL) { (*colorPtrPtr) = appThemeData->textColor[colorIndex]; return TCL_OK; } gdk_threads_enter(); /* +++ grab global mutex +++ */ widget = appThemeData->gtkTreeHeader; style = gtk_widget_get_style(widget); gdkColor = &style->fg[state_type]; pref.red = gdkColor->red; pref.green = gdkColor->green; pref.blue = gdkColor->blue; appThemeData->textColor[colorIndex] = Tk_GetColorByValue(tree->tkwin, &pref); (*colorPtrPtr) = appThemeData->textColor[colorIndex]; gdk_threads_leave(); /* +++ release global mutex +++ */ return TCL_OK; } #define ANIM_BUTTON_INTERVAL 50 /* same as gtk_treeview */ static void AnimButtonTimerProc( ClientData clientData ) { TreeCtrl *tree = clientData; int finished = 0; if (tree->themeData->animButtonExpanding) { if (tree->themeData->animButtonStyle == GTK_EXPANDER_SEMI_COLLAPSED) tree->themeData->animButtonStyle = GTK_EXPANDER_SEMI_EXPANDED; else finished = 1; } else { if (tree->themeData->animButtonStyle == GTK_EXPANDER_SEMI_EXPANDED) tree->themeData->animButtonStyle = GTK_EXPANDER_SEMI_COLLAPSED; else finished = 1; } Tree_InvalidateItemDInfo(tree, tree->columnTree, tree->themeData->animButtonItem, NULL); if (finished) { tree->themeData->animButtonTimer = NULL; tree->themeData->animButtonItem = NULL; } else { tree->themeData->animButtonTimer = Tcl_CreateTimerHandler( ANIM_BUTTON_INTERVAL, AnimButtonTimerProc, tree); } } /* *---------------------------------------------------------------------- * * TreeTheme_AnimateButtonStart -- * * Starts an expand/collapse item button animating from open to * closed or vice versa. * * Results: * TCL_OK. * * Side effects: * May create a new Tcl_TimerToken. * *---------------------------------------------------------------------- */ int TreeTheme_AnimateButtonStart( TreeCtrl *tree, /* Widget info. */ TreeItem item /* The item whose button should animate. */ ) { int open = (TreeItem_GetState(tree, item) & STATE_ITEM_OPEN) != 0; int animate; /* gtk_treeview toggles right away, not when the animation finishes. */ TreeItem_OpenClose(tree, item, -1); #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif if (IsGtkUnavailable() || appThemeData->gtkTreeView == NULL) { return TCL_OK; } gdk_threads_enter(); /* +++ grab global mutex +++ */ g_object_get(gtk_widget_get_settings(GTK_WIDGET(appThemeData->gtkTreeView)), "gtk-enable-animations", &animate, NULL); gdk_threads_leave(); /* +++ release global mutex +++ */ if (!animate) { return TCL_OK; } if (tree->themeData->animButtonTimer != NULL) Tcl_DeleteTimerHandler(tree->themeData->animButtonTimer); tree->themeData->animButtonItem = item; tree->themeData->animButtonTimer = Tcl_CreateTimerHandler( ANIM_BUTTON_INTERVAL, AnimButtonTimerProc, tree); tree->themeData->animButtonExpanding = !open; if (open) tree->themeData->animButtonStyle = GTK_EXPANDER_SEMI_EXPANDED; else tree->themeData->animButtonStyle = GTK_EXPANDER_SEMI_COLLAPSED; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_ItemDeleted -- * * Cancels any item-button animation in progress. * * Results: * TCL_OK. * * Side effects: * May delete a TCL_TimerToken. * *---------------------------------------------------------------------- */ int TreeTheme_ItemDeleted( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item being deleted. */ ) { if (item != tree->themeData->animButtonItem) return TCL_OK; if (tree->themeData->animButtonTimer != NULL) { Tcl_DeleteTimerHandler(tree->themeData->animButtonTimer); tree->themeData->animButtonTimer = NULL; tree->themeData->animButtonItem = NULL; } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_Relayout -- * * This gets called when certain config options change and when * the size of the widget changes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeTheme_Relayout( TreeCtrl *tree /* Widget info. */ ) { } /* *---------------------------------------------------------------------- * * TreeTheme_IsDesktopComposited -- * * Determine if the OS windowing system is composited AKA * double-buffered. * * Results: * FALSE FALSE FALSE. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_IsDesktopComposited( TreeCtrl *tree /* Widget info. */ ) { return FALSE; } /* *---------------------------------------------------------------------- * * TreeTheme_ThemeChanged -- * * Called after the system theme changes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeTheme_ThemeChanged( TreeCtrl *tree /* Widget info. */ ) { } #if 0 /* _GTK_READ_RCFILES ClientMessage sent to X toplevel windows with WM_STATE property */ /* gtk_rc_reparse_all_for_settings(gtk_widget_get_settings(widget), FALSE); */ static int ClientMessageHandler(Tk_Window tkwin, XEvent *eventPtr) { dbwin("ClientMessageHandler type=%d\n",eventPtr->type); fprintf(stderr,"ClientMessageHandler type=%d\n",eventPtr->type); return 0; } #endif /* *---------------------------------------------------------------------- * * TreeTheme_InitWidget -- * * Performs theme-related initialization when a treectrl is * created. * * Results: * TCL_OK or TCL_ERROR, but result is ignored. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_InitWidget( TreeCtrl *tree /* Widget info. */ ) { tree->themeData = (TreeThemeData) ckalloc(sizeof(struct TreeThemeData_)); memset(tree->themeData, '\0', sizeof(struct TreeThemeData_)); Tcl_MutexLock(&themeMutex); if (IsGtkUnavailable() == 0 && appThemeData->pixbuf_init == 0) { Tk_MakeWindowExist(tree->tkwin); gdk_threads_enter(); /* +++ grab global mutex +++ */ gdk_pixbuf_xlib_init(Tk_Display(tree->tkwin), 0); xlib_rgb_init(Tk_Display(tree->tkwin), Tk_Screen(tree->tkwin)); gdk_threads_leave(); /* +++ release global mutex +++ */ appThemeData->pixbuf_init = 1; } Tcl_MutexUnlock(&themeMutex); #if 0 Tk_CreateClientMessageHandler(ClientMessageHandler); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_FreeWidget -- * * Performs theme-related cleanup a when a treectrl is destroyed. * * Results: * None. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { if (tree->themeData != NULL) { ckfree((char *) tree->themeData); tree->themeData = NULL; } return TCL_OK; } #if 0 static void StyleSetCallback( GtkWidget *widget, GtkStyle *previous_style, gpointer user_data) { Tcl_Interp *interp = user_data; dbwin("StyleSetCallback\n"); /* Tree_TheWorldHasChanged(interp);*/ } static int ThemeChangedObjCmd( ClientData clientData, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { if (IsGtkUnavailable() == 0) { int i; const gchar *theme_name; GtkSettings *settings = gtk_widget_get_settings(appThemeData->gtkWindow); GtkRcContext *context = settings ? settings->rc_context : NULL; if (context == NULL) return TCL_OK; g_object_get(settings, "gtk-theme-name", &theme_name, NULL); dbwin("context->theme_name %s\n", theme_name); dbwin("gtk_rc_get_theme_dir %s\n", gtk_rc_get_theme_dir()); for (i = 0; gtk_rc_get_default_files()[i] != NULL; i++) { dbwin("gtk_rc_parse %s\n", gtk_rc_get_default_files()[i]); // gtk_rc_parse(gtk_rc_get_default_files()[i]); } gtk_rc_reparse_all_for_settings(settings, TRUE); /* calls StyleSetCallback! */ } return TCL_OK; } #endif static int (*TkXErrorHandler)(Display *displayPtr, XErrorEvent *errorPtr); static int TreeCtrlErrorHandler(Display *displayPtr, XErrorEvent *errorPtr) { return TkXErrorHandler(displayPtr, errorPtr); } /* *---------------------------------------------------------------------- * * TreeTheme_InitInterp -- * * Performs theme-related initialization when the TkTreeCtrl * package is loaded into an interpreter. * * Results: * TCL_OK or TCL_ERROR, but result is ignored. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_InitInterp( Tcl_Interp *interp /* Interp that loaded TkTreeCtrl pkg. */ ) { Tcl_MutexLock(&themeMutex); if (appThemeData == NULL) { int argc = 1; char **argv = g_new0(char*, 2); argv[0] = (char *) Tcl_GetNameOfExecutable(); GtkTreeViewColumn *column; if (!g_thread_supported()) { /* Initialized Glib threads. Must be done before gdk_threads_init(). */ g_thread_init(NULL); /* Initialize Gdk threads. Should be done before gtk_init(). */ /* FIXME: it isn't ok to call this multiple times, it creates mutexes each time, could * be an embedded interp in a Gtk+ application which already called this. * Assume it hasn't been done if g_thread_init() wasn't called. */ gdk_threads_init(); } appThemeData = (TreeThemeAppData*) ckalloc(sizeof(TreeThemeAppData)); memset(appThemeData, '\0', sizeof(TreeThemeAppData)); gdk_threads_enter(); /* +++ grab global mutex +++ */ /* Gtk+ installs an X error handler which terminates the application. * Install our own error handler so we can get the Tk error handler * before Gtk+ installs its own. After initializing Gtk+ the Tk * error handler is restored. */ TkXErrorHandler = XSetErrorHandler(TreeCtrlErrorHandler); #if 0 /* This must be called before gtk_init(). */ /* FIXME: this might already have been called (from tile-gtk, or if this is an * an embedded interp in a Gtk+ application which already called gtk_init. */ gtk_disable_setlocale(); #endif appThemeData->gtk_init = gtk_init_check(&argc, &argv); g_free(argv); if (!appThemeData->gtk_init) { XSetErrorHandler(TkXErrorHandler); gdk_threads_leave(); /* +++ release global mutex +++ */ Tcl_MutexUnlock(&themeMutex); return TCL_ERROR; } appThemeData->gtkWindow = gtk_window_new(GTK_WINDOW_POPUP); gtk_widget_realize(appThemeData->gtkWindow); appThemeData->protoLayout = gtk_fixed_new(); gtk_container_add(GTK_CONTAINER(appThemeData->gtkWindow), appThemeData->protoLayout); appThemeData->gtkTreeView = gtk_tree_view_new(); gtk_container_add(GTK_CONTAINER(appThemeData->protoLayout), appThemeData->gtkTreeView); gtk_widget_realize(appThemeData->gtkTreeView); #if 0 g_signal_connect(G_OBJECT(appThemeData->gtkTreeView), "style-set", G_CALLBACK(StyleSetCallback), interp); /* FIXME: all interps, which thread */ #endif /* GTK_SHADOW_IN is default for GtkTreeView */ appThemeData->gtkArrow = gtk_arrow_new(GTK_ARROW_NONE, GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(appThemeData->protoLayout), appThemeData->gtkArrow); gtk_widget_realize(appThemeData->gtkArrow); /* Create *three* columns, and use the middle column when drawing * headers. */ column = gtk_tree_view_column_new(); gtk_tree_view_append_column(GTK_TREE_VIEW(appThemeData->gtkTreeView), column); column = gtk_tree_view_column_new(); gtk_tree_view_append_column(GTK_TREE_VIEW(appThemeData->gtkTreeView), column); appThemeData->gtkTreeHeader = column->button; column = gtk_tree_view_column_new(); gtk_tree_view_append_column(GTK_TREE_VIEW(appThemeData->gtkTreeView), column); XSetErrorHandler(TkXErrorHandler); gdk_threads_leave(); /* +++ release global mutex +++ */ } Tcl_MutexUnlock(&themeMutex); #if 0 Tcl_CreateObjCommand(interp, "gtk-theme-changed", ThemeChangedObjCmd, NULL, NULL); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_SetOptionDefault -- * * Sets the default value for an option. * * Results: * Sets the defValue field if it wasn't done already. * * Side effects: * Changes an existing option table. * *---------------------------------------------------------------------- */ void TreeTheme_SetOptionDefault( Tk_OptionSpec *specPtr ) { #ifdef TREECTRL_DEBUG if (specPtr == NULL) panic("TreeTheme_SetOptionDefault specPtr == NULL"); #endif /* Only set the default value once per-application. */ if (specPtr->defValue != NULL) return; if (!strcmp(specPtr->optionName, "-buttontracking")) specPtr->defValue = IsGtkUnavailable() ? "0" : "1"; else if (!strcmp(specPtr->optionName, "-showlines")) specPtr->defValue = IsGtkUnavailable() ? "1" : "0"; #ifdef TREECTRL_DEBUG else panic("TreeTheme_SetOptionDefault unhandled option \"%s\"", specPtr->optionName ? specPtr->optionName : "NULL"); #endif } #endif /* TREECTRL_GTK */ #ifndef TREECTRL_GTK /* *---------------------------------------------------------------------- * * TreeTheme_DrawHeaderItem -- * * Draws the background of a single column header. On Mac OS X * this also draws the sort arrow, if any. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawHeaderItem( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ int state, /* COLUMN_STATE_xxx flags. */ int arrow, /* COLUMN_ARROW_xxx flags. */ int visIndex, /* 0-based index in list of visible columns. */ int x, int y, /* Bounds of the header. */ int width, int height /* Bounds of the header. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_GetHeaderContentMargins -- * * Returns the padding inside the column header borders where * text etc may be displayed. * * Results: * TCL_OK if 'bounds' was set, TCL_ERROR otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetHeaderContentMargins( TreeCtrl *tree, /* Widget info. */ int state, /* COLUMN_STATE_xxx flags. */ int arrow, /* COLUMN_ARROW_xxx flags. */ int bounds[4] /* Returned left-top-right-bottom padding. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawHeaderArrow -- * * Draws the sort arrow in a column header. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawHeaderArrow( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ int state, /* COLUMN_STATE_xxx flags. */ int up, /* TRUE if up arrow, FALSE otherwise. */ int x, int y, /* Bounds of arrow. Width and */ int width, int height /* height are the same as that returned */ /* by TreeTheme_GetArrowSize(). */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawButton -- * * Draws a single expand/collapse item button. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawButton( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeItem item, /* Needed for animating. */ int state, /* STATE_xxx | BUTTON_STATE_xxx flags. */ int x, int y, /* Bounds of the button. Width and height */ int width, int height /* are the same as that returned by */ /* TreeTheme_GetButtonSize(). */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_GetButtonSize -- * * Returns the width and height of an expand/collapse item button. * * Results: * TCL_OK if *widthPtr and *heightPtr were set, TCL_ERROR * if themed buttons can't be drawn. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetButtonSize( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Needed on MS Windows. */ int open, /* TRUE if expanded button. */ int *widthPtr, /* Returned width of button. */ int *heightPtr /* Returned height of button. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_GetArrowSize -- * * Returns the width and height of a column header sort arrow. * * Results: * TCL_OK if *widthPtr and *heightPtr were set, TCL_ERROR * if themed sort arrows can't be drawn. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetArrowSize( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Needed on MS Windows. */ int up, /* TRUE if up arrow. */ int *widthPtr, /* Returned width of arrow. */ int *heightPtr /* Returned height of arrow. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_SetBorders -- * * Sets the TreeCtrl.inset pad values according to the needs of * the system theme. * * Results: * TCL_OK if the inset was set, TCL_ERROR if the -highlightthickness * and -borderwidth values should be used. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_SetBorders( TreeCtrl *tree /* Widget info. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawBorders -- * * Draws themed borders around the edges of the treectrl. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the Tk focus rectangle * and 3D border should be drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawBorders( TreeCtrl *tree, /* Widget info. */ Drawable drawable /* Where to draw. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_GetHeaderTextColor -- * * Returns the text fill color to display a column title with. * * Results: * TCL_OK if the *colorPtrPtr was set, TCL_ERROR if a non-theme * color should be used. * * Side effects: * May allocate a new XColor. * *---------------------------------------------------------------------- */ int TreeTheme_GetHeaderTextColor( TreeCtrl *tree, /* Widget info. */ int columnState, /* COLUMN_STATE_xxx flags. */ XColor **colorPtrPtr /* Returned text color. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_AnimateButtonStart -- * * Starts an expand/collapse item button animating from open to * closed or vice versa. * * Results: * TCL_OK. * * Side effects: * May create a new Tcl_TimerToken. * *---------------------------------------------------------------------- */ int TreeTheme_AnimateButtonStart( TreeCtrl *tree, /* Widget info. */ TreeItem item /* The item whose button should animate. */ ) { TreeItem_OpenClose(tree, item, -1); #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_ItemDeleted -- * * Cancels any item-button animation in progress. * * Results: * TCL_OK. * * Side effects: * May delete a TCL_TimerToken. * *---------------------------------------------------------------------- */ int TreeTheme_ItemDeleted( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item being deleted. */ ) { return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_Relayout -- * * This gets called when certain config options change and when * the size of the widget changes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeTheme_Relayout( TreeCtrl *tree /* Widget info. */ ) { } /* *---------------------------------------------------------------------- * * TreeTheme_IsDesktopComposited -- * * Determine if the OS windowing system is composited AKA * double-buffered. * * Results: * FALSE FALSE FALSE. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_IsDesktopComposited( TreeCtrl *tree /* Widget info. */ ) { return FALSE; } /* *---------------------------------------------------------------------- * * TreeTheme_ThemeChanged -- * * Called after the system theme changes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeTheme_ThemeChanged( TreeCtrl *tree /* Widget info. */ ) { } /* *---------------------------------------------------------------------- * * TreeTheme_InitWidget -- * * Performs theme-related initialization when a treectrl is * created. * * Results: * TCL_OK or TCL_ERROR, but result is ignored. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_InitWidget( TreeCtrl *tree /* Widget info. */ ) { return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_FreeWidget -- * * Performs theme-related cleanup a when a treectrl is destroyed. * * Results: * None. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_InitInterp -- * * Performs theme-related initialization when the TkTreeCtrl * package is loaded into an interpreter. * * Results: * TCL_OK or TCL_ERROR, but result is ignored. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_InitInterp( Tcl_Interp *interp /* Interp that loaded TkTreeCtrl pkg. */ ) { return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_SetOptionDefault -- * * Sets the default value for an option. * * Results: * Sets the defValue field if it wasn't done already. * * Side effects: * Changes an existing option table. * *---------------------------------------------------------------------- */ void TreeTheme_SetOptionDefault( Tk_OptionSpec *specPtr ) { #ifdef TREECTRL_DEBUG if (specPtr == NULL) panic("TreeTheme_SetOptionDefault specPtr == NULL"); #endif /* Only set the default value once per-application. */ if (specPtr->defValue != NULL) return; if (!strcmp(specPtr->optionName, "-buttontracking")) specPtr->defValue = "0"; else if (!strcmp(specPtr->optionName, "-showlines")) specPtr->defValue = "1"; #ifdef TREECTRL_DEBUG else panic("TreeTheme_SetOptionDefault unhandled option \"%s\"", specPtr->optionName ? specPtr->optionName : "NULL"); #endif } #endif /* not TREECTRL_GTK */ int TreeThemeCmd( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tcl_Interp *interp = tree->interp; static CONST char *commandName[] = { "platform", (char *) NULL }; enum { COMMAND_PLATFORM }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandName, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { /* T theme platform */ case COMMAND_PLATFORM: { char *platform = "X11"; #ifdef TREECTRL_GTK if (IsGtkUnavailable() == 0) platform = "gtk"; #endif Tcl_SetObjResult(interp, Tcl_NewStringObj(platform, -1)); break; } } return TCL_OK; } /*** Gradients ***/ /* *---------------------------------------------------------------------- * * Tree_HasNativeGradients -- * * Determine if this platform supports gradients natively. * * Results: * 0. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tree_HasNativeGradients( TreeCtrl *tree) { #ifdef TREECTRL_GTK return IsGtkUnavailable() == 0; #else return 0; #endif } /* *---------------------------------------------------------------------- * * TreeGradient_FillRect -- * * Paint a rectangle with a gradient. * * Results: * If the gradient has <2 stops then nothing is drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ #ifdef TREECTRL_GTK #include #define BlueDoubleFromXColorPtr(xc) (double) (((xc)->pixel & 0xFF)) / 255.0 #define GreenDoubleFromXColorPtr(xc) (double) ((((xc)->pixel >> 8) & 0xFF)) / 255.0 #define RedDoubleFromXColorPtr(xc) (double) ((((xc)->pixel >> 16) & 0xFF)) / 255.0 #endif /* TREECTRL_GTK */ void TreeGradient_FillRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr /* Rectangle to paint. */ ) { #ifdef TREECTRL_GTK cairo_t *c; cairo_surface_t *surface; cairo_pattern_t *pattern; double x1, y1, x2, y2; int i; if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (IsGtkUnavailable() || !tree->nativeGradients) { errorExit: TreeGradient_FillRectX11(tree, td, clip, gradient, trBrush, tr); return; } surface = cairo_xlib_surface_create(tree->display, td.drawable, Tk_Visual(tree->tkwin), td.width, td.height); if (surface == NULL) goto errorExit; c = cairo_create(surface); if (c == NULL) goto errorExit; x1 = trBrush.x, y1 = trBrush.y; if (gradient->vertical) { x2 = x1, y2 = y1 + trBrush.height; } else { x2 = x1 + trBrush.width, y2 = y1; } pattern = cairo_pattern_create_linear(x1, y1, x2, y2); if (pattern == NULL) goto errorExit; for (i = 0; i < gradient->stopArrPtr->nstops; i++) { GradientStop *stop = gradient->stopArrPtr->stops[i]; cairo_pattern_add_color_stop_rgba(pattern, stop->offset, RedDoubleFromXColorPtr(stop->color), GreenDoubleFromXColorPtr(stop->color), BlueDoubleFromXColorPtr(stop->color), stop->opacity); } cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_set_source(c, pattern); cairo_rectangle(c, tr.x, tr.y, tr.width, tr.height); cairo_fill(c); cairo_pattern_destroy(pattern); cairo_destroy(c); cairo_surface_destroy(surface); #else TreeGradient_FillRectX11(tree, td, clip, gradient, trBrush, tr); #endif } #ifdef TREECTRL_GTK static void MakeRectPath_Outline( cairo_t *c, /* Cairo context. */ TreeRectangle tr, /* Where to draw. */ int outlineWidth, /* Thickness of the outline. */ int open /* RECT_OPEN_x flags */ ) { double x = tr.x, y = tr.y, w = tr.width, h = tr.height; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; x += outlineWidth / 2.0, y += outlineWidth / 2.0; w -= outlineWidth, h -= outlineWidth; /* Simple case: draw all 4 edges */ if (!open) { cairo_rectangle(c, x, y, w, h); /* Complicated case: some edges are "open" */ } else { if (drawN) { cairo_move_to(c, x, y); cairo_line_to(c, x + w, y); } else if (drawE) cairo_move_to(c, x + w, y); if (drawE) cairo_line_to(c, x + w, y + h); else if (drawS) cairo_move_to(c, x + w, y + h); if (drawS) cairo_line_to(c, x, y + h); else if (drawW) cairo_move_to(c, x, y + h); if (drawW) cairo_line_to(c, x, y); } } #endif /* TREECTRL_GTK */ void TreeGradient_DrawRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to draw. */ int outlineWidth, /* Width of outline. */ int open /* RECT_OPEN_x flags */ ) { #ifdef TREECTRL_GTK cairo_t *c; cairo_surface_t *surface; cairo_pattern_t *pattern; int x1, y1, x2, y2, i; if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (IsGtkUnavailable() || !tree->nativeGradients) { errorExit: TreeGradient_DrawRectX11(tree, td, clip, gradient, trBrush, tr, outlineWidth, open); return; } surface = cairo_xlib_surface_create(tree->display, td.drawable, Tk_Visual(tree->tkwin), td.width, td.height); if (surface == NULL) goto errorExit; c = cairo_create(surface); if (c == NULL) goto errorExit; x1 = trBrush.x, y1 = trBrush.y; if (gradient->vertical) { x2 = x1, y2 = y1 + trBrush.height; } else { x2 = x1 + trBrush.width, y2 = y1; } pattern = cairo_pattern_create_linear(x1, y1, x2, y2); if (pattern == NULL) goto errorExit; for (i = 0; i < gradient->stopArrPtr->nstops; i++) { GradientStop *stop = gradient->stopArrPtr->stops[i]; cairo_pattern_add_color_stop_rgba(pattern, stop->offset, RedDoubleFromXColorPtr(stop->color), GreenDoubleFromXColorPtr(stop->color), BlueDoubleFromXColorPtr(stop->color), stop->opacity); } cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_set_source(c, pattern); cairo_set_line_width(c, outlineWidth); cairo_set_line_cap(c, CAIRO_LINE_CAP_SQUARE); MakeRectPath_Outline(c, tr, outlineWidth, open); cairo_stroke(c); cairo_pattern_destroy(pattern); cairo_destroy(c); cairo_surface_destroy(surface); #else TreeGradient_DrawRectX11(tree, td, clip, gradient, trBrush, tr, outlineWidth, open); #endif } #ifdef TREECTRL_GTK /* http://cairographics.org/cookbook/roundedrectangles/ */ #define ARC_TO_BEZIER 0.55228475 static void MakeRoundRectPath_Fill( cairo_t *c, /* Cairo context. */ TreeRectangle tr, /* Where to draw. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { double x = tr.x, y = tr.y, w = tr.width, h = tr.height; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; double c1, c2; c1 = ARC_TO_BEZIER * rx; c2 = ARC_TO_BEZIER * ry; /* Simple case: draw all 4 corners and 4 edges */ if (!open) { cairo_move_to(c, x + rx, y); cairo_rel_line_to(c, w - 2 * rx, 0.0); cairo_rel_curve_to(c, c1, 0.0, rx, c2, rx, ry); cairo_rel_line_to(c, 0, h - 2 * ry); cairo_rel_curve_to(c, 0.0, c2, c1 - rx, ry, -rx, ry); cairo_rel_line_to(c, -w + 2 * rx, 0); cairo_rel_curve_to(c, -c1, 0, -rx, -c2, -rx, -ry); cairo_rel_line_to(c, 0, -h + 2 * ry); cairo_rel_curve_to(c, 0.0, -c2, rx - c1, -ry, rx, -ry); /* Complicated case: some edges are "open" */ } else { struct {double x,y;} start[4], end[4]; /* start and end points of line segments */ #define PointMake(P,X,Y) (P).x=X,(P).y=Y PointMake(start[0], x, y); end[3] = start[0]; if (drawW && drawN) { start[0].x += rx; end[3].y += ry; } PointMake(end[0], x + w, y); start[1]= end[0]; if (drawE && drawN) { end[0].x -= rx; start[1].y += ry; } PointMake(end[1], x + w, y + h); start[2] = end[1]; if (drawE && drawS) { end[1].y -= ry; start[2].x -= rx; } PointMake(end[2], x, y + h); start[3] = end[2]; if (drawW && drawS) { end[2].x += rx; start[3].y -= ry; } #undef PointMake if (drawW && drawN) { cairo_move_to(c, x, y + ry); cairo_rel_curve_to(c, 0.0, -c2, rx - c1, -ry, rx, -ry); /* top-left */ } else { cairo_move_to(c, start[0].x, start[0].y); } cairo_line_to(c, end[0].x, end[0].y); if (drawE && drawN) cairo_rel_curve_to(c, c1, 0.0, rx, c2, rx, ry); /* top-right */ /*else CGPathMoveToPoint(p, NULL, start[1].x, start[1].y);*/ cairo_line_to(c, end[1].x, end[1].y); if (drawE && drawS) cairo_rel_curve_to(c, 0.0, c2, c1 - rx, ry, -rx, ry); /* bottom-right */ /*else CGPathMoveToPoint(p, NULL, start[2].x, start[2].y);*/ cairo_line_to(c, end[2].x, end[2].y); if (drawW && drawS) cairo_rel_curve_to(c, -c1, 0, -rx, -c2, -rx, -ry); /* bottom-left */ /*else CGPathMoveToPoint(p, NULL, start[3].x, start[3].y);*/ cairo_line_to(c, end[3].x, end[3].y); } } static void MakeRoundRectPath_Outline( cairo_t *c, /* Cairo context. */ TreeRectangle tr, /* Where to draw. */ int outlineWidth, /* Thickness of the outline. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { double x = tr.x, y = tr.y, w = tr.width, h = tr.height; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; double c1, c2; c1 = ARC_TO_BEZIER * rx; c2 = ARC_TO_BEZIER * ry; x += outlineWidth / 2.0, y += outlineWidth / 2.0; w -= outlineWidth, h -= outlineWidth; /* Simple case: draw all 4 corners and 4 edges */ if (!open) { cairo_move_to(c, x + rx, y); cairo_rel_line_to(c, w - 2 * rx, 0.0); cairo_rel_curve_to(c, c1, 0.0, rx, c2, rx, ry); cairo_rel_line_to(c, 0, h - 2 * ry); cairo_rel_curve_to(c, 0.0, c2, c1 - rx, ry, -rx, ry); cairo_rel_line_to(c, -w + 2 * rx, 0); cairo_rel_curve_to(c, -c1, 0, -rx, -c2, -rx, -ry); cairo_rel_line_to(c, 0, -h + 2 * ry); cairo_rel_curve_to(c, 0.0, -c2, rx - c1, -ry, rx, -ry); /* Complicated case: some edges are "open" */ } else { struct {double x,y;} start[4], end[4]; /* start and end points of line segments */ #define PointMake(P,X,Y) (P).x=X,(P).y=Y PointMake(start[0], x, y); end[3] = start[0]; if (drawW && drawN) { start[0].x += rx; end[3].y += ry; } PointMake(end[0], x + w, y); start[1]= end[0]; if (drawE && drawN) { end[0].x -= rx; start[1].y += ry; } PointMake(end[1], x + w, y + h); start[2] = end[1]; if (drawE && drawS) { end[1].y -= ry; start[2].x -= rx; } PointMake(end[2], x, y + h); start[3] = end[2]; if (drawW && drawS) { end[2].x += rx; start[3].y -= ry; } #undef PointMake if (drawW && drawN) { cairo_move_to(c, x, y + ry); cairo_rel_curve_to(c, 0.0, -c2, rx - c1, -ry, rx, -ry); /* top-left */ } else if (drawN) { cairo_move_to(c, start[0].x, start[0].y); } if (drawN) cairo_line_to(c, end[0].x, end[0].y); else if (drawE) cairo_move_to(c, start[1].x, start[1].y); if (drawE && drawN) cairo_rel_curve_to(c, c1, 0.0, rx, c2, rx, ry); /* top-right */ if (drawE) cairo_line_to(c, end[1].x, end[1].y); else if (drawS) cairo_move_to(c, end[1].x, end[1].y); if (drawE && drawS) cairo_rel_curve_to(c, 0.0, c2, c1 - rx, ry, -rx, ry); /* bottom-right */ if (drawS) cairo_line_to(c, end[2].x, end[2].y); else if (drawW) cairo_move_to(c, start[3].x, start[3].y); if (drawW && drawS) cairo_rel_curve_to(c, -c1, 0, -rx, -c2, -rx, -ry); /* bottom-left */ if (drawW) cairo_line_to(c, end[3].x, end[3].y); } } #endif /* TREECTRL_GTK */ void TreeGradient_FillRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Where to draw. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { #ifdef TREECTRL_GTK cairo_t *c; cairo_surface_t *surface; cairo_pattern_t *pattern; int x1, y1, x2, y2, i; #if 0 int x, y, w, h, c1, c2; #endif if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (IsGtkUnavailable() || !tree->nativeGradients) { errorExit: TreeGradient_FillRoundRectX11(tree, td, clip, gradient, trBrush, tr, rx, ry, open); return; } surface = cairo_xlib_surface_create(tree->display, td.drawable, Tk_Visual(tree->tkwin), td.width, td.height); if (surface == NULL) goto errorExit; c = cairo_create(surface); if (c == NULL) goto errorExit; x1 = trBrush.x, y1 = trBrush.y; if (gradient->vertical) { x2 = x1, y2 = y1 + trBrush.height; } else { x2 = x1 + trBrush.width, y2 = y1; } pattern = cairo_pattern_create_linear(x1, y1, x2, y2); if (pattern == NULL) goto errorExit; for (i = 0; i < gradient->stopArrPtr->nstops; i++) { GradientStop *stop = gradient->stopArrPtr->stops[i]; cairo_pattern_add_color_stop_rgba(pattern, stop->offset, RedDoubleFromXColorPtr(stop->color), GreenDoubleFromXColorPtr(stop->color), BlueDoubleFromXColorPtr(stop->color), stop->opacity); } cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_set_source(c, pattern); /* http://cairographics.org/cookbook/roundedrectangles/ */ #if 1 MakeRoundRectPath_Fill(c, tr, rx, ry, open); #else x = tr.x, y = tr.y, w = tr.width, h = tr.height; /* A****BQ */ /* H C */ /* * * */ /* G D */ /* F****E */ cairo_move_to(c,x+rx,y); /* Move to A */ cairo_line_to(c,x+w-rx,y); /* Straight line to B */ cairo_curve_to(c,x+w,y,x+w,y,x+w,y+ry); /* Curve to C, Control points are both at Q */ cairo_line_to(c,x+w,y+h-ry); /* Move to D */ cairo_curve_to(c,x+w,y+h,x+w,y+h,x+w-rx,y+h); /* Curve to E */ cairo_line_to(c,x+rx,y+h); /* Line to F */ cairo_curve_to(c,x,y+h,x,y+h,x,y+h-ry); /* Curve to G */ cairo_line_to(c,x,y+ry); /* Line to H */ cairo_curve_to(c,x,y,x,y,x+rx,y); /* Curve to A */ #endif cairo_fill(c); cairo_pattern_destroy(pattern); cairo_destroy(c); cairo_surface_destroy(surface); #else TreeGradient_FillRoundRectX11(tree, td, NULL, gradient, trBrush, tr, rx, ry, open); #endif } void Tree_DrawRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ XColor *xcolor, /* Color. */ TreeRectangle tr, /* Where to draw. */ int outlineWidth, /* Thickness of the outline. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { /* FIXME: Can use 'cairo' on Unix, but need to add it to configure + Make */ GC gc = Tk_GCForColor(xcolor, Tk_WindowId(tree->tkwin)); Tree_DrawRoundRectX11(tree, td, clip, gc, tr, outlineWidth, rx, ry, open); } void TreeGradient_DrawRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to draw. */ int outlineWidth, /* Width of outline. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { #ifdef TREECTRL_GTK cairo_t *c; cairo_surface_t *surface; cairo_pattern_t *pattern; int x1, y1, x2, y2, i; XColor *xcolor; GC gc; if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (IsGtkUnavailable() || !tree->nativeGradients) { errorExit: xcolor = gradient->stopArrPtr->stops[0]->color; /* Use the first stop color */ gc = Tk_GCForColor(xcolor, Tk_WindowId(tree->tkwin)); Tree_DrawRoundRectX11(tree, td, clip, gc, tr, outlineWidth, rx, ry, open); return; } surface = cairo_xlib_surface_create(tree->display, td.drawable, Tk_Visual(tree->tkwin), td.width, td.height); if (surface == NULL) goto errorExit; c = cairo_create(surface); if (c == NULL) goto errorExit; x1 = trBrush.x, y1 = trBrush.y; if (gradient->vertical) { x2 = x1, y2 = y1 + trBrush.height; } else { x2 = x1 + trBrush.width, y2 = y1; } pattern = cairo_pattern_create_linear(x1, y1, x2, y2); if (pattern == NULL) goto errorExit; for (i = 0; i < gradient->stopArrPtr->nstops; i++) { GradientStop *stop = gradient->stopArrPtr->stops[i]; cairo_pattern_add_color_stop_rgba(pattern, stop->offset, RedDoubleFromXColorPtr(stop->color), GreenDoubleFromXColorPtr(stop->color), BlueDoubleFromXColorPtr(stop->color), stop->opacity); } cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_set_source(c, pattern); cairo_set_line_width(c, outlineWidth); cairo_set_line_cap(c, CAIRO_LINE_CAP_SQUARE); /* http://cairographics.org/cookbook/roundedrectangles/ */ MakeRoundRectPath_Outline(c, tr, outlineWidth, rx, ry, open); cairo_stroke(c); cairo_pattern_destroy(pattern); cairo_destroy(c); cairo_surface_destroy(surface); #else XColor *xcolor; GC gc; if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; xcolor = gradient->stopArrPtr->stops[0]->color; /* Use the first stop color */ gc = Tk_GCForColor(xcolor, Tk_WindowId(tree->tkwin)); Tree_DrawRoundRectX11(tree, td, clip, gc, tr, outlineWidth, rx, ry, open); #endif } void Tree_FillRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ XColor *xcolor, /* Color. */ TreeRectangle tr, /* Where to draw. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { /* FIXME: Can use 'cairo' on Unix, but need to add it to configure + Make */ GC gc = Tk_GCForColor(xcolor, Tk_WindowId(tree->tkwin)); Tree_FillRoundRectX11(tree, td, clip, gc, tr, rx, ry, open); } int TreeDraw_InitInterp( Tcl_Interp *interp ) { return TCL_OK; } tktreectrl-2.4.1/win/0000755000076400010400000000000011646706172015022 5ustar TimAdministratorstktreectrl-2.4.1/win/tkWinTree.c0000644000076400010400000031560411570331572017105 0ustar TimAdministrators/* * tkWinTree.c -- * * Platform-specific parts of TkTreeCtrl for Microsoft Windows. * * Copyright (c) 2010-2011 Tim Baker */ #define WINVER 0x0501 /* MingW32 */ #define _WIN32_WINNT 0x0501 /* ACTCTX stuff */ #include "tkTreeCtrl.h" #include "tkWinInt.h" /* *---------------------------------------------------------------------- * * Tree_HDotLine -- * * Draws a horizontal 1-pixel-tall dotted line. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_HDotLine( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ int x1, int y1, int x2 /* Left, top and right coordinates. */ ) { TkWinDCState state; HDC dc; HPEN pen, oldPen; int nw; int wx = x1 + tree->drawableXOrigin; int wy = y1 + tree->drawableYOrigin; dc = TkWinGetDrawableDC(tree->display, drawable, &state); SetROP2(dc, R2_COPYPEN); pen = CreatePen(PS_SOLID, 1, tree->lineGC[0]->foreground); oldPen = SelectObject(dc, pen); nw = !(wx & 1) == !(wy & 1); for (x1 += !nw; x1 < x2; x1 += 2) { MoveToEx(dc, x1, y1, NULL); LineTo(dc, x1 + 1, y1); } SelectObject(dc, oldPen); DeleteObject(pen); TkWinReleaseDrawableDC(drawable, dc, &state); } /* *---------------------------------------------------------------------- * * Tree_VDotLine -- * * Draws a vertical 1-pixel-wide dotted line. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_VDotLine( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ int x1, int y1, int y2) /* Left, top, and bottom coordinates. */ { TkWinDCState state; HDC dc; HPEN pen, oldPen; int nw; int wx = x1 + tree->drawableXOrigin; int wy = y1 + tree->drawableYOrigin; dc = TkWinGetDrawableDC(tree->display, drawable, &state); SetROP2(dc, R2_COPYPEN); pen = CreatePen(PS_SOLID, 1, tree->lineGC[0]->foreground); oldPen = SelectObject(dc, pen); nw = !(wx & 1) == !(wy & 1); for (y1 += !nw; y1 < y2; y1 += 2) { MoveToEx(dc, x1, y1, NULL); LineTo(dc, x1 + 1, y1); } SelectObject(dc, oldPen); DeleteObject(pen); TkWinReleaseDrawableDC(drawable, dc, &state); } /* *---------------------------------------------------------------------- * * Tree_DrawActiveOutline -- * * Draws 0 or more sides of a rectangle, dot-on dot-off, XOR style. * This is used by rectangle Elements to indicate the "active" * item. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_DrawActiveOutline( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ int x, int y, /* Left and top coordinates. */ int width, int height, /* Size of rectangle. */ int open /* RECT_OPEN_x flags */ ) { int wx = x + tree->drawableXOrigin; int wy = y + tree->drawableYOrigin; int w = !(open & RECT_OPEN_W); int n = !(open & RECT_OPEN_N); int e = !(open & RECT_OPEN_E); int s = !(open & RECT_OPEN_S); int nw, ne, sw, se; int i; TkWinDCState state; HDC dc; /* Dots on even pixels only */ nw = !(wx & 1) == !(wy & 1); ne = !((wx + width - 1) & 1) == !(wy & 1); sw = !(wx & 1) == !((wy + height - 1) & 1); se = !((wx + width - 1) & 1) == !((wy + height - 1) & 1); dc = TkWinGetDrawableDC(tree->display, drawable, &state); SetROP2(dc, R2_NOT); if (w) /* left */ { for (i = !nw; i < height; i += 2) { MoveToEx(dc, x, y + i, NULL); LineTo(dc, x + 1, y + i); } } if (n) /* top */ { for (i = nw ? w * 2 : 1; i < width; i += 2) { MoveToEx(dc, x + i, y, NULL); LineTo(dc, x + i + 1, y); } } if (e) /* right */ { for (i = ne ? n * 2 : 1; i < height; i += 2) { MoveToEx(dc, x + width - 1, y + i, NULL); LineTo(dc, x + width, y + i); } } if (s) /* bottom */ { for (i = sw ? w * 2 : 1; i < width - (se && e); i += 2) { MoveToEx(dc, x + i, y + height - 1, NULL); LineTo(dc, x + i + 1, y + height - 1); } } TkWinReleaseDrawableDC(drawable, dc, &state); } /* * The following structure is used when drawing a number of dotted XOR * rectangles. */ struct DotStatePriv { TreeCtrl *tree; Drawable drawable; HDC dc; TkWinDCState dcState; HRGN rgn; }; /* *---------------------------------------------------------------------- * * TreeDotRect_Setup -- * * Prepare a drawable for drawing a series of dotted XOR rectangles. * * Results: * State info is returned to be used by the other TreeDotRect_xxx() * procedures. * * Side effects: * On Win32 and OSX the device context/graphics port is altered * in preparation for drawing. On X11 a new graphics context is * created. * *---------------------------------------------------------------------- */ void TreeDotRect_Setup( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ DotState *p /* Where to save state info. */ ) { struct DotStatePriv *dotState = (struct DotStatePriv *) p; if (sizeof(*dotState) > sizeof(*p)) panic("TreeDotRect_Setup: DotState hack is too small"); dotState->tree = tree; dotState->drawable = drawable; dotState->dc = TkWinGetDrawableDC(tree->display, drawable, &dotState->dcState); /* XOR drawing */ SetROP2(dotState->dc, R2_NOT); /* Keep drawing inside the contentbox. */ dotState->rgn = CreateRectRgn( Tree_ContentLeft(tree), Tree_ContentTop(tree), Tree_ContentRight(tree), Tree_ContentBottom(tree)); SelectClipRgn(dotState->dc, dotState->rgn); } /* *---------------------------------------------------------------------- * * TreeDotRect_Draw -- * * Draw a dotted XOR rectangle. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void TreeDotRect_Draw( DotState *p, /* Info returned by TreeDotRect_Setup(). */ int x, int y, /* Left and top coordinates. */ int width, int height /* Size of rectangle. */ ) { struct DotStatePriv *dotState = (struct DotStatePriv *) p; #if 1 RECT rect; rect.left = x; rect.right = x + width; rect.top = y; rect.bottom = y + height; DrawFocusRect(dotState->dc, &rect); #else HDC dc = dotState->dc; int i; int wx = x + dotState->tree->drawableXOrigin; int wy = y + dotState->tree->drawableYOrigin; int nw, ne, sw, se; /* Dots on even pixels only */ nw = !(wx & 1) == !(wy & 1); ne = !((wx + width - 1) & 1) == !(wy & 1); sw = !(wx & 1) == !((wy + height - 1) & 1); se = !((wx + width - 1) & 1) == !((wy + height - 1) & 1); for (i = !nw; i < height; i += 2) { MoveToEx(dc, x, y + i, NULL); LineTo(dc, x + 1, y + i); } for (i = nw ? 2 : 1; i < width; i += 2) { MoveToEx(dc, x + i, y, NULL); LineTo(dc, x + i + 1, y); } for (i = ne ? 2 : 1; i < height; i += 2) { MoveToEx(dc, x + width - 1, y + i, NULL); LineTo(dc, x + width, y + i); } for (i = sw ? 2 : 1; i < width - se; i += 2) { MoveToEx(dc, x + i, y + height - 1, NULL); LineTo(dc, x + i + 1, y + height - 1); } #endif } /* *---------------------------------------------------------------------- * * TreeDotRect_Restore -- * * Restore the drawing environment. * * Results: * None. * * Side effects: * On Win32 and OSX the device context/graphics port is restored. * On X11 a new graphics context is freed. * *---------------------------------------------------------------------- */ void TreeDotRect_Restore( DotState *p /* Info returned by TreeDotRect_Setup(). */ ) { struct DotStatePriv *dotState = (struct DotStatePriv *) p; SelectClipRgn(dotState->dc, NULL); DeleteObject(dotState->rgn); TkWinReleaseDrawableDC(dotState->drawable, dotState->dc, &dotState->dcState); } /* *---------------------------------------------------------------------- * * Tree_FillRegion -- * * Paint a region with the foreground color of a graphics context. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_FillRegion( Display *display, /* Display. */ Drawable drawable, /* Where to draw. */ GC gc, /* Foreground color. */ TkRegion rgn /* Region to paint. */ ) { HDC dc; TkWinDCState dcState; HBRUSH brush; dc = TkWinGetDrawableDC(display, drawable, &dcState); SetROP2(dc, R2_COPYPEN); brush = CreateSolidBrush(gc->foreground); FillRgn(dc, (HRGN) rgn, brush); DeleteObject(brush); TkWinReleaseDrawableDC(drawable, dc, &dcState); } /* *---------------------------------------------------------------------- * * Tree_OffsetRegion -- * * Offset a region. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_OffsetRegion( TkRegion region, /* Region to modify. */ int xOffset, int yOffset /* Horizontal and vertical offsets. */ ) { OffsetRgn((HRGN) region, xOffset, yOffset); } /* *---------------------------------------------------------------------- * * Tree_UnionRegion -- * * Compute the union of 2 regions. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_UnionRegion( TkRegion rgnA, TkRegion rgnB, TkRegion rgnOut ) { CombineRgn((HRGN) rgnA, (HRGN) rgnB, (HRGN) rgnOut, RGN_OR); } /* *---------------------------------------------------------------------- * * Tree_ScrollWindow -- * * Wrapper around TkScrollWindow() to fix an apparent bug with the * Mac/OSX versions. * * Results: * None. * * Side effects: * Stuff is scrolled in a drawable. * *---------------------------------------------------------------------- */ int Tree_ScrollWindow( TreeCtrl *tree, /* Widget info. */ GC gc, /* Arg to TkScrollWindow(). */ int x, int y, /* Arg to TkScrollWindow(). */ int width, int height, /* Arg to TkScrollWindow(). */ int dx, int dy, /* Arg to TkScrollWindow(). */ TkRegion damageRgn /* Arg to TkScrollWindow(). */ ) { #if 0 /* It would be best to call ScrollWindowEx with SW_SCROLLCHILDREN so * that windows in window elements scroll smoothly with a minimum of * redrawing. */ HWND hwnd = TkWinGetHWND(Tk_WindowId(tree->tkwin)); HWND hwndChild; RECT scrollRect, childRect; struct { int x; int y; TkWindow *winPtr; } winInfo[128], *winInfoPtr; TkWindow *winPtr = (TkWindow *) tree->tkwin; int winCount = 0; int result; winInfoPtr = winInfo; for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) { if (winPtr->window != None) { hwndChild = TkWinGetHWND(winPtr->window); GetWindowRect(hwndChild, &childRect); winInfoPtr->x = childRect.left; winInfoPtr->y = childRect.top; winInfoPtr->winPtr = winPtr; winInfoPtr++; winCount++; } } scrollRect.left = x; scrollRect.top = y; scrollRect.right = x + width; scrollRect.bottom = y + height; result = (ScrollWindowEx(hwnd, dx, dy, &scrollRect, NULL, (HRGN) damageRgn, NULL, SW_SCROLLCHILDREN) == NULLREGION) ? 0 : 1; winInfoPtr = winInfo; while (winCount--) { winPtr = winInfoPtr->winPtr; hwndChild = TkWinGetHWND(winPtr->window); GetWindowRect(hwndChild, &childRect); if (childRect.left != winInfoPtr->x || childRect.top != winInfoPtr->y) { dbwin("moved window %s %d,%d\n", winPtr->pathName, childRect.left - winInfoPtr->x, childRect.top - winInfoPtr->y); winPtr->changes.x += childRect.left - winInfoPtr->x; winPtr->changes.y += childRect.top - winInfoPtr->y; /* TkDoConfigureNotify(winPtr); */ } winInfoPtr++; } #else int result = TkScrollWindow(tree->tkwin, gc, x, y, width, height, dx, dy, damageRgn); #endif return result; } /* *---------------------------------------------------------------------- * * Tree_UnsetClipMask -- * * Wrapper around XSetClipMask(). On Win32 Tk_DrawChars() does * not clear the clipping region. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Tree_UnsetClipMask( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Where to draw. */ GC gc /* Graphics context to modify. */ ) { XSetClipMask(tree->display, gc, None); /* Tk_DrawChars does not clear the clip region */ if (drawable == Tk_WindowId(tree->tkwin)) { HDC dc; TkWinDCState dcState; dc = TkWinGetDrawableDC(tree->display, drawable, &dcState); SelectClipRgn(dc, NULL); TkWinReleaseDrawableDC(drawable, dc, &dcState); } } /* *---------------------------------------------------------------------- * * Tree_DrawBitmapWithGC -- * * Draw part of a bitmap. * * Results: * None. * * Side effects: * Stuff is drawn. * *---------------------------------------------------------------------- */ void Tree_DrawBitmapWithGC( TreeCtrl *tree, /* Widget info. */ Pixmap bitmap, /* Bitmap to draw. */ Drawable drawable, /* Where to draw. */ GC gc, /* Graphics context. */ int src_x, int src_y, /* Left and top of part of bitmap to copy. */ int width, int height, /* Width and height of part of bitmap to * copy. */ int dest_x, int dest_y /* Left and top coordinates to copy part of * the bitmap to. */ ) { TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask; XSetClipOrigin(tree->display, gc, dest_x, dest_y); /* * It seems as though the device context is not set up properly * when drawing a transparent bitmap into a window. Normally Tk draws * into an offscreen pixmap which gets a temporary device context. * This fixes a bug with -doublebuffer none in the demo "Bitmaps". */ if (drawable == Tk_WindowId(tree->tkwin)) { if ((clipPtr != NULL) && (clipPtr->type == TKP_CLIP_PIXMAP) && (clipPtr->value.pixmap == bitmap)) { HDC dc; TkWinDCState dcState; dc = TkWinGetDrawableDC(tree->display, drawable, &dcState); SetTextColor(dc, RGB(0,0,0)); SetBkColor(dc, RGB(255,255,255)); TkWinReleaseDrawableDC(drawable, dc, &dcState); } } XCopyPlane(tree->display, bitmap, drawable, gc, src_x, src_y, (unsigned int) width, (unsigned int) height, dest_x, dest_y, 1); XSetClipOrigin(tree->display, gc, 0, 0); } /* * TIP #116 altered Tk_PhotoPutBlock API to add interp arg. * We need to remove that for compiling with 8.4. */ #if (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 5) #define TK_PHOTOPUTBLOCK(interp, hdl, blk, x, y, w, h, cr) \ Tk_PhotoPutBlock(hdl, blk, x, y, w, h, cr) #define TK_PHOTOPUTZOOMEDBLOCK(interp, hdl, blk, x, y, w, h, \ zx, zy, sx, sy, cr) \ Tk_PhotoPutZoomedBlock(hdl, blk, x, y, w, h, \ zx, zy, sx, sy, cr) #else #define TK_PHOTOPUTBLOCK Tk_PhotoPutBlock #define TK_PHOTOPUTZOOMEDBLOCK Tk_PhotoPutZoomedBlock #endif /* *---------------------------------------------------------------------- * * Tree_XImage2Photo -- * * Copy pixels from an XImage to a Tk photo image. * * Results: * None. * * Side effects: * The given photo image is blanked and all the pixels from the * XImage are put into the photo image. * *---------------------------------------------------------------------- */ void Tree_XImage2Photo( Tcl_Interp *interp, /* Current interpreter. */ Tk_PhotoHandle photoH, /* Existing photo image. */ XImage *ximage, /* XImage to copy pixels from. */ unsigned long trans, /* Pixel value in ximage that should be * considered transparent. */ int alpha /* Desired transparency of photo image.*/ ) { Tk_PhotoImageBlock photoBlock; unsigned char *pixelPtr; int x, y, w = ximage->width, h = ximage->height; Tk_PhotoBlank(photoH); /* See TkPoscriptImage */ pixelPtr = (unsigned char *) Tcl_Alloc(ximage->width * ximage->height * 4); photoBlock.pixelPtr = pixelPtr; photoBlock.width = ximage->width; photoBlock.height = ximage->height; photoBlock.pitch = ximage->width * 4; photoBlock.pixelSize = 4; photoBlock.offset[0] = 0; photoBlock.offset[1] = 1; photoBlock.offset[2] = 2; photoBlock.offset[3] = 3; for (y = 0; y < ximage->height; y++) { for (x = 0; x < ximage->width; x++) { int r, g, b; unsigned long pixel; /* FIXME: I think this blows up on classic Mac??? */ pixel = XGetPixel(ximage, x, y); /* Set alpha=0 for transparent pixel in the source XImage */ if (trans != 0 && pixel == trans) { pixelPtr[y * photoBlock.pitch + x * 4 + 3] = 0; continue; } r = GetRValue(pixel); g = GetGValue(pixel); b = GetBValue(pixel); pixelPtr[y * photoBlock.pitch + x * 4 + 0] = r; pixelPtr[y * photoBlock.pitch + x * 4 + 1] = g; pixelPtr[y * photoBlock.pitch + x * 4 + 2] = b; pixelPtr[y * photoBlock.pitch + x * 4 + 3] = alpha; } } TK_PHOTOPUTBLOCK(interp, photoH, &photoBlock, 0, 0, w, h, TK_PHOTO_COMPOSITE_SET); Tcl_Free((char *) pixelPtr); } typedef struct { TreeCtrl *tree; TreeClip *clip; HDC dc; TkRegion region; } TreeClipStateDC; static void TreeClip_ToDC( TreeCtrl *tree, /* Widget info. */ TreeClip *clip, /* Clipping area or NULL. */ HDC dc, /* Windows device context. */ TreeClipStateDC *state ) { state->tree = tree; state->clip = clip; state->dc = dc; state->region = None; if (clip && clip->type == TREE_CLIP_RECT) { state->region = Tree_GetRectRegion(tree, &clip->tr); SelectClipRgn(dc, (HRGN) state->region); } if (clip && clip->type == TREE_CLIP_AREA) { TreeRectangle tr; if (Tree_AreaBbox(tree, clip->area, &tr) == 0) return; state->region = Tree_GetRectRegion(tree, &tr); SelectClipRgn(dc, (HRGN) state->region); } if (clip && clip->type == TREE_CLIP_REGION) { SelectClipRgn(dc, (HRGN) clip->region); } } static void TreeClip_FinishDC( TreeClipStateDC *state ) { SelectClipRgn(state->dc, NULL); if (state->region != NULL) Tree_FreeRegion(state->tree, state->region); } #if USE_ITEM_PIXMAP == 0 /* *---------------------------------------------------------------------- * * DrawOrFillArc -- * Copied from tkTwinDraw.c because the clip region is ignored on * Win32. * * This function handles the rendering of drawn or filled arcs and * chords. * * Results: * None. * * Side effects: * Renders the requested arc. * *---------------------------------------------------------------------- */ /* * These macros convert between X's bizarre angle units to radians. */ #define PI 3.14159265358979 #define XAngleToRadians(a) ((double)(a) / 64 * PI / 180); static void DrawOrFillArc( TreeCtrl *tree, /* Widget info. */ Drawable d, TreeClip *clip, /* Clipping area or NULL. */ GC gc, int x, int y, /* left top */ unsigned int width, unsigned int height, int start, /* start: three-o'clock (deg*64) */ int extent, /* extent: relative (deg*64) */ int fill) /* ==0 draw, !=0 fill */ { HDC dc; HBRUSH brush, oldBrush; HPEN pen, oldPen; TkWinDCState state; TreeClipStateDC clipState; int clockwise = (extent < 0); /* non-zero if clockwise */ int xstart, ystart, xend, yend; double radian_start, radian_end, xr, yr; if (d == None) { return; } dc = TkWinGetDrawableDC(tree->display, d, &state); TreeClip_ToDC(tree, clip, dc, &clipState); /* SetROP2(dc, tkpWinRopModes[gc->function]);*/ /* * Compute the absolute starting and ending angles in normalized radians. * Swap the start and end if drawing clockwise. */ start = start % (64*360); if (start < 0) { start += (64*360); } extent = (start+extent) % (64*360); if (extent < 0) { extent += (64*360); } if (clockwise) { int tmp = start; start = extent; extent = tmp; } radian_start = XAngleToRadians(start); radian_end = XAngleToRadians(extent); /* * Now compute points on the radial lines that define the starting and * ending angles. Be sure to take into account that the y-coordinate * system is inverted. */ xr = x + width / 2.0; yr = y + height / 2.0; xstart = (int)((xr + cos(radian_start)*width/2.0) + 0.5); ystart = (int)((yr + sin(-radian_start)*height/2.0) + 0.5); xend = (int)((xr + cos(radian_end)*width/2.0) + 0.5); yend = (int)((yr + sin(-radian_end)*height/2.0) + 0.5); /* * Now draw a filled or open figure. Note that we have to increase the * size of the bounding box by one to account for the difference in pixel * definitions between X and Windows. */ pen = CreatePen((int) PS_SOLID, gc->line_width, gc->foreground); oldPen = SelectObject(dc, pen); if (!fill) { /* * Note that this call will leave a gap of one pixel at the end of the * arc for thin arcs. We can't use ArcTo because it's only supported * under Windows NT. */ SetBkMode(dc, TRANSPARENT); Arc(dc, x, y, (int) (x+width+1), (int) (y+height+1), xstart, ystart, xend, yend); } else { brush = CreateSolidBrush(gc->foreground); oldBrush = SelectObject(dc, brush); if (gc->arc_mode == ArcChord) { Chord(dc, x, y, (int) (x+width+1), (int) (y+height+1), xstart, ystart, xend, yend); } else if (gc->arc_mode == ArcPieSlice) { Pie(dc, x, y, (int) (x+width+1), (int) (y+height+1), xstart, ystart, xend, yend); } DeleteObject(SelectObject(dc, oldBrush)); } DeleteObject(SelectObject(dc, oldPen)); TreeClip_FinishDC(&clipState); TkWinReleaseDrawableDC(d, dc, &state); } /* *---------------------------------------------------------------------- * * Tree_DrawArc -- * * Wrapper around XDrawArc() because the clip region is * ignored on Win32. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ void Tree_DrawArc( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ GC gc, int x, int y, unsigned int width, unsigned int height, int start, int extent) { tree->display->request++; DrawOrFillArc(tree, td.drawable, clip, gc, x, y, width, height, start, extent, 0); } /* *---------------------------------------------------------------------- * * Tree_FillArc -- * * Wrapper around XFillArc() because the clip region is * ignored on Win32. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ void Tree_FillArc( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ GC gc, int x, int y, unsigned int width, unsigned int height, int start, int extent) { tree->display->request++; DrawOrFillArc(tree, td.drawable, clip, gc, x, y, width, height, start, extent, 1); } #endif /* USE_ITEM_PIXMAP == 0 */ /* *---------------------------------------------------------------------- * * Tree_FillRectangle -- * * Wrapper around XFillRectangle() because the clip region is * ignored on Win32. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ void Tree_FillRectangle( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ GC gc, /* Graphics context. */ TreeRectangle tr /* Rectangle to paint. */ ) { #if 1 HDC dc; TkWinDCState dcState; TreeClipStateDC clipState; RECT rect; COLORREF oldColor; dc = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); TreeClip_ToDC(tree, clip, dc, &clipState); rect.left = tr.x, rect.top = tr.y, rect.right = tr.x + tr.width, rect.bottom = tr.y + tr.height; oldColor = SetBkColor(dc, (COLORREF)gc->foreground); SetBkMode(dc, OPAQUE); ExtTextOut(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); SetBkColor(dc, oldColor); TreeClip_FinishDC(&clipState); TkWinReleaseDrawableDC(td.drawable, dc, &dcState); #else HDC dc; TkWinDCState dcState; HBRUSH brush; RECT rect; TreeClipStateDC clipState; dc = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); TreeClip_ToDC(tree, clip, dc, &clipState); brush = CreateSolidBrush(gc->foreground); rect.left = tr.x, rect.top = tr.y, rect.right = tr.x + tr.width, rect.bottom = tr.y + tr.height; FillRect(dc, &rect, brush); TreeClip_FinishDC(&clipState); DeleteObject(brush); TkWinReleaseDrawableDC(td.drawable, dc, &dcState); #endif } #if USE_ITEM_PIXMAP == 0 static void FastFillRect( HDC dc, int x, int y, int width, int height, COLORREF pixel ) { RECT rect; COLORREF oldColor; rect.left = x, rect.top = y, rect.right = x + width, rect.bottom = y + height; oldColor = SetBkColor(dc, pixel); SetBkMode(dc, OPAQUE); ExtTextOut(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); SetBkColor(dc, oldColor); } static void _3DVerticalBevel( HDC dc, Tk_Window tkwin, /* Window for which border was allocated. */ Tk_3DBorder border, /* Token for border to draw. */ int x, int y, int width, int height, /* Area of vertical bevel. */ int leftBevel, /* Non-zero means this bevel forms the left * side of the object; 0 means it forms the * right side. */ int relief) /* Kind of bevel to draw. For example, * TK_RELIEF_RAISED means interior of object * should appear higher than exterior. */ { COLORREF left, right; int half; switch (relief) { case TK_RELIEF_RAISED: left = (leftBevel) ? TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT_GC) : TkWinGetBorderPixels(tkwin, border, TK_3D_DARK_GC); right = (leftBevel) ? TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT2) : TkWinGetBorderPixels(tkwin, border, TK_3D_DARK2); break; case TK_RELIEF_SUNKEN: left = (leftBevel) ? TkWinGetBorderPixels(tkwin, border, TK_3D_DARK_GC) : TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT2); right = (leftBevel) ? TkWinGetBorderPixels(tkwin, border, TK_3D_DARK2) : TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT_GC); break; case TK_RELIEF_RIDGE: left = TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT_GC); right = TkWinGetBorderPixels(tkwin, border, TK_3D_DARK_GC); break; case TK_RELIEF_GROOVE: left = TkWinGetBorderPixels(tkwin, border, TK_3D_DARK_GC); right = TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT_GC); break; case TK_RELIEF_FLAT: left = right = TkWinGetBorderPixels(tkwin, border, TK_3D_FLAT_GC); break; case TK_RELIEF_SOLID: default: left = right = RGB(0,0,0); break; } half = width/2; if (leftBevel && (width & 1)) { half++; } FastFillRect(dc, x, y, half, height, left); FastFillRect(dc, x+half, y, width-half, height, right); } static void _3DHorizontalBevel( HDC dc, Tk_Window tkwin, /* Window for which border was allocated. */ Tk_3DBorder border, /* Token for border to draw. */ int x, int y, int width, int height, /* Bounding box of area of bevel. Height gives * width of border. */ int leftIn, int rightIn, /* Describes whether the left and right edges * of the bevel angle in or out as they go * down. For example, if "leftIn" is true, the * left side of the bevel looks like this: * ___________ * __________ * _________ * ________ */ int topBevel, /* Non-zero means this bevel forms the top * side of the object; 0 means it forms the * bottom side. */ int relief) /* Kind of bevel to draw. For example, * TK_RELIEF_RAISED means interior of object * should appear higher than exterior. */ { int bottom, halfway, x1, x2, x1Delta, x2Delta; int topColor, bottomColor; switch (relief) { case TK_RELIEF_RAISED: topColor = (topBevel) ? TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT_GC) : TkWinGetBorderPixels(tkwin, border, TK_3D_DARK_GC); bottomColor = (topBevel) ? TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT2) : TkWinGetBorderPixels(tkwin, border, TK_3D_DARK2); break; case TK_RELIEF_SUNKEN: topColor = (topBevel) ? TkWinGetBorderPixels(tkwin, border, TK_3D_DARK_GC) : TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT2); bottomColor = (topBevel) ? TkWinGetBorderPixels(tkwin, border, TK_3D_DARK2) : TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT_GC); break; case TK_RELIEF_RIDGE: topColor = TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT_GC); bottomColor = TkWinGetBorderPixels(tkwin, border, TK_3D_DARK_GC); break; case TK_RELIEF_GROOVE: topColor = TkWinGetBorderPixels(tkwin, border, TK_3D_DARK_GC); bottomColor = TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT_GC); break; case TK_RELIEF_FLAT: topColor = bottomColor = TkWinGetBorderPixels(tkwin, border, TK_3D_FLAT_GC); break; case TK_RELIEF_SOLID: default: topColor = bottomColor = RGB(0,0,0); } if (leftIn) { x1 = x+1; } else { x1 = x+height-1; } x2 = x+width; if (rightIn) { x2--; } else { x2 -= height; } x1Delta = (leftIn) ? 1 : -1; x2Delta = (rightIn) ? -1 : 1; halfway = y + height/2; if (topBevel && (height & 1)) { halfway++; } bottom = y + height; for ( ; y < bottom; y++) { if (x1 < x2) { FastFillRect(dc, x1, y, x2-x1, 1, (y < halfway) ? topColor : bottomColor); } x1 += x1Delta; x2 += x2Delta; } } /* *---------------------------------------------------------------------- * * Tree_Draw3DRectangle -- * * Reimplementation of Tk_Draw3DRectangle() because the clip * region is ignored on Win32. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ void Tree_Draw3DRectangle( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ Tk_3DBorder border, /* Token for border to draw. */ int x, int y, int width, int height, /* Outside area of region in which border will * be drawn. */ int borderWidth, /* Desired width for border, in pixels. */ int relief /* Type of relief: TK_RELIEF_RAISED, * TK_RELIEF_SUNKEN, TK_RELIEF_GROOVE, etc. */ ) { Tk_Window tkwin = tree->tkwin; HDC dc; TkWinDCState dcState; TreeClipStateDC clipState; dc = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); TreeClip_ToDC(tree, clip, dc, &clipState); if (width < 2*borderWidth) { borderWidth = width/2; } if (height < 2*borderWidth) { borderWidth = height/2; } _3DVerticalBevel(dc, tkwin, border, x, y, borderWidth, height, 1, relief); _3DVerticalBevel(dc, tkwin, border, x+width-borderWidth, y, borderWidth, height, 0, relief); _3DHorizontalBevel(dc, tkwin, border, x, y, width, borderWidth, 1, 1, 1, relief); _3DHorizontalBevel(dc, tkwin, border, x, y+height-borderWidth, width, borderWidth, 0, 0, 0, relief); TreeClip_FinishDC(&clipState); TkWinReleaseDrawableDC(td.drawable, dc, &dcState); } /* *---------------------------------------------------------------------- * * Tree_Fill3DRectangle -- * * Reimplementation of Tree_Fill3DRectangle() because the clip * region is ignored on Win32. * * Results: * None. * * Side effects: * Draws onto the specified drawable. * *---------------------------------------------------------------------- */ void Tree_Fill3DRectangle( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ Tk_3DBorder border, /* Token for border to draw. */ int x, int y, int width, int height, /* Outside area of rectangular region. */ int borderWidth, /* Desired width for border, in pixels. Border * will be *inside* region. */ int relief /* Indicates 3D effect: TK_RELIEF_FLAT, * TK_RELIEF_RAISED, or TK_RELIEF_SUNKEN. */ ) { Tk_Window tkwin = tree->tkwin; HDC dc; TkWinDCState dcState; TreeClipStateDC clipState; int doubleBorder; dc = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); TreeClip_ToDC(tree, clip, dc, &clipState); if (relief == TK_RELIEF_FLAT) { borderWidth = 0; } else { if (width < 2*borderWidth) { borderWidth = width/2; } if (height < 2*borderWidth) { borderWidth = height/2; } } doubleBorder = 2*borderWidth; if ((width > doubleBorder) && (height > doubleBorder)) { FastFillRect(dc, x + borderWidth, y + borderWidth, (unsigned int) (width - doubleBorder), (unsigned int) (height - doubleBorder), TkWinGetBorderPixels(tkwin, border, TK_3D_FLAT_GC)); } TreeClip_FinishDC(&clipState); TkWinReleaseDrawableDC(td.drawable, dc, &dcState); if (borderWidth) { Tree_Draw3DRectangle(tree, td, clip, border, x, y, width, height, borderWidth, relief); } } #endif /* USE_ITEM_PIXMAP == 0 */ /*** Themes ***/ #include #ifdef __MINGW32__ #include #else /* __MING32__ */ /* is part of the Windows SDK but not the Platform SDK. */ /*#include */ #ifndef HP_HEADERITEM #define HP_HEADERITEM 1 #define HIS_NORMAL 1 #define HIS_HOT 2 #define HIS_PRESSED 3 #define TVP_GLYPH 2 #define TVP_HOTGLYPH 4 #define GLPS_CLOSED 1 #define GLPS_OPENED 2 #define HGLPS_CLOSED 1 #define HGLPS_OPENED 2 #endif /* HP_HEADERITEM */ #endif /* __MING32__ */ #include #include /* MingW32 */ #ifdef __MINGW32__ /* vsstyle.h */ #define TVP_HOTGLYPH 4 #define HGLPS_CLOSED 1 #define HGLPS_OPENED 2 #endif #ifndef TMT_CONTENTMARGINS #define TMT_CONTENTMARGINS 3602 #endif typedef HTHEME (STDAPICALLTYPE OpenThemeDataProc)(HWND hwnd, LPCWSTR pszClassList); typedef HRESULT (STDAPICALLTYPE CloseThemeDataProc)(HTHEME hTheme); typedef HRESULT (STDAPICALLTYPE DrawThemeBackgroundProc)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect); typedef HRESULT (STDAPICALLTYPE DrawThemeBackgroundExProc)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, DTBGOPTS *PDTBGOPTS); typedef HRESULT (STDAPICALLTYPE DrawThemeParentBackgroundProc)(HWND hwnd, HDC hdc, OPTIONAL const RECT *prc); typedef HRESULT (STDAPICALLTYPE DrawThemeEdgeProc)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pDestRect, UINT uEdge, UINT uFlags, RECT *pContentRect); typedef HRESULT (STDAPICALLTYPE DrawThemeTextProc)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect); typedef HRESULT (STDAPICALLTYPE GetThemeBackgroundContentRectProc)( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect); typedef HRESULT (STDAPICALLTYPE GetThemeBackgroundExtentProc)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pContentRect, RECT *pExtentRect); typedef HRESULT (STDAPICALLTYPE GetThemeMarginsProc)(HTHEME, HDC, int iPartId, int iStateId, int iPropId, OPTIONAL RECT *prc, MARGINS *pMargins); typedef HRESULT (STDAPICALLTYPE GetThemePartSizeProc)(HTHEME, HDC, int iPartId, int iStateId, RECT *prc, enum THEMESIZE eSize, SIZE *psz); typedef HRESULT (STDAPICALLTYPE GetThemeTextExtentProc)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, const RECT *pBoundingRect, RECT *pExtentRect); typedef BOOL (STDAPICALLTYPE IsThemeActiveProc)(VOID); typedef BOOL (STDAPICALLTYPE IsAppThemedProc)(VOID); typedef BOOL (STDAPICALLTYPE IsThemePartDefinedProc)(HTHEME, int, int); typedef HRESULT (STDAPICALLTYPE IsThemeBackgroundPartiallyTransparentProc)( HTHEME, int, int); typedef HRESULT (STDAPICALLTYPE SetWindowThemeProc)(HWND, LPCWSTR, LPCWSTR); typedef struct { OpenThemeDataProc *OpenThemeData; CloseThemeDataProc *CloseThemeData; DrawThemeBackgroundProc *DrawThemeBackground; DrawThemeBackgroundExProc *DrawThemeBackgroundEx; DrawThemeParentBackgroundProc *DrawThemeParentBackground; DrawThemeEdgeProc *DrawThemeEdge; DrawThemeTextProc *DrawThemeText; GetThemeBackgroundContentRectProc *GetThemeBackgroundContentRect; GetThemeBackgroundExtentProc *GetThemeBackgroundExtent; GetThemeMarginsProc *GetThemeMargins; GetThemePartSizeProc *GetThemePartSize; GetThemeTextExtentProc *GetThemeTextExtent; IsThemeActiveProc *IsThemeActive; IsAppThemedProc *IsAppThemed; IsThemePartDefinedProc *IsThemePartDefined; IsThemeBackgroundPartiallyTransparentProc *IsThemeBackgroundPartiallyTransparent; SetWindowThemeProc *SetWindowTheme; } XPThemeProcs; typedef struct { HINSTANCE hlibrary; XPThemeProcs *procs; int registered; int themeEnabled; } XPThemeData; typedef struct TreeThemeData_ { HTHEME hThemeHEADER; HTHEME hThemeTREEVIEW; SIZE buttonOpen; SIZE buttonClosed; } TreeThemeData_; static XPThemeProcs *procs = NULL; static XPThemeData *appThemeData = NULL; TCL_DECLARE_MUTEX(themeMutex) /* Functions imported from kernel32.dll requiring windows XP or greater. */ /* But I already link to GetVersionEx so is this importing needed? */ typedef HANDLE (STDAPICALLTYPE CreateActCtxAProc)(PCACTCTXA pActCtx); typedef BOOL (STDAPICALLTYPE ActivateActCtxProc)(HANDLE hActCtx, ULONG_PTR *lpCookie); typedef BOOL (STDAPICALLTYPE DeactivateActCtxProc)(DWORD dwFlags, ULONG_PTR ulCookie); typedef VOID (STDAPICALLTYPE ReleaseActCtxProc)(HANDLE hActCtx); typedef struct { CreateActCtxAProc *CreateActCtxA; ActivateActCtxProc *ActivateActCtx; DeactivateActCtxProc *DeactivateActCtx; ReleaseActCtxProc *ReleaseActCtx; } ActCtxProcs; static ActCtxProcs * GetActCtxProcs(void) { HINSTANCE hInst; ActCtxProcs *procs = (ActCtxProcs *) ckalloc(sizeof(ActCtxProcs)); hInst = LoadLibrary("kernel32.dll"); /* FIXME: leak? */ if (hInst != 0) { #define LOADPROC(name) \ (0 != (procs->name = (name ## Proc *)GetProcAddress(hInst, #name) )) if (LOADPROC(CreateActCtxA) && LOADPROC(ActivateActCtx) && LOADPROC(DeactivateActCtx) && LOADPROC(ReleaseActCtx)) { return procs; } #undef LOADPROC } ckfree((char*)procs); return NULL; } static HMODULE thisModule = NULL; /* Return the HMODULE for this treectrl.dll. */ static HMODULE GetMyHandle(void) { #if 1 return thisModule; #else HMODULE hModule = NULL; /* FIXME: Only >=NT so I shouldn't link to it? But I already linked to * GetVersionEx so will it run on 95/98? */ GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&appThemeData, &hModule); return hModule; #endif } BOOL WINAPI DllMain( HINSTANCE hInst, /* Library instance handle. */ DWORD reason, /* Reason this function is being called. */ LPVOID reserved) /* Not used. */ { if (reason == DLL_PROCESS_ATTACH) { thisModule = (HMODULE) hInst; } return TRUE; } static HANDLE ActivateManifestContext(ActCtxProcs *procs, ULONG_PTR *ulpCookie) { ACTCTXA actctx; HANDLE hCtx; #if 1 char myPath[1024]; DWORD len; if (procs == NULL) return INVALID_HANDLE_VALUE; len = GetModuleFileName(GetMyHandle(),myPath,1024); myPath[len] = 0; ZeroMemory(&actctx, sizeof(actctx)); actctx.cbSize = sizeof(actctx); actctx.lpSource = myPath; actctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; #else if (procs == NULL) return INVALID_HANDLE_VALUE; ZeroMemory(&actctx, sizeof(actctx)); actctx.cbSize = sizeof(actctx); actctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID; actctx.hModule = GetMyHandle(); #endif actctx.lpResourceName = MAKEINTRESOURCE(2); hCtx = procs->CreateActCtxA(&actctx); if (hCtx == INVALID_HANDLE_VALUE) { char msg[1024]; DWORD err = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS| FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)msg, sizeof(msg), 0); return INVALID_HANDLE_VALUE; } if (procs->ActivateActCtx(hCtx, ulpCookie)) return hCtx; return INVALID_HANDLE_VALUE; } static void DeactivateManifestContext(ActCtxProcs *procs, HANDLE hCtx, ULONG_PTR ulpCookie) { if (procs == NULL) return; if (hCtx != INVALID_HANDLE_VALUE) { procs->DeactivateActCtx(0, ulpCookie); procs->ReleaseActCtx(hCtx); } ckfree((char*)procs); } /* http://www.manbu.net/Lib/En/Class5/Sub16/1/29.asp */ static int ComCtlVersionOK(void) { HINSTANCE handle; typedef HRESULT (STDAPICALLTYPE DllGetVersionProc)(DLLVERSIONINFO *); DllGetVersionProc *pDllGetVersion; int result = FALSE; ActCtxProcs *procs; HANDLE hCtx; ULONG_PTR ulpCookie; procs = GetActCtxProcs(); hCtx = ActivateManifestContext(procs, &ulpCookie); handle = LoadLibrary("comctl32.dll"); DeactivateManifestContext(procs, hCtx, ulpCookie); if (handle == NULL) return FALSE; pDllGetVersion = (DllGetVersionProc *) GetProcAddress(handle, "DllGetVersion"); if (pDllGetVersion != NULL) { DLLVERSIONINFO dvi; memset(&dvi, '\0', sizeof(dvi)); dvi.cbSize = sizeof(dvi); if ((*pDllGetVersion)(&dvi) == NOERROR) result = dvi.dwMajorVersion >= 6; } FreeLibrary(handle); return result; } /* *---------------------------------------------------------------------- * * LoadXPThemeProcs -- * Initialize XP theming support. * * XP theme support is included in UXTHEME.DLL * We dynamically load this DLL at runtime instead of linking * to it at build-time. * * Returns: * A pointer to an XPThemeProcs table if successful, NULL otherwise. *---------------------------------------------------------------------- */ static XPThemeProcs * LoadXPThemeProcs(HINSTANCE *phlib) { OSVERSIONINFO os; /* * We have to check whether we are running at least on Windows XP. * In order to determine this we call GetVersionEx directly, although * it would be a good idea to wrap it inside a function similar to * TkWinGetPlatformId... */ ZeroMemory(&os, sizeof(os)); os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&os); if ((os.dwMajorVersion >= 5 && os.dwMinorVersion >= 1) || (os.dwMajorVersion > 5)) { /* * We are running under Windows XP or a newer version. * Load the library "uxtheme.dll", where the native widget * drawing routines are implemented. */ HINSTANCE handle; *phlib = handle = LoadLibrary("uxtheme.dll"); if (handle != 0) { /* * We have successfully loaded the library. Proceed in storing the * addresses of the functions we want to use. */ XPThemeProcs *procs = (XPThemeProcs*)ckalloc(sizeof(XPThemeProcs)); #define LOADPROC(name) \ (0 != (procs->name = (name ## Proc *)GetProcAddress(handle, #name) )) if ( LOADPROC(OpenThemeData) && LOADPROC(CloseThemeData) && LOADPROC(DrawThemeBackground) && LOADPROC(DrawThemeBackgroundEx) && LOADPROC(DrawThemeParentBackground) && LOADPROC(DrawThemeEdge) && LOADPROC(DrawThemeText) && LOADPROC(GetThemeBackgroundContentRect) && LOADPROC(GetThemeBackgroundExtent) && LOADPROC(GetThemeMargins) && LOADPROC(GetThemePartSize) && LOADPROC(GetThemeTextExtent) && LOADPROC(IsThemeActive) && LOADPROC(IsAppThemed) && LOADPROC(IsThemePartDefined) && LOADPROC(IsThemeBackgroundPartiallyTransparent) && LOADPROC(SetWindowTheme) && ComCtlVersionOK() ) { return procs; } #undef LOADPROC ckfree((char*)procs); } } return 0; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawHeaderItem -- * * Draws the background of a single column header. On Mac OS X * this also draws the sort arrow, if any. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawHeaderItem( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ int state, /* COLUMN_STATE_xxx flags. */ int arrow, /* COLUMN_ARROW_xxx flags. */ int visIndex, /* 0-based index in list of visible columns. */ int x, int y, /* Bounds of the header. */ int width, int height /* Bounds of the header. */ ) { HTHEME hTheme; HDC hDC; TkWinDCState dcState; RECT rc; HRESULT hr; int iPartId = HP_HEADERITEM; int iStateId = HIS_NORMAL; switch (state) { case COLUMN_STATE_ACTIVE: iStateId = HIS_HOT; break; case COLUMN_STATE_PRESSED: iStateId = HIS_PRESSED; break; } if (!appThemeData->themeEnabled || !procs) return TCL_ERROR; hTheme = tree->themeData->hThemeHEADER; if (!hTheme) return TCL_ERROR; #if 0 /* Always returns FALSE */ if (!procs->IsThemePartDefined( hTheme, iPartId, iStateId)) { return TCL_ERROR; } #endif rc.left = x; rc.top = y; rc.right = x + width; rc.bottom = y + height; /* Is transparent for the default XP style. */ if (procs->IsThemeBackgroundPartiallyTransparent( hTheme, iPartId, iStateId)) { #if 1 /* What color should I use? */ Tk_Fill3DRectangle(tree->tkwin, td.drawable, tree->border, x, y, width, height, 0, TK_RELIEF_FLAT); #else /* This draws nothing, maybe because the parent window is not * themed */ procs->DrawThemeParentBackground( hwnd, hDC, &rc); #endif } hDC = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); #if 0 { /* Default XP theme gives rect 3 pixels narrower than rc */ RECT contentRect, extentRect; hr = procs->GetThemeBackgroundContentRect( hTheme, hDC, iPartId, iStateId, &rc, &contentRect ); dbwin("GetThemeBackgroundContentRect width=%d height=%d\n", contentRect.right - contentRect.left, contentRect.bottom - contentRect.top); /* Gives rc */ hr = procs->GetThemeBackgroundExtent( hTheme, hDC, iPartId, iStateId, &contentRect, &extentRect ); dbwin("GetThemeBackgroundExtent width=%d height=%d\n", extentRect.right - extentRect.left, extentRect.bottom - extentRect.top); } #endif hr = procs->DrawThemeBackground( hTheme, hDC, iPartId, iStateId, &rc, NULL); TkWinReleaseDrawableDC(td.drawable, hDC, &dcState); if (hr != S_OK) return TCL_ERROR; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_GetHeaderContentMargins -- * * Returns the padding inside the column header borders where * text etc may be displayed. * * Results: * TCL_OK if 'bounds' was set, TCL_ERROR otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetHeaderContentMargins( TreeCtrl *tree, /* Widget info. */ int state, /* COLUMN_STATE_xxx flags. */ int arrow, /* COLUMN_ARROW_xxx flags. */ int bounds[4] /* Returned left-top-right-bottom padding. */ ) { Window win = Tk_WindowId(tree->tkwin); HTHEME hTheme; HDC hDC; TkWinDCState dcState; HRESULT hr; MARGINS margins; int iPartId = HP_HEADERITEM; int iStateId = HIS_NORMAL; switch (state) { case COLUMN_STATE_ACTIVE: iStateId = HIS_HOT; break; case COLUMN_STATE_PRESSED: iStateId = HIS_PRESSED; break; } if (!appThemeData->themeEnabled || !procs) return TCL_ERROR; hTheme = tree->themeData->hThemeHEADER; if (!hTheme) return TCL_ERROR; hDC = TkWinGetDrawableDC(tree->display, win, &dcState); /* The default XP themes give 3,0,0,0 which makes little sense since * it is the *right* side that should not be drawn over by text; the * 2-pixel wide header divider is on the right */ hr = procs->GetThemeMargins( hTheme, hDC, iPartId, iStateId, TMT_CONTENTMARGINS, NULL, &margins); TkWinReleaseDrawableDC(win, hDC, &dcState); if (hr != S_OK) return TCL_ERROR; bounds[0] = margins.cxLeftWidth; bounds[1] = margins.cyTopHeight; bounds[2] = margins.cxRightWidth; bounds[3] = margins.cyBottomHeight; /* dbwin("margins %d %d %d %d\n", bounds[0], bounds[1], bounds[2], bounds[3]); */ return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawHeaderArrow -- * * Draws the sort arrow in a column header. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawHeaderArrow( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ int state, /* COLUMN_STATE_xxx flags. */ int up, /* TRUE if up arrow, FALSE otherwise. */ int x, int y, /* Bounds of arrow. Width and */ int width, int height /* height are the same as that returned */ /* by TreeTheme_GetArrowSize(). */ ) { #define THEME_ARROW 0 #if THEME_ARROW==0 XColor *color; GC gc; int i; if (!appThemeData->themeEnabled || !procs) return TCL_ERROR; color = Tk_GetColor(tree->interp, tree->tkwin, "#ACA899"); gc = Tk_GCForColor(color, td.drawable); if (up) { for (i = 0; i < height; i++) { XDrawLine(tree->display, td.drawable, gc, x + width / 2 - i, y + i, x + width / 2 + i + 1, y + i); } } else { for (i = 0; i < height; i++) { XDrawLine(tree->display, td.drawable, gc, x + width / 2 - i, y + (height - 1) - i, x + width / 2 + i + 1, y + (height - 1) - i); } } Tk_FreeColor(color); return TCL_OK; #else /* Doesn't seem that Microsoft actually implemented this */ Window win = Tk_WindowId(tree->tkwin); HWND hwnd = Tk_GetHWND(win); HTHEME hTheme; HDC hDC; TkWinDCState dcState; RECT rc; HRESULT hr; int iPartId = HP_HEADERSORTARROW; int iStateId = up ? HSAS_SORTEDUP : HSAS_SORTEDDOWN; if (!appThemeData->themeEnabled || !procs) return TCL_ERROR; hTheme = tree->themeData->hThemeHEADER; if (!hTheme) return TCL_ERROR; if (!procs->IsThemePartDefined( hTheme, iPartId, iStateId)) { return TCL_ERROR; } hDC = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); rc.left = x; rc.top = y; rc.right = x + width; rc.bottom = y + height; hr = procs->DrawThemeBackground( hTheme, hDC, iPartId, iStateId, &rc, NULL); TkWinReleaseDrawableDC(td.drawable, hDC, &dcState); return TCL_OK; #endif /* THEME_ARROW==1 */ } /* *---------------------------------------------------------------------- * * TreeTheme_DrawButton -- * * Draws a single expand/collapse item button. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the X11 fallback * should be used. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawButton( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeItem item, /* Needed for animating. */ int state, /* STATE_xxx | BUTTON_STATE_xxx flags. */ int x, int y, /* Bounds of the button. Width and height */ int width, int height /* are the same as that returned by */ /* TreeTheme_GetButtonSize(). */ ) { int open = state & STATE_ITEM_OPEN; int active = state & (BUTTON_STATE_ACTIVE|BUTTON_STATE_PRESSED); /* windows theme has no "pressed" state */ HTHEME hTheme; HDC hDC; TkWinDCState dcState; RECT rc; HRESULT hr; int iPartId, iStateId; if (!appThemeData->themeEnabled || !procs) return TCL_ERROR; hTheme = tree->themeData->hThemeTREEVIEW; if (!hTheme) return TCL_ERROR; /* On Win7 IsThemePartDefined(TVP_HOTGLYPH) correctly returns * TRUE when SetWindowTheme("explorer") is called and FALSE when it * wasn't called. */ if (active && procs->IsThemePartDefined(hTheme, TVP_HOTGLYPH, 0)) { iPartId = TVP_HOTGLYPH; iStateId = open ? HGLPS_OPENED : HGLPS_CLOSED; } else { iPartId = TVP_GLYPH; iStateId = open ? GLPS_OPENED : GLPS_CLOSED; } #if 0 /* Always returns FALSE */ if (!procs->IsThemePartDefined( hTheme, iPartId, iStateId)) { return TCL_ERROR; } #endif hDC = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); rc.left = x; rc.top = y; rc.right = x + width; rc.bottom = y + height; hr = procs->DrawThemeBackground( hTheme, hDC, iPartId, iStateId, &rc, NULL); TkWinReleaseDrawableDC(td.drawable, hDC, &dcState); if (hr != S_OK) return TCL_ERROR; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_GetButtonSize -- * * Returns the width and height of an expand/collapse item button. * * Results: * TCL_OK if *widthPtr and *heightPtr were set, TCL_ERROR * if themed buttons can't be drawn. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetButtonSize( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Needed on MS Windows. */ int open, /* TRUE if expanded button. */ int *widthPtr, /* Returned width of button. */ int *heightPtr /* Returned height of button. */ ) { TreeThemeData themeData = tree->themeData; HTHEME hTheme; HDC hDC; TkWinDCState dcState; HRESULT hr; SIZE size; int iPartId, iStateId; if (!appThemeData->themeEnabled || !procs) return TCL_ERROR; /* Use cached values */ size = open ? themeData->buttonOpen : themeData->buttonClosed; if (size.cx > 1) { *widthPtr = size.cx; *heightPtr = size.cy; return TCL_OK; } hTheme = themeData->hThemeTREEVIEW; if (!hTheme) return TCL_ERROR; iPartId = TVP_GLYPH; iStateId = open ? GLPS_OPENED : GLPS_CLOSED; #if 0 /* Always returns FALSE */ if (!procs->IsThemePartDefined( hTheme, iPartId, iStateId)) { return TCL_ERROR; } #endif hDC = TkWinGetDrawableDC(tree->display, drawable, &dcState); /* Returns 9x9 for default XP style */ hr = procs->GetThemePartSize( hTheme, hDC, iPartId, iStateId, NULL, TS_DRAW, &size ); TkWinReleaseDrawableDC(drawable, hDC, &dcState); /* With RandomN of 10000, I eventually get hr=E_HANDLE, invalid handle */ /* Not any longer since I don't call OpenThemeData/CloseThemeData for * every call. */ if (hr != S_OK) return TCL_ERROR; /* Gave me 0,0 for a non-default theme, even though glyph existed */ if ((size.cx <= 1) && (size.cy <= 1)) return TCL_ERROR; /* Cache the values */ if (open) themeData->buttonOpen = size; else themeData->buttonClosed = size; *widthPtr = size.cx; *heightPtr = size.cy; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_GetArrowSize -- * * Returns the width and height of a column header sort arrow. * * Results: * TCL_OK if *widthPtr and *heightPtr were set, TCL_ERROR * if themed sort arrows can't be drawn. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_GetArrowSize( TreeCtrl *tree, /* Widget info. */ Drawable drawable, /* Needed on MS Windows. */ int up, /* TRUE if up arrow. */ int *widthPtr, /* Returned width of arrow. */ int *heightPtr /* Returned height of arrow. */ ) { #if THEME_ARROW==0 if (!appThemeData->themeEnabled || !procs) return TCL_ERROR; *widthPtr = 9; *heightPtr = 5; return TCL_OK; #else TreeThemeData themeData = tree->themeData; HTHEME hTheme; HDC hDC; TkWinDCState dcState; HRESULT hr; SIZE size; int iPartId, iStateId; if (!appThemeData->themeEnabled || !procs) return TCL_ERROR; hTheme = themeData->hThemeTREEVIEW; if (!hTheme) return TCL_ERROR; iPartId = HP_HEADERSORTARROW; iStateId = up ? HSAS_SORTEDUP : HSAS_SORTEDDOWN; #if 0 /* Always returns FALSE */ if (!procs->IsThemePartDefined( hTheme, iPartId, iStateId)) { return TCL_ERROR; } #endif hDC = TkWinGetDrawableDC(tree->display, drawable, &dcState); hr = procs->GetThemePartSize( hTheme, hDC, iPartId, iStateId, NULL, TS_DRAW, &size ); TkWinReleaseDrawableDC(drawable, hDC, &dcState); if (hr != S_OK) return TCL_ERROR; if ((size.cx <= 1) && (size.cy <= 1)) return TCL_ERROR; *widthPtr = size.cx; *heightPtr = size.cy; return TCL_OK; #endif /* THEME_ARROW==1 */ } /* *---------------------------------------------------------------------- * * TreeTheme_SetBorders -- * * Sets the TreeCtrl.inset pad values according to the needs of * the system theme. * * Results: * TCL_OK if the inset was set, TCL_ERROR if the -highlightthickness * and -borderwidth values should be used. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_SetBorders( TreeCtrl *tree /* Widget info. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_DrawBorders -- * * Draws themed borders around the edges of the treectrl. * * Results: * TCL_OK if drawing occurred, TCL_ERROR if the Tk focus rectangle * and 3D border should be drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ int TreeTheme_DrawBorders( TreeCtrl *tree, /* Widget info. */ Drawable drawable /* Where to draw. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_GetHeaderTextColor -- * * Returns the text fill color to display a column title with. * * Results: * TCL_OK if the *colorPtrPtr was set, TCL_ERROR if a non-theme * color should be used. * * Side effects: * May allocate a new XColor. * *---------------------------------------------------------------------- */ int TreeTheme_GetHeaderTextColor( TreeCtrl *tree, /* Widget info. */ int columnState, /* COLUMN_STATE_xxx flags. */ XColor **colorPtrPtr /* Returned text color. */ ) { return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TreeTheme_AnimateButtonStart -- * * Starts an expand/collapse item button animating from open to * closed or vice versa. * * Results: * TCL_OK. * * Side effects: * May create a new Tcl_TimerToken. * *---------------------------------------------------------------------- */ int TreeTheme_AnimateButtonStart( TreeCtrl *tree, /* Widget info. */ TreeItem item /* The item whose button should animate. */ ) { TreeItem_OpenClose(tree, item, -1); #ifdef SELECTION_VISIBLE Tree_DeselectHidden(tree); #endif return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_ItemDeleted -- * * Cancels any item-button animation in progress. * * Results: * TCL_OK. * * Side effects: * May delete a TCL_TimerToken. * *---------------------------------------------------------------------- */ int TreeTheme_ItemDeleted( TreeCtrl *tree, /* Widget info. */ TreeItem item /* Item being deleted. */ ) { return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_Relayout -- * * This gets called when certain config options change and when * the size of the widget changes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeTheme_Relayout( TreeCtrl *tree /* Widget info. */ ) { } /* *---------------------------------------------------------------------- * * TreeTheme_IsDesktopComposited -- * * Determine if the OS windowing system is composited AKA * double-buffered. * * Results: * FALSE FALSE FALSE. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TreeTheme_IsDesktopComposited( TreeCtrl *tree /* Widget info. */ ) { /* TODO: Detect Vista/Win7 use of Desktop Window Manager using DwmIsCompositionEnabled(). WndProc should listen for WM_DWMCOMPOSITIONCHANGED. */ #if 1 /* On Win7 I see lots of flickering with the dragimage in the demo * "Explorer (Large Icons)", so Composition must not work quite how I * expected. */ return FALSE; #elif 0 HMODULE library = LoadLibrary("dwmapi.dll"); int result = FALSE; if (0 != library) { typedef BOOL (STDAPICALLTYPE DwmIsCompositionEnabledProc)(BOOL *pfEnabled); DwmIsCompositionEnabledProc *proc; if (0 != (proc = GetProcAddress(library, "DwmIsCompositionEnabled"))) { BOOL enabled = FALSE; result = SUCCEEDED(proc(&enabled)) && enabled; } FreeLibrary(library); } return result; #else /* http://weblogs.asp.net/kennykerr/archive/2006/08/10/Windows-Vista-for-Developers-_1320_-Part-3-_1320_-The-Desktop-Window-Manager.aspx */ bool IsCompositionEnabled() { HMODULE library = ::LoadLibrary(L"dwmapi.dll"); bool result = false; if (0 != library) { if (0 != ::GetProcAddress(library, "DwmIsCompositionEnabled")) { BOOL enabled = FALSE; result = SUCCEEDED(::DwmIsCompositionEnabled(&enabled)) && enabled; } VERIFY(::FreeLibrary(library)); } return result; } #endif return FALSE; } #if !defined(WM_THEMECHANGED) #define WM_THEMECHANGED 0x031A #endif static LRESULT WINAPI ThemeMonitorWndProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { Tcl_Interp *interp = (Tcl_Interp *)GetWindowLongPtr(hwnd, GWLP_USERDATA); switch (msg) { case WM_THEMECHANGED: Tcl_MutexLock(&themeMutex); appThemeData->themeEnabled = procs->IsThemeActive() && procs->IsAppThemed(); Tcl_MutexUnlock(&themeMutex); Tree_TheWorldHasChanged(interp); /* FIXME: must get tree->themeData->hThemeHEADER etc for each widget */ break; } return DefWindowProc(hwnd, msg, wp, lp); } static CHAR windowClassName[32] = "TreeCtrlMonitorClass"; static BOOL RegisterThemeMonitorWindowClass( HINSTANCE hinst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) ThemeMonitorWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hinst; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) COLOR_WINDOW; wc.lpszMenuName = windowClassName; wc.lpszClassName = windowClassName; return RegisterClassEx(&wc); } static HWND CreateThemeMonitorWindow( HINSTANCE hinst, Tcl_Interp *interp) { CHAR title[32] = "TreeCtrlMonitorWindow"; HWND hwnd; hwnd = CreateWindow(windowClassName, title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL); if (!hwnd) return NULL; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)interp); ShowWindow(hwnd, SW_HIDE); UpdateWindow(hwnd); return hwnd; } typedef struct PerInterpData PerInterpData; struct PerInterpData { HWND hwnd; }; static void ThemeFreeAssocData( ClientData clientData, Tcl_Interp *interp) { PerInterpData *data = (PerInterpData *) clientData; DestroyWindow(data->hwnd); ckfree((char *) data); } /* *---------------------------------------------------------------------- * * TreeTheme_ThemeChanged -- * * Called after the system theme changes. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void TreeTheme_ThemeChanged( TreeCtrl *tree /* Widget info. */ ) { Window win = Tk_WindowId(tree->tkwin); HWND hwnd = Tk_GetHWND(win); if (tree->themeData != NULL) { if (tree->themeData->hThemeHEADER != NULL) { procs->CloseThemeData(tree->themeData->hThemeHEADER); tree->themeData->hThemeHEADER = NULL; } if (tree->themeData->hThemeTREEVIEW != NULL) { procs->CloseThemeData(tree->themeData->hThemeTREEVIEW); tree->themeData->hThemeTREEVIEW = NULL; } } if (!appThemeData->themeEnabled || !procs) return; if (tree->themeData == NULL) tree->themeData = (TreeThemeData) ckalloc(sizeof(TreeThemeData_)); tree->themeData->hThemeHEADER = procs->OpenThemeData(hwnd, L"HEADER"); tree->themeData->hThemeTREEVIEW = procs->OpenThemeData(hwnd, L"TREEVIEW"); tree->themeData->buttonClosed.cx = tree->themeData->buttonOpen.cx = -1; } /* *---------------------------------------------------------------------- * * TreeTheme_InitWidget -- * * Performs theme-related initialization when a treectrl is * created. * * Results: * TCL_OK or TCL_ERROR, but result is ignored. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_InitWidget( TreeCtrl *tree /* Widget info. */ ) { Window win = Tk_WindowId(tree->tkwin); HWND hwnd = Tk_GetHWND(win); if (!appThemeData->themeEnabled || !procs) return TCL_ERROR; tree->themeData = (TreeThemeData) ckalloc(sizeof(TreeThemeData_)); /* http://www.codeproject.com/cs/miscctrl/themedtabpage.asp?msg=1445385#xx1445385xx */ /* http://msdn2.microsoft.com/en-us/library/ms649781.aspx */ tree->themeData->hThemeHEADER = procs->OpenThemeData(hwnd, L"HEADER"); tree->themeData->hThemeTREEVIEW = procs->OpenThemeData(hwnd, L"TREEVIEW"); tree->themeData->buttonClosed.cx = tree->themeData->buttonOpen.cx = -1; return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_FreeWidget -- * * Performs theme-related cleanup a when a treectrl is destroyed. * * Results: * None. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_FreeWidget( TreeCtrl *tree /* Widget info. */ ) { if (tree->themeData != NULL) { if (tree->themeData->hThemeHEADER != NULL) procs->CloseThemeData(tree->themeData->hThemeHEADER); if (tree->themeData->hThemeTREEVIEW != NULL) procs->CloseThemeData(tree->themeData->hThemeTREEVIEW); ckfree((char *) tree->themeData); } return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_InitInterp -- * * Performs theme-related initialization when the TkTreeCtrl * package is loaded into an interpreter. * * Results: * TCL_OK or TCL_ERROR, but result is ignored. * * Side effects: * Depends on the platform. * *---------------------------------------------------------------------- */ int TreeTheme_InitInterp( Tcl_Interp *interp /* Interp that loaded TkTreeCtrl pkg. */ ) { HWND hwnd; PerInterpData *data; Tcl_MutexLock(&themeMutex); /* This is done once per-application */ if (appThemeData == NULL) { appThemeData = (XPThemeData *) ckalloc(sizeof(XPThemeData)); appThemeData->procs = LoadXPThemeProcs(&appThemeData->hlibrary); appThemeData->registered = FALSE; appThemeData->themeEnabled = FALSE; procs = appThemeData->procs; if (appThemeData->procs) { /* Check this again if WM_THEMECHANGED arrives */ appThemeData->themeEnabled = procs->IsThemeActive() && procs->IsAppThemed(); appThemeData->registered = RegisterThemeMonitorWindowClass(Tk_GetHINSTANCE()); } } Tcl_MutexUnlock(&themeMutex); if (!procs || !appThemeData->registered) return TCL_ERROR; /* Per-interp */ hwnd = CreateThemeMonitorWindow(Tk_GetHINSTANCE(), interp); if (!hwnd) return TCL_ERROR; data = (PerInterpData *) ckalloc(sizeof(PerInterpData)); data->hwnd = hwnd; Tcl_SetAssocData(interp, "TreeCtrlTheme", ThemeFreeAssocData, (ClientData) data); return TCL_OK; } /* *---------------------------------------------------------------------- * * TreeTheme_SetOptionDefault -- * * Sets the default value for an option. * * Results: * Sets the defValue field if it wasn't done already. * * Side effects: * Changes an existing option table. * *---------------------------------------------------------------------- */ void TreeTheme_SetOptionDefault( Tk_OptionSpec *specPtr ) { #ifdef TREECTRL_DEBUG if (specPtr == NULL) panic("TreeTheme_SetOptionDefault specPtr == NULL"); #endif /* Only set the default value once per-application. */ if (specPtr->defValue != NULL) return; if (!strcmp(specPtr->optionName, "-buttontracking")) specPtr->defValue = "0"; else if (!strcmp(specPtr->optionName, "-showlines")) specPtr->defValue = "1"; #ifdef TREECTRL_DEBUG else panic("TreeTheme_SetOptionDefault unhandled option \"%s\"", specPtr->optionName ? specPtr->optionName : "NULL"); #endif } int TreeThemeCmd( TreeCtrl *tree, /* Widget info. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[] /* Argument values. */ ) { Tcl_Interp *interp = tree->interp; static CONST char *commandName[] = { "platform", "setwindowtheme", (char *) NULL }; enum { COMMAND_PLATFORM, COMMAND_SETWINDOWTHEME }; int index; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "command ?arg arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[2], commandName, "command", 0, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { /* T theme platform */ case COMMAND_PLATFORM: { char *platform = "X11"; /* X11, xlib, whatever */ if (appThemeData->themeEnabled && appThemeData->procs) platform = "visualstyles"; Tcl_SetObjResult(interp, Tcl_NewStringObj(platform, -1)); break; } /* T theme setwindowtheme $appname */ case COMMAND_SETWINDOWTHEME: { LPCWSTR pszSubAppName; /* L"Explorer" for example */ int length; Window win; HWND hwnd; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "appname"); return TCL_ERROR; } if (!appThemeData->themeEnabled || !appThemeData->procs) break; win = Tk_WindowId(tree->tkwin); hwnd = Tk_GetHWND(win); pszSubAppName = Tcl_GetUnicodeFromObj(objv[3], &length); procs->SetWindowTheme(hwnd, length ? pszSubAppName : NULL, NULL); /* uxtheme.h says a WM_THEMECHANGED is sent to the window. */ /* FIXME: only this window needs to be updated. */ /* This calls TreeTheme_ThemeChanged which is needed. */ Tree_TheWorldHasChanged(tree->interp); break; } } return TCL_OK; } /*** Gradients ***/ /* * GDI+ flat api */ /* gdiplus.h is a C++ header file with MSVC. */ /* gdiplus.h works with C and C++ with MinGW. */ /* However gdiplus.h is not included with MinGW-w64 for some reason and * also does not come with the Linux i586-mingw32msvc cross-compiler. */ #if 1 #define WINGDIPAPI __stdcall #define GDIPCONST const #define VOID void typedef float REAL; typedef enum CombineMode { CombineModeReplace = 0 } CombineMode; typedef enum GpFillMode { FillModeAlternate, FillModeWinding } GpFillMode; typedef enum GpLineCap { LineCapSquare = 1 } GpLineCap; typedef enum GpUnit { UnitWorld = 0, UnitDisplay = 1, UnitPixel = 2, UnitPoint = 3, UnitInch = 4, UnitDocument = 5, UnitMillimeter = 6 } GpUnit; typedef enum GpStatus { Ok = 0 } GpStatus; typedef enum GpWrapMode { WrapModeTile = 0, /* repeat */ WrapModeTileFlipXY = 3 /* reflect */ } GpWrapMode; typedef enum LinearGradientMode { LinearGradientModeHorizontal, LinearGradientModeVertical } LinearGradientMode; typedef enum GpPenAlignment { PenAlignmentCenter = 0, PenAlignmentInset = 1 } GpPenAlignment; typedef enum SmoothingMode { SmoothingModeHighQuality = 2, SmoothingModeAntiAlias = 4 } SmoothingMode; typedef struct GdiplusStartupInput { UINT32 GdiplusVersion; /*DebugEventProc*/VOID* DebugEventCallback; BOOL SuppressBackgroundThread; BOOL SuppressExternalCodecs; } GdiplusStartupInput; typedef struct GdiplusStartupOutput { /*NotificationHookProc*/VOID* NotificationHook; /*NotificationUnhookProc*/VOID* NotificationUnhook; } GdiplusStartupOutput; typedef struct GpPoint { INT X; INT Y; } GpPoint; typedef struct GpPointF { REAL X; REAL Y; } GpPointF; typedef struct GpRect { INT X; INT Y; INT Width; INT Height; } GpRect; typedef DWORD ARGB; typedef void GpBrush; typedef void GpGraphics; typedef void GpLineGradient; typedef void GpPath; typedef void GpPen; typedef void GpSolidFill; #endif /* After gdiplus.dll is dynamically loaded, this structure is * filled in with pointers to functions that are used below. */ static struct { HMODULE handle; /* gdiplus.dll */ VOID* (WINGDIPAPI *_GdipAlloc)(size_t); VOID (WINGDIPAPI *_GdipFree)(VOID*); GpStatus (WINGDIPAPI *_GdiplusStartup)(ULONG_PTR*,GDIPCONST GdiplusStartupInput*,GdiplusStartupOutput*); VOID (WINGDIPAPI *_GdiplusShutdown)(ULONG_PTR); /* Graphics */ GpStatus (WINGDIPAPI *_GdipCreateFromHDC)(HDC,GpGraphics**); GpStatus (WINGDIPAPI *_GdipFillRectangleI)(GpGraphics*,GpBrush*,INT,INT,INT,INT); GpStatus (WINGDIPAPI *_GdipDeleteGraphics)(GpGraphics*); GpStatus (WINGDIPAPI *_GdipDrawPath)(GpGraphics*,GpPen*,GpPath*); GpStatus (WINGDIPAPI *_GdipFillPath)(GpGraphics*,GpBrush*,GpPath*); GpStatus (WINGDIPAPI *_GdipSetClipHrgn)(GpGraphics*,HRGN,CombineMode); GpStatus (WINGDIPAPI *_GdipSetClipPath)(GpGraphics*,GpPath*,CombineMode); GpStatus (WINGDIPAPI *_GdipSetClipRectI)(GpGraphics*,INT,INT,INT,INT,CombineMode); GpStatus (WINGDIPAPI *_GdipSetSmoothingMode)(GpGraphics*,SmoothingMode); /* GraphicsPath */ GpStatus (WINGDIPAPI *_GdipCreatePath)(GpFillMode,GpPath**); GpStatus (WINGDIPAPI *_GdipDeletePath)(GpPath*); GpStatus (WINGDIPAPI *_GdipResetPath)(GpPath*); GpStatus (WINGDIPAPI *_GdipAddPathArc)(GpPath*,REAL,REAL,REAL,REAL,REAL,REAL); GpStatus (WINGDIPAPI *_GdipAddPathLine)(GpPath*,REAL,REAL,REAL,REAL); GpStatus (WINGDIPAPI *_GdipAddPathRectangle)(GpPath*,REAL,REAL,REAL,REAL); GpStatus (WINGDIPAPI *_GdipStartPathFigure)(GpPath*); GpStatus (WINGDIPAPI *_GdipClosePathFigure)(GpPath*); /* Linear Gradient brush */ GpStatus (WINGDIPAPI *_GdipCreateLineBrushFromRectI)(GDIPCONST GpRect*,ARGB,ARGB,LinearGradientMode,GpWrapMode,GpLineGradient**); GpStatus (WINGDIPAPI *_GdipSetLinePresetBlend)(GpLineGradient*,GDIPCONST ARGB*,GDIPCONST REAL*,INT); GpStatus (WINGDIPAPI *_GdipDeleteBrush)(GpBrush*); /* Pen */ GpStatus (WINGDIPAPI *_GdipCreatePen1)(ARGB,REAL,GpUnit,GpPen**); GpStatus (WINGDIPAPI *_GdipCreatePen2)(GpBrush*,REAL,GpUnit,GpPen**); GpStatus (WINGDIPAPI *_GdipSetPenEndCap)(GpPen*,GpLineCap); GpStatus (WINGDIPAPI *_GdipSetPenStartCap)(GpPen*,GpLineCap); GpStatus (WINGDIPAPI *_GdipSetPenMode)(GpPen*,GpPenAlignment); GpStatus (WINGDIPAPI *_GdipDeletePen)(GpPen*); /* SolidFill brush */ GpStatus (WINGDIPAPI *_GdipCreateSolidFill)(ARGB,GpSolidFill**); } DllExports = {0}; /* Per-application global data */ typedef struct { ULONG_PTR token; /* Result of GdiplusStartup() */ #if 0 GdiplusStartupOutput output; /* Result of GdiplusStartup() */ #endif } TreeDrawAppData; static TreeDrawAppData *appDrawData = NULL; /* Tcl_CreateExitHandler() callback that shuts down GDI+ */ static void TreeDraw_ExitHandler( ClientData clientData ) { if (appDrawData != NULL) { if (DllExports.handle != NULL) DllExports._GdiplusShutdown(appDrawData->token); } } /* Load gdiplus.dll (if it exists) and fill in the DllExports global */ /* If gdiplus.dll can't be loaded DllExports.handle is set to NULL which * should be checked to test whether GDI+ can be used. */ static int LoadGdiplus(void) { DllExports.handle = LoadLibrary("gdiplus.dll"); if (DllExports.handle != NULL) { #define LOADPROC(name) \ (0 != (DllExports._ ## name = (VOID *)GetProcAddress(DllExports.handle, #name) )) if ( LOADPROC(GdipAlloc) && LOADPROC(GdipFree) && LOADPROC(GdiplusStartup) && LOADPROC(GdiplusShutdown) && LOADPROC(GdipCreateFromHDC) && LOADPROC(GdipFillRectangleI) && LOADPROC(GdipDeleteGraphics) && LOADPROC(GdipDrawPath) && LOADPROC(GdipFillPath) && LOADPROC(GdipSetClipHrgn) && LOADPROC(GdipSetClipPath) && LOADPROC(GdipSetClipRectI) && LOADPROC(GdipSetSmoothingMode) && LOADPROC(GdipCreatePath) && LOADPROC(GdipDeletePath) && LOADPROC(GdipResetPath) && LOADPROC(GdipAddPathArc) && LOADPROC(GdipAddPathLine) && LOADPROC(GdipAddPathRectangle) && LOADPROC(GdipStartPathFigure) && LOADPROC(GdipClosePathFigure) && LOADPROC(GdipCreateLineBrushFromRectI) && LOADPROC(GdipSetLinePresetBlend) && LOADPROC(GdipDeleteBrush) && LOADPROC(GdipCreatePen1) && LOADPROC(GdipCreatePen2) && LOADPROC(GdipSetPenEndCap) && LOADPROC(GdipSetPenStartCap) && LOADPROC(GdipSetPenMode) && LOADPROC(GdipDeletePen) && LOADPROC(GdipCreateSolidFill) ) { return 1; } #undef LOADPROC } DllExports.handle = NULL; return 0; } /* Per-interp init */ int TreeDraw_InitInterp( Tcl_Interp *interp ) { /* This is done once per-application */ if (appDrawData == NULL) { appDrawData = (TreeDrawAppData *) ckalloc(sizeof(TreeDrawAppData)); memset(appDrawData, '\0', sizeof(TreeDrawAppData)); if (LoadGdiplus()) { GdiplusStartupInput input; GpStatus status; input.GdiplusVersion = 1; input.DebugEventCallback = NULL; input.SuppressBackgroundThread = FALSE; input.SuppressExternalCodecs = FALSE; /* Not sure what happens when the main application or other * DLLs also call this, probably it is okay. */ status = DllExports._GdiplusStartup(&appDrawData->token, &input, #if 1 NULL); #else &appDrawData->output); #endif if (status != Ok) { DllExports.handle = NULL; } } Tcl_CreateExitHandler(TreeDraw_ExitHandler, NULL); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Tree_HasNativeGradients -- * * Determine if this platform supports gradients natively. * * Results: * 1 if GDI+ is available, * 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int Tree_HasNativeGradients( TreeCtrl *tree) { return (DllExports.handle != NULL); } /* ARGB is a DWORD color used by GDI+ */ static ARGB MakeARGB(BYTE a, BYTE r, BYTE g, BYTE b) { return (ARGB) ((((DWORD) a) << 24) | (((DWORD) r) << 16) | (((DWORD) g) << 8) | ((DWORD) b)); } static ARGB MakeGDIPlusColor(XColor *xc, double opacity) { return MakeARGB( (BYTE)(opacity*255), (BYTE)((xc)->pixel & 0xFF), (BYTE)(((xc)->pixel >> 8) & 0xFF), (BYTE)(((xc)->pixel >> 16) & 0xFF)); } typedef struct { TreeCtrl *tree; TreeClip *clip; GpGraphics *graphics; } TreeClipStateGraphics; static GpStatus TreeClip_ToGraphics( TreeCtrl *tree, TreeClip *clip, GpGraphics *graphics, TreeClipStateGraphics *state ) { GpStatus status = Ok; state->tree = tree; state->clip = clip; state->graphics = graphics; if (clip && clip->type == TREE_CLIP_RECT) { status = DllExports._GdipSetClipRectI(graphics, clip->tr.x, clip->tr.y, clip->tr.width, clip->tr.height, CombineModeReplace); } if (clip && clip->type == TREE_CLIP_AREA) { TreeRectangle tr; if (Tree_AreaBbox(tree, clip->area, &tr) == 0) { TreeRect_SetXYWH(tr, 0, 0, 0, 0); } status = DllExports._GdipSetClipRectI(graphics, TreeRect_Left(tr), TreeRect_Top(tr), TreeRect_Width(tr), TreeRect_Height(tr), CombineModeReplace); } if (clip && clip->type == TREE_CLIP_REGION) { status = DllExports._GdipSetClipHrgn(graphics, (HRGN) clip->region, CombineModeReplace); } return status; } static GpStatus MakeLinearGradientBrush( TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ GpLineGradient **lgPtr /* Result. */ ) { GpLineGradient *lineGradient; GpStatus status; GpRect rect; GradientStop *stop; int i, nstops; ARGB color1, color2; (*lgPtr) = NULL; nstops = gradient->stopArrPtr->nstops; rect.X = trBrush.x, rect.Y = trBrush.y, rect.Width = trBrush.width, rect.Height = trBrush.height; /* BUG BUG BUG: A linear gradient brush will *sometimes* wrap when it * shouldn't due to rounding errors or something, resulting in a line * of color2 where color1 starts. The recommended solution is to * make the brush 1-pixel larger on all sides than the area being * painted. The downside of this is you will lose a bit of the gradient. */ if (gradient->vertical) rect.Y -= 1, rect.Height += 1; else rect.X -= 1, rect.Width += 1; stop = gradient->stopArrPtr->stops[0]; color1 = MakeGDIPlusColor(stop->color, stop->opacity); stop = gradient->stopArrPtr->stops[nstops-1]; color2 = MakeGDIPlusColor(stop->color, stop->opacity); status = DllExports._GdipCreateLineBrushFromRectI( &rect, color1, color2, gradient->vertical ? LinearGradientModeVertical : LinearGradientModeHorizontal, WrapModeTile, &lineGradient); if (status != Ok) return status; if (nstops > 2) { ARGB *col = DllExports._GdipAlloc(nstops * sizeof(ARGB)); if (col != NULL) { REAL *pos = DllExports._GdipAlloc(nstops * sizeof(REAL)); if (pos != NULL) { for (i = 0; i < nstops; i++) { stop = gradient->stopArrPtr->stops[i]; col[i] = MakeGDIPlusColor(stop->color, stop->opacity); pos[i] = (REAL)stop->offset; } status = DllExports._GdipSetLinePresetBlend(lineGradient, col, pos, nstops); DllExports._GdipFree((void*) pos); } DllExports._GdipFree((void*) col); } } (*lgPtr) = lineGradient; return Ok; } /* *---------------------------------------------------------------------- * * TreeGradient_FillRect -- * * Paint a rectangle with a gradient using GDI+. * * Results: * If GDI+ isn't available then fall back to X11. If the gradient * has <2 stops then nothing is drawn. * * Side effects: * Drawing. * *---------------------------------------------------------------------- */ void TreeGradient_FillRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr /* Rectangle to paint. */ ) { HDC hDC; TkWinDCState dcState; TreeClipStateGraphics clipState; GpGraphics *graphics; GpLineGradient *lineGradient = NULL; GpStatus status; GpRect rect; int nstops; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (!tree->nativeGradients || (DllExports.handle == NULL)) { TreeGradient_FillRectX11(tree, td, clip, gradient, trBrush, tr); return; } nstops = gradient->stopArrPtr ? gradient->stopArrPtr->nstops : 0; if (nstops < 2) /* can be 0, but < 2 isn't allowed */ return; hDC = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); status = DllExports._GdipCreateFromHDC(hDC, &graphics); if (status != Ok) goto error1; status = TreeClip_ToGraphics(tree, clip, graphics, &clipState); if (status != Ok) goto error2; status = MakeLinearGradientBrush(gradient, trBrush, &lineGradient); if (status != Ok) goto error2; rect.X = tr.x, rect.Y = tr.y, rect.Width = tr.width, rect.Height = tr.height; DllExports._GdipFillRectangleI(graphics, lineGradient, rect.X, rect.Y, rect.Width, rect.Height); DllExports._GdipDeleteBrush(lineGradient); error2: DllExports._GdipDeleteGraphics(graphics); error1: TkWinReleaseDrawableDC(td.drawable, hDC, &dcState); #ifdef TREECTRL_DEBUG if (status != Ok) dbwin("TreeGradient_FillRect gdiplus status != Ok"); #endif } static void GetRectPath_Outline( GpPath *path, /* GDI+ path to set. */ TreeRectangle tr, /* Rectangle to draw. */ int open, /* RECT_OPEN_x flags. */ int outlineWidth /* Thickness of the outline. */ ) { REAL x = (REAL)tr.x, y = (REAL)tr.y, width = (REAL)tr.width, height = (REAL)tr.height; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; /* Weird issue, if outlineWidth == 1 the NW corner is missing a pixel, * even when calling GdipAddPathRectangle. So don't draw on the 1/2 * pixel boundary in that case. */ if (outlineWidth > 1) { x += outlineWidth / 2.0f, y += outlineWidth / 2.0f; } width -= outlineWidth, height -= outlineWidth; /* Simple case: draw all 4 edges */ if (drawW && drawN && drawE && drawS) { DllExports._GdipAddPathRectangle(path, x, y, width, height); /* Complicated case: some edges are "open" */ } else { if (drawN) DllExports._GdipAddPathLine(path, x, y, x + width, y); if (drawE) DllExports._GdipAddPathLine(path, x + width, y, x + width, y + height); else if (drawN) DllExports._GdipStartPathFigure(path); if (drawS) DllExports._GdipAddPathLine(path, x + width, y + height, x, y + height); else if (drawE) DllExports._GdipStartPathFigure(path); if (drawW) DllExports._GdipAddPathLine(path, x, y + height, x, y); } } void TreeGradient_DrawRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to draw. */ int outlineWidth, /* Width of outline. */ int open /* RECT_OPEN_x flags */ ) { HDC hDC; TkWinDCState dcState; TreeClipStateGraphics clipState; GpGraphics *graphics; GpPath *path; GpLineGradient *lineGradient; GpPen *pen; GpStatus status; if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (!tree->nativeGradients || (DllExports.handle == NULL)) { TreeGradient_DrawRectX11(tree, td, clip, gradient, trBrush, tr, outlineWidth, open); return; } hDC = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); status = DllExports._GdipCreateFromHDC(hDC, &graphics); if (status != Ok) goto error1; status = DllExports._GdipCreatePath(FillModeAlternate, &path); if (status != Ok) goto error2; status = MakeLinearGradientBrush(gradient, trBrush, &lineGradient); if (status != Ok) goto error3; status = DllExports._GdipCreatePen2(lineGradient, (REAL) outlineWidth, UnitPixel, &pen); if (status != Ok) goto error4; status = TreeClip_ToGraphics(tree, clip, graphics, &clipState); if (status != Ok) goto error5; GetRectPath_Outline(path, tr, open, outlineWidth); DllExports._GdipSetPenStartCap(pen, LineCapSquare); DllExports._GdipSetPenEndCap(pen, LineCapSquare); DllExports._GdipDrawPath(graphics, pen, path); error5: DllExports._GdipDeletePen(pen); error4: DllExports._GdipDeleteBrush(path); error3: DllExports._GdipDeletePath(path); error2: DllExports._GdipDeleteGraphics(graphics); error1: TkWinReleaseDrawableDC(td.drawable, hDC, &dcState); } static void GetRoundRectPath_Outline( GpPath *path, /* GDI+ path to set. */ TreeRectangle tr, /* Rectangle to draw. */ int rx, int ry, /* Corner radius. */ int open, /* RECT_OPEN_x flags. */ int fudgeX, /* Fix for "open" edge endpoints when */ int fudgeY, /* outlineWidth>1. */ int outlineWidth ) { REAL x = (REAL)tr.x, y = (REAL)tr.y, width = (REAL)tr.width, height = (REAL)tr.height; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; if (outlineWidth > 0) { x += outlineWidth / 2.0f, y += outlineWidth / 2.0f; width -= outlineWidth, height -= outlineWidth; } else { width -= 1, height -= 1; } /* Simple case: draw all 4 corners and 4 edges */ if (drawW && drawN && drawE && drawS) { DllExports._GdipAddPathArc(path, x, y, rx*2.0f, ry*2.0f, 180.0f, 90.0f); /* top-left */ DllExports._GdipAddPathArc(path, x + width - rx*2.0f, y, rx*2.0f, ry*2.0f, 270.0f, 90.0f); /* top-right */ DllExports._GdipAddPathArc(path, x + width - rx*2.0f, y + height - ry*2.0f, rx*2.0f, ry*2.0f, 0.0f, 90.0f); /* bottom-right */ DllExports._GdipAddPathArc(path, x, y + height - ry*2.0f, rx*2.0f, ry*2.0f, 90.0f, 90.0f); /* bottom-left */ DllExports._GdipClosePathFigure(path); /* Complicated case: some edges are "open" */ } else { GpPointF start[4], end[4]; /* start and end points of line segments*/ start[0].X = x, start[0].Y = y; end[3] = start[0]; if (drawW && drawN) { start[0].X += rx; end[3].Y += ry; } else { start[0].X -= fudgeX; end[3].Y -= fudgeY; } end[0].X = x + width, end[0].Y = y; start[1]= end[0]; if (drawE && drawN) { end[0].X -= rx; start[1].Y += ry; } else { end[0].X += fudgeX; start[1].Y -= fudgeY; } end[1].X = x + width, end[1].Y = y + height; start[2] = end[1]; if (drawE && drawS) { end[1].Y -= ry; start[2].X -= rx; } else { end[1].Y += fudgeY; start[2].X += fudgeX; } end[2].X = x, end[2].Y = y + height; start[3] = end[2]; if (drawW && drawS) { end[2].X += rx; start[3].Y -= ry; } else { end[2].X -= fudgeX; start[3].Y += fudgeY; } if (drawW && drawN) DllExports._GdipAddPathArc(path, x, y, rx*2.0f, ry*2.0f, 180.0f, 90.0f); /* top-left */ if (drawN) DllExports._GdipAddPathLine(path, start[0].X, start[0].Y, end[0].X, end[0].Y); if (drawE && drawN) DllExports._GdipAddPathArc(path, x + width - rx*2.0f, y, rx*2.0f, ry*2.0f, 270.0f, 90.0f); /* top-right */ if (drawE) DllExports._GdipAddPathLine(path, start[1].X, start[1].Y, end[1].X, end[1].Y); else if (drawN) DllExports._GdipStartPathFigure(path); if (drawE && drawS) DllExports._GdipAddPathArc(path, x + width - rx*2.0f, y + height - ry*2.0f, rx*2.0f, ry*2.0f, 0.0f, 90.0f); /* bottom-right */ if (drawS) DllExports._GdipAddPathLine(path, start[2].X, start[2].Y, end[2].X, end[2].Y); else if (drawE) DllExports._GdipStartPathFigure(path); if (drawW && drawS) DllExports._GdipAddPathArc(path, x, y + height - ry*2.0f, rx*2.0f, ry*2.0f, 90.0f, 90.0f); /* bottom-left */ if (drawW) DllExports._GdipAddPathLine(path, start[3].X, start[3].Y, end[3].X, end[3].Y); } } void Tree_DrawRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ XColor *xcolor, /* Color. */ TreeRectangle tr, /* Rectangle to draw. */ int outlineWidth, /* Width of outline. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { HDC hDC; TkWinDCState dcState; TreeClipStateGraphics clipState; GpGraphics *graphics; GpPath *path; ARGB color; GpPen *pen; GpStatus status; int i; if (!tree->nativeGradients || (DllExports.handle == NULL)) { GC gc = Tk_GCForColor(xcolor, td.drawable); Tree_DrawRoundRectX11(tree, td, clip, gc, tr, outlineWidth, rx, ry, open); return; } hDC = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); status = DllExports._GdipCreateFromHDC(hDC, &graphics); if (status != Ok) goto error1; status = DllExports._GdipCreatePath(FillModeAlternate, &path); if (status != Ok) goto error2; color = MakeGDIPlusColor(xcolor,1.0f); status = DllExports._GdipCreatePen1(color, 1, UnitPixel, &pen); if (status != Ok) goto error3; status = TreeClip_ToGraphics(tree, clip, graphics, &clipState); if (status != Ok) goto error3; GetRoundRectPath_Outline(path, tr, rx, ry, open, 0, 0, 0); DllExports._GdipDrawPath(graphics, pen, path); /* http://www.codeproject.com/KB/GDI-plus/RoundRect.aspx */ for (i = 1; i < outlineWidth; i++) { tr.x += 1, tr.width -= 2; DllExports._GdipResetPath(path); GetRoundRectPath_Outline(path, tr, rx, ry, open, i, i-1, 0); DllExports._GdipDrawPath(graphics, pen, path); tr.y += 1, tr.height -= 2; DllExports._GdipResetPath(path); GetRoundRectPath_Outline(path, tr, rx, ry, open, i, i, 0); DllExports._GdipDrawPath(graphics, pen, path); } DllExports._GdipDeletePen(pen); error3: DllExports._GdipDeletePath(path); error2: DllExports._GdipDeleteGraphics(graphics); error1: TkWinReleaseDrawableDC(td.drawable, hDC, &dcState); } void TreeGradient_DrawRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to draw. */ int outlineWidth, /* Width of outline. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { HDC hDC; TkWinDCState dcState; TreeClipStateGraphics clipState; GpGraphics *graphics; GpPath *path; GpLineGradient *lineGradient; GpPen *pen; GpStatus status; int i; int canRepairCorners; if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (!tree->nativeGradients || (DllExports.handle == NULL)) { XColor *xcolor = gradient->stopArrPtr->stops[0]->color; /* Use the first stop color */ GC gc = Tk_GCForColor(xcolor, td.drawable); Tree_DrawRoundRectX11(tree, td, clip, gc, tr, outlineWidth, rx, ry, open); return; } hDC = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); status = DllExports._GdipCreateFromHDC(hDC, &graphics); if (status != Ok) goto error1; status = DllExports._GdipCreatePath(FillModeAlternate, &path); if (status != Ok) goto error2; status = MakeLinearGradientBrush(gradient, trBrush, &lineGradient); if (status != Ok) goto error3; canRepairCorners = (outlineWidth == 1) || TreeGradient_IsOpaque(tree, gradient); status = DllExports._GdipCreatePen2(lineGradient, canRepairCorners ? 1.0f : (REAL) outlineWidth, UnitPixel, &pen); if (status != Ok) goto error4; status = TreeClip_ToGraphics(tree, clip, graphics, &clipState); if (status != Ok) goto error5; GetRoundRectPath_Outline(path, tr, rx, ry, open, 0, 0, canRepairCorners ? 0 : outlineWidth); DllExports._GdipDrawPath(graphics, pen, path); /* http://www.codeproject.com/KB/GDI-plus/RoundRect.aspx */ if (canRepairCorners) { for (i = 1; i < outlineWidth; i++) { tr.x += 1, tr.width -= 2; DllExports._GdipResetPath(path); GetRoundRectPath_Outline(path, tr, rx, ry, open, i, i-1, 0); DllExports._GdipDrawPath(graphics, pen, path); tr.y += 1, tr.height -= 2; DllExports._GdipResetPath(path); GetRoundRectPath_Outline(path, tr, rx, ry, open, i, i, 0); DllExports._GdipDrawPath(graphics, pen, path); } } error5: DllExports._GdipDeletePen(pen); error4: DllExports._GdipDeleteBrush(path); error3: DllExports._GdipDeletePath(path); error2: DllExports._GdipDeleteGraphics(graphics); error1: TkWinReleaseDrawableDC(td.drawable, hDC, &dcState); } #define ROUND_RECT_SYMMETRY_HACK /* This returns a path 1-pixel smaller on the right and bottom edges than * it should be. * For some reason GdipFillPath produces different (and asymmetric) results * than GdipDrawPath. So after filling the round rectangle with this path * GetRoundRectPath_Outline should be called to paint the right and bottom * edges. */ /* http://www.codeproject.com/KB/GDI-plus/RoundRect.aspx */ static void GetRoundRectPath_Fill( GpPath *path, /* GDI+ path to set. */ TreeRectangle tr, /* Rectangle to paint. */ int rx, int ry, /* Corner radius. */ int open /* RECT_OPEN_x flags. */ #ifdef ROUND_RECT_SYMMETRY_HACK , int rrhack #endif ) { REAL x = (REAL)tr.x, y = (REAL)tr.y, width = (REAL)tr.width, height = (REAL)tr.height; int drawW = (open & RECT_OPEN_W) == 0; int drawN = (open & RECT_OPEN_N) == 0; int drawE = (open & RECT_OPEN_E) == 0; int drawS = (open & RECT_OPEN_S) == 0; /* Simple case: draw all 4 corners and 4 edges */ if (drawW && drawN && drawE && drawS) { #ifdef ROUND_RECT_SYMMETRY_HACK if (rrhack) width -= 1, height -= 1; #endif DllExports._GdipAddPathArc(path, x, y, rx*2.0f, ry*2.0f, 180.0f, 90.0f); /* top-left */ DllExports._GdipAddPathArc(path, x + width - rx*2.0f, y, rx*2.0f, ry*2.0f, 270.0f, 90.0f); /* top-right */ DllExports._GdipAddPathArc(path, x + width - rx*2.0f, y + height - ry*2.0f, rx*2.0f, ry*2.0f, 0.0f, 90.0f); /* bottom-right */ DllExports._GdipAddPathArc(path, x, y + height - ry*2.0f, rx*2.0f, ry*2.0f, 90.0f, 90.0f); /* bottom-left */ DllExports._GdipClosePathFigure(path); /* Complicated case: some edges are "open" */ } else { GpPointF start[4], end[4]; /* start and end points of line segments*/ #ifdef ROUND_RECT_SYMMETRY_HACK if (rrhack) { if (drawE) width -= 1; if (drawS) height -= 1; } #endif start[0].X = x, start[0].Y = y; end[3] = start[0]; if (drawW && drawN) { start[0].X += rx; end[3].Y += ry; } end[0].X = x + width, end[0].Y = y; start[1]= end[0]; if (drawE && drawN) { end[0].X -= rx; start[1].Y += ry; } end[1].X = x + width, end[1].Y = y + height; start[2] = end[1]; if (drawE && drawS) { end[1].Y -= ry; start[2].X -= rx; } end[2].X = x, end[2].Y = y + height; start[3] = end[2]; if (drawW && drawS) { end[2].X += rx; start[3].Y -= ry; } if (drawW && drawN) DllExports._GdipAddPathArc(path, x, y, rx*2.0f, ry*2.0f, 180.0f, 90.0f); /* top-left */ DllExports._GdipAddPathLine(path, start[0].X, start[0].Y, end[0].X, end[0].Y); if (drawE && drawN) DllExports._GdipAddPathArc(path, x + width - rx*2.0f, y, rx*2.0f, ry*2.0f, 270.0f, 90.0f); /* top-right */ DllExports._GdipAddPathLine(path, start[1].X, start[1].Y, end[1].X, end[1].Y); if (drawE && drawS) DllExports._GdipAddPathArc(path, x + width - rx*2.0f, y + height - ry*2.0f, rx*2.0f, ry*2.0f, 0.0f, 90.0f); /* bottom-right */ DllExports._GdipAddPathLine(path, start[2].X, start[2].Y, end[2].X, end[2].Y); if (drawW && drawS) DllExports._GdipAddPathArc(path, x, y + height - ry*2.0f, rx*2.0f, ry*2.0f, 90.0f, 90.0f); /* bottom-left */ DllExports._GdipAddPathLine(path, start[3].X, start[3].Y, end[3].X, end[3].Y); } } void Tree_FillRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ XColor *xcolor, /* Color. */ TreeRectangle tr, /* Recangle to paint. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { HDC hDC; TkWinDCState dcState; TreeClipStateGraphics clipState; GpGraphics *graphics; GpPath *path; ARGB color; GpSolidFill *brush; #ifdef ROUND_RECT_SYMMETRY_HACK GpPen *pen; #endif GpStatus status; if (!tree->nativeGradients || (DllExports.handle == NULL)) { GC gc = Tk_GCForColor(xcolor, td.drawable); Tree_FillRoundRectX11(tree, td, clip, gc, tr, rx, ry, open); return; } hDC = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); status = DllExports._GdipCreateFromHDC(hDC, &graphics); if (status != Ok) goto error1; status = DllExports._GdipCreatePath(FillModeAlternate, &path); if (status != Ok) goto error2; color = MakeGDIPlusColor(xcolor,1.0f); status = DllExports._GdipCreateSolidFill(color, &brush); if (status != Ok) goto error3; #if !defined(ROUND_RECT_SYMMETRY_HACK) && 0 /* SmoothingModeHighQuality and SmoothingModeAntiAlias seem the same. */ DllExports._GdipSetSmoothingMode(graphics, SmoothingModeHighQuality); /* Antialiasing paints outside the rectangle. If I clip drawing to the * rectangle I still get artifacts on the "open" edges. */ // status = DllExports._GdipSetClipRectI(graphics, // tr.x, tr.y, tr.width, tr.height, CombineModeReplace); #endif GetRoundRectPath_Fill(path, tr, rx, ry, open #ifdef ROUND_RECT_SYMMETRY_HACK , 1 #endif ); status = TreeClip_ToGraphics(tree, clip, graphics, &clipState); if (status != Ok) goto error4; DllExports._GdipFillPath(graphics, brush, path); #ifdef ROUND_RECT_SYMMETRY_HACK status = DllExports._GdipCreatePen1(color, 1, UnitPixel, &pen); if (status != Ok) goto error4; /* See comments above for why this is done */ DllExports._GdipResetPath(path); GetRoundRectPath_Outline(path, tr, rx, ry, open, 0, 0, 0); DllExports._GdipDrawPath(graphics, pen, path); DllExports._GdipDeletePen(pen); #endif /* ROUND_RECT_SYMMETRY_HACK */ error4: DllExports._GdipDeleteBrush(brush); error3: DllExports._GdipDeletePath(path); error2: DllExports._GdipDeleteGraphics(graphics); error1: TkWinReleaseDrawableDC(td.drawable, hDC, &dcState); } void TreeGradient_FillRoundRect( TreeCtrl *tree, /* Widget info. */ TreeDrawable td, /* Where to draw. */ TreeClip *clip, /* Clipping area or NULL. */ TreeGradient gradient, /* Gradient token. */ TreeRectangle trBrush, /* Brush bounds. */ TreeRectangle tr, /* Rectangle to paint. */ int rx, int ry, /* Corner radius */ int open /* RECT_OPEN_x flags */ ) { HDC hDC; TkWinDCState dcState; TreeClipStateGraphics clipState; GpGraphics *graphics; GpPath *path; GpLineGradient *lineGradient; GpPen *pen; GpStatus status; int canRepairCorners; if (gradient->stopArrPtr == NULL || gradient->stopArrPtr->nstops < 2) return; /* Draw nothing if the brush is zero-sized. */ if (trBrush.width <= 0 || trBrush.height <= 0) return; if (!tree->nativeGradients || (DllExports.handle == NULL)) { TreeGradient_FillRoundRectX11(tree, td, NULL, gradient, trBrush, tr, rx, ry, open); return; } hDC = TkWinGetDrawableDC(tree->display, td.drawable, &dcState); status = DllExports._GdipCreateFromHDC(hDC, &graphics); if (status != Ok) goto error1; status = DllExports._GdipCreatePath(FillModeAlternate, &path); if (status != Ok) goto error2; status = MakeLinearGradientBrush(gradient, trBrush, &lineGradient); if (status != Ok) goto error3; /* Filling the rounded rectangle gives asymmetric results at the corners. * If the gradient is fully opaque then the corners can be "repaired" by * drawing a 1-pixel thick outline after filling the shape. */ canRepairCorners = TreeGradient_IsOpaque(tree, gradient); GetRoundRectPath_Fill(path, tr, rx, ry, open #ifdef ROUND_RECT_SYMMETRY_HACK , canRepairCorners #endif ); status = TreeClip_ToGraphics(tree, clip, graphics, &clipState); if (status != Ok) goto error4; DllExports._GdipFillPath(graphics, lineGradient, path); if (canRepairCorners) { status = DllExports._GdipCreatePen2(lineGradient, 1, UnitPixel, &pen); if (status != Ok) goto error4; DllExports._GdipResetPath(path); GetRoundRectPath_Outline(path, tr, rx, ry, open, 0, 0, 0); DllExports._GdipDrawPath(graphics, pen, path); DllExports._GdipDeletePen(pen); } error4: DllExports._GdipDeleteBrush(lineGradient); error3: DllExports._GdipDeletePath(path); error2: DllExports._GdipDeleteGraphics(graphics); error1: TkWinReleaseDrawableDC(td.drawable, hDC, &dcState); } tktreectrl-2.4.1/winrc.m40000644000076400010400000000506411452412507015605 0ustar TimAdministrators# This was taken from Tk's configure.in and tcl.m4. AC_DEFUN([TREECTRL_PROG_RC], [ # AC_MSG_CHECKING([for windows resource compiler]) RC_DEPARG='"$<"' if test "${GCC}" = "yes" ; then AC_CHECK_PROG(RC, windres, windres) if test "${RC}" = "" ; then AC_MSG_ERROR([Required resource tool 'windres' not found on PATH.]) fi RC_OUT=-o RC_TYPE= RC_INCLUDE=--include RC_DEFINE=--define RES=res.o # Check for a bug in gcc's windres that causes the # compile to fail when a Windows native path is # passed into windres. The mingw toolchain requires # Windows native paths while Cygwin should work # with both. Avoid the bug by passing a POSIX # path when using the Cygwin toolchain. if test "$ac_cv_cygwin" != "yes" -a "$CYGPATH" != "echo" ; then conftest=/tmp/conftest.rc echo "STRINGTABLE BEGIN" > $conftest echo "101 \"name\"" >> $conftest echo "END" >> $conftest AC_MSG_CHECKING([for Windows native path bug in windres]) cyg_conftest=`$CYGPATH $conftest` if AC_TRY_COMMAND($RC -o conftest.res.o $cyg_conftest) ; then AC_MSG_RESULT([no]) RC_DEPARG='"$(shell $(CYGPATH) $<)"' else AC_MSG_RESULT([yes]) fi conftest= cyg_conftest= fi else if test "$do64bit" != "no" ; then RC="\"${MSSDK}/bin/rc.exe\"" elif test "$doWince" != "no" ; then RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" else RC="rc" fi RC_OUT=-fo RC_TYPE=-r RC_INCLUDE=-i RC_DEFINE=-d RES=res fi AC_SUBST(RC) AC_SUBST(RC_OUT) AC_SUBST(RC_TYPE) AC_SUBST(RC_INCLUDE) AC_SUBST(RC_DEFINE) AC_SUBST(RC_DEPARG) AC_SUBST(RES) ]) # This is basically TEA_ADD_SOURCES but sets the object file extension to # $RES instead of $OBJ. AC_DEFUN([TREECTRL_ADD_RC], [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${RES}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${RES}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${RES}" fi PKG_OBJECTS="$PKG_OBJECTS $j" TEA_ADD_CLEANFILES($j) ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ])