summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortreectrl <treectrl>2002-12-17 05:04:00 (GMT)
committertreectrl <treectrl>2002-12-17 05:04:00 (GMT)
commit51219bf94e57870b142db498f63180828d6990d9 (patch)
tree2aaef21ae17c7dc8591f1fdf095fb4fbeeef8197
downloadtktreectrl-51219bf94e57870b142db498f63180828d6990d9.zip
tktreectrl-51219bf94e57870b142db498f63180828d6990d9.tar.gz
tktreectrl-51219bf94e57870b142db498f63180828d6990d9.tar.bz2
Initial revision
-rw-r--r--Makefile.in451
-rw-r--r--aclocal.m49
-rw-r--r--configure7052
-rw-r--r--configure.ac210
-rw-r--r--demo.tcl935
-rw-r--r--demos/bitmaps.tcl55
-rw-r--r--demos/explorer.tcl367
-rw-r--r--demos/help.tcl347
-rw-r--r--demos/imovie.tcl111
-rw-r--r--demos/layout.tcl98
-rw-r--r--demos/mailwasher.tcl183
-rw-r--r--demos/outlook-folders.tcl106
-rw-r--r--demos/outlook-newgroup.tcl382
-rw-r--r--demos/random.tcl475
-rw-r--r--demos/www-options.tcl299
-rw-r--r--doc/manual.txt415
-rw-r--r--generic/qebind.c1992
-rw-r--r--generic/qebind.h67
-rw-r--r--generic/tkTreeColumn.c1547
-rw-r--r--generic/tkTreeCtrl.c2988
-rw-r--r--generic/tkTreeCtrl.h488
-rw-r--r--generic/tkTreeDisplay.c3618
-rw-r--r--generic/tkTreeDrag.c436
-rw-r--r--generic/tkTreeElem.c3436
-rw-r--r--generic/tkTreeElem.h79
-rw-r--r--generic/tkTreeItem.c3662
-rw-r--r--generic/tkTreeMarquee.c364
-rw-r--r--generic/tkTreeNotify.c389
-rw-r--r--generic/tkTreeStyle.c3652
-rw-r--r--generic/tkTreeUtils.c877
-rw-r--r--library/filelist-bindings.tcl788
-rw-r--r--library/treectrl.tcl825
-rw-r--r--pics/big-dll.gifbin0 -> 437 bytes
-rw-r--r--pics/big-exe.gifbin0 -> 368 bytes
-rw-r--r--pics/big-file.gifbin0 -> 466 bytes
-rw-r--r--pics/big-folder.gifbin0 -> 459 bytes
-rw-r--r--pics/big-txt.gifbin0 -> 392 bytes
-rw-r--r--pics/checked.gifbin0 -> 78 bytes
-rw-r--r--pics/file.gifbin0 -> 279 bytes
-rw-r--r--pics/folder-closed.gifbin0 -> 111 bytes
-rw-r--r--pics/folder-open.gifbin0 -> 120 bytes
-rw-r--r--pics/help-book-closed.gifbin0 -> 115 bytes
-rw-r--r--pics/help-book-open.gifbin0 -> 128 bytes
-rw-r--r--pics/help-page.gifbin0 -> 132 bytes
-rw-r--r--pics/imovie-01.gifbin0 -> 5406 bytes
-rw-r--r--pics/imovie-02.gifbin0 -> 5912 bytes
-rw-r--r--pics/imovie-03.gifbin0 -> 4696 bytes
-rw-r--r--pics/imovie-04.gifbin0 -> 5783 bytes
-rw-r--r--pics/imovie-05.gifbin0 -> 3238 bytes
-rw-r--r--pics/imovie-06.gifbin0 -> 3509 bytes
-rw-r--r--pics/imovie-07.gifbin0 -> 2091 bytes
-rw-r--r--pics/internet-check-off.gifbin0 -> 70 bytes
-rw-r--r--pics/internet-check-on.gifbin0 -> 76 bytes
-rw-r--r--pics/internet-print.gifbin0 -> 124 bytes
-rw-r--r--pics/internet-radio-off.gifbin0 -> 68 bytes
-rw-r--r--pics/internet-radio-on.gifbin0 -> 71 bytes
-rw-r--r--pics/internet-search.gifbin0 -> 114 bytes
-rw-r--r--pics/internet-security.gifbin0 -> 108 bytes
-rw-r--r--pics/mac-collapse.gifbin0 -> 275 bytes
-rw-r--r--pics/mac-expand.gifbin0 -> 277 bytes
-rw-r--r--pics/outlook-arrow.gifbin0 -> 73 bytes
-rw-r--r--pics/outlook-clip.gifbin0 -> 73 bytes
-rw-r--r--pics/outlook-deleted.gifbin0 -> 138 bytes
-rw-r--r--pics/outlook-draft.gifbin0 -> 134 bytes
-rw-r--r--pics/outlook-folder.gifbin0 -> 133 bytes
-rw-r--r--pics/outlook-group.gifbin0 -> 144 bytes
-rw-r--r--pics/outlook-inbox.gifbin0 -> 133 bytes
-rw-r--r--pics/outlook-local.gifbin0 -> 146 bytes
-rw-r--r--pics/outlook-main.gifbin0 -> 174 bytes
-rw-r--r--pics/outlook-outbox.gifbin0 -> 136 bytes
-rw-r--r--pics/outlook-read-2.gifbin0 -> 343 bytes
-rw-r--r--pics/outlook-read.gifbin0 -> 304 bytes
-rw-r--r--pics/outlook-sent.gifbin0 -> 132 bytes
-rw-r--r--pics/outlook-server.gifbin0 -> 163 bytes
-rw-r--r--pics/outlook-unread.gifbin0 -> 303 bytes
-rw-r--r--pics/outlook-watch.gifbin0 -> 98 bytes
-rw-r--r--pics/small-dll.gifbin0 -> 311 bytes
-rw-r--r--pics/small-exe.gifbin0 -> 115 bytes
-rw-r--r--pics/small-file.gifbin0 -> 338 bytes
-rw-r--r--pics/small-folder.gifbin0 -> 307 bytes
-rw-r--r--pics/small-txt.gifbin0 -> 302 bytes
-rw-r--r--pics/unchecked.gifbin0 -> 72 bytes
-rw-r--r--pkgIndex.tcl.in9
-rw-r--r--tclconfig/ChangeLog161
-rw-r--r--tclconfig/README.txt26
-rw-r--r--tclconfig/install-sh119
-rw-r--r--tclconfig/tcl.m43171
87 files changed, 40189 insertions, 0 deletions
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..b6b4d28
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,451 @@
+# 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.
+#
+# RCS: @(#) $Id: Makefile.in,v 1.1 2002/12/17 05:04:20 treectrl Exp $
+
+#========================================================================
+# Edit the following few lines when writing a new extension
+#========================================================================
+
+#========================================================================
+# Enumerate the names of the source files included in this package.
+# This will be used when a dist target is added to the Makefile.
+# EXTRA_SOURCES will be replaced by WIN_SOURCES or UNIX_SOURCES, as is
+# appropriate for your platform. It is not important to specify the
+# directory, as long as it is the $(srcdir) or in the generic, win or
+# unix subdirectory.
+#========================================================================
+
+treectrl_SOURCES = \
+ qebind.c \
+ tkTreeColumn.c \
+ tkTreeCtrl.c \
+ tkTreeDisplay.c \
+ tkTreeDrag.c \
+ tkTreeElem.c \
+ tkTreeItem.c \
+ tkTreeMarquee.c \
+ tkTreeNotify.c \
+ tkTreeStyle.c \
+ tkTreeUtils.c \
+ @EXTRA_SOURCES@
+
+WIN_SOURCES =
+UNIX_SOURCES =
+
+#========================================================================
+# Identify the object files. This replaces .c with .$(OBJEXT) for all
+# the named source files. These objects are created and linked into the
+# final library. In these do not correspond directly to the source files
+# above, you will need to enumerate the object files here.
+# Normally we would use $(OBJEXT), but certain make executables won't do
+# the extra macro in a macro conversion properly.
+#
+# "sample_LIB_FILE" refers to the library (dynamic or static as per
+# configuration options) composed of the named objects.
+#========================================================================
+
+treectrl_OBJECTS = $(treectrl_SOURCES:.c=.@OBJEXT@)
+treectrl_LIB_FILE = @treectrl_LIB_FILE@
+
+#========================================================================
+# RUNTIME_SOURCES identifies Tcl runtime files that are associated with
+# this package that need to be installed, if any.
+#========================================================================
+
+RUNTIME_SOURCES = treectrl.tcl filelist-bindings.tcl
+
+#========================================================================
+# This is a list of header files to be installed
+#========================================================================
+
+GENERIC_HDRS =
+
+#========================================================================
+# Add additional lines to handle any additional AC_SUBST cases that
+# have been added to the configure script.
+#========================================================================
+
+#SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@
+
+#========================================================================
+# 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 variable "$(PACKAGE)_LIB_FILE" is the parameterized name of the
+# library that we are building.
+#========================================================================
+
+lib_BINARIES = $($(PACKAGE)_LIB_FILE)
+BINARIES = $(lib_BINARIES)
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+libdir = @libdir@
+datadir = @datadir@
+mandir = @mandir@
+includedir = @includedir@
+
+DESTDIR =
+
+PKG_DIR = $(PACKAGE)$(VERSION)
+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 = @PACKAGE@
+VERSION = @VERSION@
+CC = @CC@
+CFLAGS_DEBUG = @CFLAGS_DEBUG@
+CFLAGS_DEFAULT = @CFLAGS_DEFAULT@
+CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@
+CLEANFILES = @CLEANFILES@
+EXEEXT = @EXEEXT@
+LDFLAGS_DEBUG = @LDFLAGS_DEBUG@
+LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@
+LDFLAGS_OPTIMIZE = @LDFLAGS_OPTIMIZE@
+MAKE_LIB = @MAKE_LIB@
+MAKE_SHARED_LIB = @MAKE_SHARED_LIB@
+MAKE_STATIC_LIB = @MAKE_STATIC_LIB@
+OBJEXT = @OBJEXT@
+RANLIB = @RANLIB@
+SHLIB_CFLAGS = @SHLIB_CFLAGS@
+SHLIB_LD = @SHLIB_LD@
+SHLIB_LDFLAGS = @SHLIB_LDFLAGS@
+SHLIB_LD_LIBS = @SHLIB_LD_LIBS@
+STLIB_LD = @STLIB_LD@
+TCL_DEFS = @TCL_DEFS@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+# This is necessary for packages that use private Tcl headers
+TCL_TOP_DIR_NATIVE = @TCL_TOP_DIR_NATIVE@
+TK_SRC_DIR = @TK_SRC_DIR@
+TK_TOP_DIR_NATIVE = @TK_TOP_DIR_NATIVE@
+# Not used, but retained for reference of what libs Tcl required
+TCL_LIBS = @TCL_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)
+TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \
+ LD_LIBRARY_PATH="$(EXTRA_PATH):$(LD_LIBRARY_PATH)" \
+ LIBPATH="$(EXTRA_PATH):${LIBPATH}" \
+ SHLIB_PATH="$(EXTRA_PATH):${SHLIB_PATH}" \
+ PATH="$(EXTRA_PATH):$(PATH)" \
+ TCLLIBPATH="$(top_builddir)"
+TCLSH_PROG = @TCLSH_PROG@
+TCLSH = $(TCLSH_ENV) $(TCLSH_PROG)
+SHARED_BUILD = @SHARED_BUILD@
+
+INCLUDES = @TCL_INCLUDES@ @TK_INCLUDES@
+
+EXTRA_CFLAGS = $(MEM_DEBUG_FLAGS) @EXTRA_CFLAGS@
+
+DEFS = $(TCL_DEFS) @DEFS@ $(EXTRA_CFLAGS)
+
+CONFIG_CLEAN_FILES = Makefile
+
+CPPFLAGS = @CPPFLAGS@
+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) pkgIndex.tcl
+
+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
+ if test "x$(SHARED_BUILD)" = "x1"; then \
+ $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \
+ fi
+
+#========================================================================
+# This rule installs platform-independent files, such as header files.
+#========================================================================
+
+install-libraries: libraries
+ @mkdir -p $(DESTDIR)$(includedir)
+ @echo "Installing header files in $(DESTDIR)$(includedir)"
+ @for i in $(GENERIC_HDRS) ; do \
+ echo "Installing $$i" ; \
+ $(INSTALL_DATA) $$i $(DESTDIR)$(includedir) ; \
+ done;
+
+#========================================================================
+# Install documentation. Unix manpages should go in the $(mandir)
+# directory.
+#========================================================================
+
+install-doc-x: doc
+ @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:
+ @echo "No docs to install"
+
+test: binaries libraries
+ $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS)
+
+shell: binaries libraries
+ @$(TCLSH) $(SCRIPT)
+
+gdb:
+ $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT)
+
+depend:
+
+#========================================================================
+# $($(PACKAGE)_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 $($(PACKAGE)_OBJECTS) objects are created and linked into the final
+# library. In most cases these object files will correspond to the
+# source files above.
+#========================================================================
+
+$($(PACKAGE)_LIB_FILE): $($(PACKAGE)_OBJECTS)
+ -rm -f $($(PACKAGE)_LIB_FILE)
+ ${MAKE_LIB}
+ $(RANLIB) $($(PACKAGE)_LIB_FILE)
+
+#========================================================================
+# We need to enumerate the list of .c to .o lines here.
+#
+# 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:
+#
+# sample.$(OBJEXT): $(srcdir)/generic/sample.c
+# $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.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.
+# As necessary, add $(srcdir):$(srcdir)/compat:....
+#========================================================================
+
+# I added leading $(srcdir) because autoconf 2.53 strips it off
+VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win
+
+.c.$(OBJEXT):
+ $(COMPILE) -c `@CYGPATH@ $<` -o $@
+
+#========================================================================
+# Create the pkgIndex.tcl file.
+# It is usually easiest to let Tcl do this for you with pkg_mkIndex, but
+# you may find that you need to customize the package. If so, either
+# modify the -hand version, or create a pkgIndex.tcl.in file and have
+# the configure script output the pkgIndex.tcl by editing configure.in.
+#========================================================================
+
+pkgIndex.tcl-x:
+ ( echo pkg_mkIndex . $($(PACKAGE)_LIB_FILE) \; exit; ) | $(TCLSH)
+
+pkgIndex.tcl-hand:
+ (echo 'package ifneeded $(PACKAGE) $(VERSION) \
+ [list load [file join $$dir $($(PACKAGE)_LIB_FILE)]]'\
+ ) > 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)/ChangeLog $(srcdir)/README* $(srcdir)/license* \
+ $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \
+ $(DIST_DIR)/
+ chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4
+ chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in
+
+ 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='$(RUNTIME_SOURCES)'; for p in $$list; do \
+ if test -f $(srcdir)/library/$$p; then \
+ echo " Install $$p $(DESTDIR)$(pkglibdir)/$$p"; \
+ $(INSTALL_DATA) $(srcdir)/library/$$p $(DESTDIR)$(pkglibdir)/$$p; \
+ 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)
+
+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='$(RUNTIME_SOURCES)'; for p in $$list; do \
+ 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:
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..0b05739
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,9 @@
+#
+# Include the TEA standard macro set
+#
+
+builtin(include,tclconfig/tcl.m4)
+
+#
+# Add here whatever m4 macros you want to define for your package
+#
diff --git a/configure b/configure
new file mode 100644
index 0000000..63a3898
--- /dev/null
+++ b/configure
@@ -0,0 +1,7052 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.56.
+#
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+# 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 Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; 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
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# 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
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ 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
+
+ ;;
+ 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
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); 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 sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="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="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="generic/tkTreeCtrl.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CONFIGDIR PACKAGE VERSION treectrl_LIB_FILE CYGPATH EXEEXT TCL_VERSION TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_LIBS TCL_DEFS TCL_EXTRA_CFLAGS TCL_LD_FLAGS TCL_SHLIB_LD_LIBS TK_VERSION TK_BIN_DIR TK_SRC_DIR TK_LIB_FILE TK_LIB_FLAG TK_LIB_SPEC TK_STUB_LIB_FILE TK_STUB_LIB_FLAG TK_STUB_LIB_SPEC TK_LIBS TK_XINCLUDES CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA SET_MAKE RANLIB ac_ct_RANLIB TCL_TOP_DIR_NATIVE TCL_GENERIC_DIR_NATIVE TCL_UNIX_DIR_NATIVE TCL_WIN_DIR_NATIVE TCL_BMAP_DIR_NATIVE TCL_TOOL_DIR_NATIVE TCL_PLATFORM_DIR_NATIVE TCL_INCLUDES TK_TOP_DIR_NATIVE TK_UNIX_DIR_NATIVE TK_WIN_DIR_NATIVE TK_GENERIC_DIR_NATIVE TK_XLIB_DIR_NATIVE TK_PLATFORM_DIR_NATIVE TK_INCLUDES CLEANFILES EXTRA_SOURCES TCL_THREADS SHARED_BUILD AR CPP EGREP DL_LIBS CFLAGS_DEBUG CFLAGS_OPTIMIZE CFLAGS_WARNING EXTRA_CFLAGS STLIB_LD SHLIB_LD SHLIB_CFLAGS SHLIB_LDFLAGS SHLIB_LD_LIBS LDFLAGS_DEBUG LDFLAGS_OPTIMIZE TCL_DBGX CFLAGS_DEFAULT LDFLAGS_DEFAULT MAKE_LIB MAKE_SHARED_LIB MAKE_STATIC_LIB MAKE_STUB_LIB TCLSH_PROG WISH_PROG LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# 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.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+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
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -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 | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$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 ;;
+
+ -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 ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ 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 ;;
+
+ -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_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=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 ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ 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'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+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
+ 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
+
+
+# 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 its parent.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ 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
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# 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 this package 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 \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+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]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --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]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --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 --enable-shared
+ --enable-64bit enable 64bit support (where applicable)
+ --enable-64bit-vis enable 64bit Sparc VIS support
+ --disable-load disallow dynamic loading and "load" command
+ --enable-symbols build with debugging symbols --disable-symbols
+
+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)
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style 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
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+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 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.56. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+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`
+hostinfo = `(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=.
+ echo "PATH: $as_dir"
+done
+
+} >&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_sep=
+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=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$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
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export 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: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core core.* *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >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
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ 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.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+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 `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; 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,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+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
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`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.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+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_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
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in tclconfig $srcdir/tclconfig" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in tclconfig $srcdir/tclconfig" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+CONFIGDIR=${srcdir}/tclconfig
+
+
+#----------------------------------------------------------------------
+# __CHANGE__
+# Set your package name and version numbers here. The NODOT_VERSION is
+# required for constructing the library name on systems that don't like
+# dots in library names (Windows). The VERSION variable is used on the
+# other systems.
+#----------------------------------------------------------------------
+
+PACKAGE=treectrl
+
+MAJOR_VERSION=1
+MINOR_VERSION=0
+PATCHLEVEL=
+
+VERSION=${MAJOR_VERSION}.${MINOR_VERSION}${PATCHLEVEL}
+NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
+
+
+
+# This package name must be replaced statically for AC_SUBST to work
+
+# Substitute stub_LIB_FILE if your package creates a stub library too.
+#AC_SUBST(samplestub_LIB_FILE)
+
+#--------------------------------------------------------------------
+# We put this here so that you can compile with -DVERSION="1.2" to
+# encode the package version directly into the source files.
+#--------------------------------------------------------------------
+
+eval cat >>confdefs.h <<_ACEOF
+#define VERSION "${VERSION}"
+_ACEOF
+
+
+#--------------------------------------------------------------------
+# Call TEA_INIT as the first TEA_ macro to set up initial vars.
+# This will define a ${TEA_PLATFORM} variable == "unix" or "windows".
+#--------------------------------------------------------------------
+
+
+ echo "$as_me:$LINENO: checking for correct TEA configuration" >&5
+echo $ECHO_N "checking for correct TEA configuration... $ECHO_C" >&6
+ if test x"${PACKAGE}" = x ; then
+ { { echo "$as_me:$LINENO: error:
+The PACKAGE variable must be defined by your TEA configure.in" >&5
+echo "$as_me: error:
+The PACKAGE variable must be defined by your TEA configure.in" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ echo "$as_me:$LINENO: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+ TEA_INITED=ok
+ case "`uname -s`" in
+ *win32*|*WIN32*|*CYGWIN_NT*|*CYGWIN_9*|*CYGWIN_ME*|*MINGW32_*)
+ # Extract the first word of "cygpath", so it can be a program name with args.
+set dummy cygpath; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CYGPATH+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CYGPATH="cygpath -w"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo"
+fi
+fi
+CYGPATH=$ac_cv_prog_CYGPATH
+if test -n "$CYGPATH"; then
+ echo "$as_me:$LINENO: result: $CYGPATH" >&5
+echo "${ECHO_T}$CYGPATH" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ EXEEXT=".exe"
+ TEA_PLATFORM="windows"
+ ;;
+ *)
+ CYGPATH=echo
+ EXEEXT=""
+ TEA_PLATFORM="unix"
+ ;;
+ esac
+
+
+
+
+
+#--------------------------------------------------------------------
+# Load the tclConfig.sh file
+#--------------------------------------------------------------------
+
+
+ if test x"${TEA_INITED}" = x ; then
+ # Can't refer to exact macro name or it will be substituted
+ { { echo "$as_me:$LINENO: error: Must call TEA INIT before PATH_TCLCONFIG" >&5
+echo "$as_me: error: Must call TEA INIT before PATH_TCLCONFIG" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ #
+ # 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 or --without-tcl was given.
+if test "${with_tcl+set}" = set; then
+ withval="$with_tcl"
+ with_tclconfig=${withval}
+fi;
+ echo "$as_me:$LINENO: checking for Tcl configuration" >&5
+echo $ECHO_N "checking for Tcl configuration... $ECHO_C" >&6
+ if test "${ac_cv_c_tclconfig+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+
+ # First check to see if --with-tcl was specified.
+ if test x"${with_tclconfig}" != x ; then
+ if test -f "${with_tclconfig}/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
+ else
+ { { echo "$as_me:$LINENO: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&5
+echo "$as_me: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&2;}
+ { (exit 1); exit 1; }; }
+ 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]* 2>/dev/null` \
+ ../../tcl \
+ `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \
+ ../../../tcl \
+ `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do
+ if test -f "$i/unix/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd $i/unix; 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 ${exec_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` \
+ ; 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]* 2>/dev/null` ; do
+ 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"
+ { echo "$as_me:$LINENO: WARNING: \"Cannot find Tcl configuration definitions\"" >&5
+echo "$as_me: WARNING: \"Cannot find Tcl configuration definitions\"" >&2;}
+ exit 0
+ else
+ no_tcl=
+ TCL_BIN_DIR=${ac_cv_c_tclconfig}
+ echo "$as_me:$LINENO: result: found $TCL_BIN_DIR/tclConfig.sh" >&5
+echo "${ECHO_T}found $TCL_BIN_DIR/tclConfig.sh" >&6
+ fi
+ fi
+
+
+ echo "$as_me:$LINENO: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5
+echo $ECHO_N "checking for existence of $TCL_BIN_DIR/tclConfig.sh... $ECHO_C" >&6
+
+ if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
+ echo "$as_me:$LINENO: result: loading" >&5
+echo "${ECHO_T}loading" >&6
+ . $TCL_BIN_DIR/tclConfig.sh
+ else
+ echo "$as_me:$LINENO: result: file not found" >&5
+echo "${ECHO_T}file not found" >&6
+ fi
+
+ #
+ # 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}
+ fi
+
+ #
+ # eval is required to do the TCL_DBGX substitution
+ #
+
+ eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
+ eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
+ eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
+
+ eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
+ eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
+ eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #AC_SUBST(TCL_DBGX)
+
+
+
+
+
+ #AC_SUBST(TCL_BUILD_LIB_SPEC)
+ #AC_SUBST(TCL_BUILD_STUB_LIB_SPEC)
+
+
+#--------------------------------------------------------------------
+# 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 or --without-tk was given.
+if test "${with_tk+set}" = set; then
+ withval="$with_tk"
+ with_tkconfig=${withval}
+fi;
+ echo "$as_me:$LINENO: checking for Tk configuration" >&5
+echo $ECHO_N "checking for Tk configuration... $ECHO_C" >&6
+ if test "${ac_cv_c_tkconfig+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+
+ # First check to see if --with-tkconfig was specified.
+ if test x"${with_tkconfig}" != x ; then
+ if test -f "${with_tkconfig}/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)`
+ else
+ { { echo "$as_me:$LINENO: error: ${with_tkconfig} directory doesn't contain tkConfig.sh" >&5
+echo "$as_me: error: ${with_tkconfig} directory doesn't contain tkConfig.sh" >&2;}
+ { (exit 1); exit 1; }; }
+ 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]* 2>/dev/null` \
+ ../../tk \
+ `ls -dr ../../tk[8-9].[0-9]* 2>/dev/null` \
+ ../../../tk \
+ `ls -dr ../../../tk[8-9].[0-9]* 2>/dev/null` ; do
+ if test -f "$i/unix/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd $i/unix; 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 ${exec_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` \
+ ; 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]* 2>/dev/null` ; do
+ 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"
+ { echo "$as_me:$LINENO: WARNING: \"Cannot find Tk configuration definitions\"" >&5
+echo "$as_me: WARNING: \"Cannot find Tk configuration definitions\"" >&2;}
+ exit 0
+ else
+ no_tk=
+ TK_BIN_DIR=${ac_cv_c_tkconfig}
+ echo "$as_me:$LINENO: result: found $TK_BIN_DIR/tkConfig.sh" >&5
+echo "${ECHO_T}found $TK_BIN_DIR/tkConfig.sh" >&6
+ fi
+ fi
+
+
+
+ echo "$as_me:$LINENO: checking for existence of ${TK_BIN_DIR}/tkConfig.sh" >&5
+echo $ECHO_N "checking for existence of ${TK_BIN_DIR}/tkConfig.sh... $ECHO_C" >&6
+
+ if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then
+ echo "$as_me:$LINENO: result: loading" >&5
+echo "${ECHO_T}loading" >&6
+ . $TK_BIN_DIR/tkConfig.sh
+ else
+ echo "$as_me:$LINENO: result: could not find ${TK_BIN_DIR}/tkConfig.sh" >&5
+echo "${ECHO_T}could not find ${TK_BIN_DIR}/tkConfig.sh" >&6
+ fi
+
+ #
+ # 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}
+ fi
+
+ #
+ # eval is required to do the TK_DBGX substitution
+ #
+
+ eval "TK_LIB_FILE=\"${TK_LIB_FILE}\""
+ eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\""
+ eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\""
+
+ eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\""
+ eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\""
+ eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#-----------------------------------------------------------------------
+# Handle the --prefix=... option by defaulting to what Tcl gave.
+# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER.
+#-----------------------------------------------------------------------
+
+
+ # Should be AC_MSG_NOTICE, but that requires autoconf 2.50
+ if test "${prefix}" = "NONE"; then
+ prefix_default=yes
+ if test x"${TCL_PREFIX}" != x; then
+ { echo "$as_me:$LINENO: WARNING: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&5
+echo "$as_me: WARNING: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&2;}
+ prefix=${TCL_PREFIX}
+ else
+ prefix=/usr/local
+ fi
+ fi
+ if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" ; then
+ if test x"${TCL_EXEC_PREFIX}" != x; then
+ { echo "$as_me:$LINENO: WARNING: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&5
+echo "$as_me: WARNING: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&2;}
+ exec_prefix=${TCL_EXEC_PREFIX}
+ else
+ 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.
+#-----------------------------------------------------------------------
+
+
+
+ # 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
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+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
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+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
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$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"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+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
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ 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
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out 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.
+echo "$as_me:$LINENO: checking for C compiler default output" >&5
+echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; 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 | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$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
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* 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;
+}
+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
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ ''\
+ '#include <stdlib.h>' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+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 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
+ echo "$as_me:$LINENO: checking if the compiler understands -pipe" >&5
+echo $ECHO_N "checking if the compiler understands -pipe... $ECHO_C" >&6
+ OLDCC="$CC"
+ CC="$CC -pipe"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+CC="$OLDCC"
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ fi
+
+ # 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"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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/* | \
+ /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 $as_executable_p "$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
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+
+
+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. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$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'
+
+
+ #--------------------------------------------------------------------
+ # Checks to see if the make program sets the $MAKE variable.
+ #--------------------------------------------------------------------
+
+ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+ #--------------------------------------------------------------------
+ # Determines the correct binary file extension (.o, .obj, .exe etc.)
+ #--------------------------------------------------------------------
+
+
+
+
+
+#--------------------------------------------------------------------
+# __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
+
+ echo "$as_me:$LINENO: checking for Tcl private include files" >&5
+echo $ECHO_N "checking for Tcl private include files... $ECHO_C" >&6
+
+ if test "${TEA_PLATFORM}" = "windows"; then
+ TCL_TOP_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}`\"
+ TCL_GENERIC_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/generic`\"
+ TCL_UNIX_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/unix`\"
+ TCL_WIN_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/win`\"
+ TCL_BMAP_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/bitmaps`\"
+ TCL_TOOL_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/tools`\"
+ TCL_COMPAT_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/compat`\"
+ TCL_PLATFORM_DIR_NATIVE=${TCL_WIN_DIR_NATIVE}
+ else
+ TCL_TOP_DIR_NATIVE='$(TCL_SRC_DIR)'
+ TCL_GENERIC_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/generic'
+ TCL_UNIX_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/unix'
+ TCL_WIN_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/win'
+ TCL_BMAP_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/bitmaps'
+ TCL_TOOL_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/tools'
+ TCL_COMPAT_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/compat'
+ TCL_PLATFORM_DIR_NATIVE=${TCL_UNIX_DIR_NATIVE}
+ fi
+
+
+
+
+
+
+
+
+
+ TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}"
+
+ echo "$as_me:$LINENO: result: Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" >&5
+echo "${ECHO_T}Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}" >&6
+
+
+#TEA_PUBLIC_TK_HEADERS
+
+ echo "$as_me:$LINENO: checking for Tk private include files" >&5
+echo $ECHO_N "checking for Tk private include files... $ECHO_C" >&6
+
+ if test "${TEA_PLATFORM}" = "windows"; then
+ TK_TOP_DIR_NATIVE=\"`${CYGPATH} ${TK_SRC_DIR}`\"
+ TK_UNIX_DIR_NATIVE=\"`${CYGPATH} ${TK_SRC_DIR}/unix`\"
+ TK_WIN_DIR_NATIVE=\"`${CYGPATH} ${TK_SRC_DIR}/win`\"
+ TK_GENERIC_DIR_NATIVE=\"`${CYGPATH} ${TK_SRC_DIR}/generic`\"
+ TK_XLIB_DIR_NATIVE=\"`${CYGPATH} ${TK_SRC_DIR}/xlib`\"
+ TK_PLATFORM_DIR_NATIVE=${TK_WIN_DIR_NATIVE}
+
+ TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE} -I${TK_XLIB_DIR_NATIVE}"
+ else
+ TK_TOP_DIR_NATIVE='$(TK_SRC_DIR)'
+ TK_GENERIC_DIR_NATIVE='$(TK_TOP_DIR_NATIVE)/generic'
+ TK_UNIX_DIR_NATIVE='$(TK_TOP_DIR_NATIVE)/unix'
+ TK_WIN_DIR_NATIVE='$(TK_TOP_DIR_NATIVE)/win'
+ TK_PLATFORM_DIR_NATIVE=${TK_UNIX_DIR_NATIVE}
+
+ TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}"
+ fi
+
+
+
+
+
+
+
+
+
+ echo "$as_me:$LINENO: result: Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" >&5
+echo "${ECHO_T}Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}" >&6
+
+
+#--------------------------------------------------------------------
+# __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.
+#--------------------------------------------------------------------
+
+if test "${TEA_PLATFORM}" = "windows" ; then
+ cat >>confdefs.h <<\_ACEOF
+#define BUILD_treectrl 1
+_ACEOF
+
+ CLEANFILES="pkgIndex.tcl *.lib *.dll *.exp *.ilk *.pdb vc*.pch"
+ EXTRA_SOURCES='$(WIN_SOURCES)'
+else
+ CLEANFILES="pkgIndex.tcl"
+ EXTRA_SOURCES='$(UNIX_SOURCES)'
+fi
+
+
+
+#--------------------------------------------------------------------
+# Check whether --enable-threads or --disable-threads was given.
+#--------------------------------------------------------------------
+
+
+ # Check whether --enable-threads or --disable-threads was given.
+if test "${enable_threads+set}" = set; then
+ enableval="$enable_threads"
+ tcl_ok=$enableval
+else
+ tcl_ok=
+fi;
+
+ if test "$tcl_ok" = "yes"; then
+ TCL_THREADS=1
+
+ if test "${TEA_PLATFORM}" != "windows" ; then
+ # We are always OK on Windows, so check what this platform wants.
+ cat >>confdefs.h <<\_ACEOF
+#define USE_THREAD_ALLOC 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define _REENTRANT 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define _THREAD_SAFE 1
+_ACEOF
+
+ echo "$as_me:$LINENO: checking for pthread_mutex_init in -lpthread" >&5
+echo $ECHO_N "checking for pthread_mutex_init in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread_pthread_mutex_init+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_mutex_init ();
+int
+main ()
+{
+pthread_mutex_init ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread_pthread_mutex_init=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread_pthread_mutex_init=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread_pthread_mutex_init" >&6
+if test $ac_cv_lib_pthread_pthread_mutex_init = 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]
+ echo "$as_me:$LINENO: checking for __pthread_mutex_init in -lpthread" >&5
+echo $ECHO_N "checking for __pthread_mutex_init in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread___pthread_mutex_init+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char __pthread_mutex_init ();
+int
+main ()
+{
+__pthread_mutex_init ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread___pthread_mutex_init=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread___pthread_mutex_init=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread___pthread_mutex_init" >&6
+if test $ac_cv_lib_pthread___pthread_mutex_init = 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
+ echo "$as_me:$LINENO: checking for pthread_mutex_init in -lpthreads" >&5
+echo $ECHO_N "checking for pthread_mutex_init in -lpthreads... $ECHO_C" >&6
+if test "${ac_cv_lib_pthreads_pthread_mutex_init+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthreads $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_mutex_init ();
+int
+main ()
+{
+pthread_mutex_init ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthreads_pthread_mutex_init=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthreads_pthread_mutex_init=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5
+echo "${ECHO_T}$ac_cv_lib_pthreads_pthread_mutex_init" >&6
+if test $ac_cv_lib_pthreads_pthread_mutex_init = yes; then
+ tcl_ok=yes
+else
+ tcl_ok=no
+fi
+
+ if test "$tcl_ok" = "yes"; then
+ # The space is needed
+ THREADS_LIBS=" -lpthreads"
+ else
+ echo "$as_me:$LINENO: checking for pthread_mutex_init in -lc" >&5
+echo $ECHO_N "checking for pthread_mutex_init in -lc... $ECHO_C" >&6
+if test "${ac_cv_lib_c_pthread_mutex_init+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_mutex_init ();
+int
+main ()
+{
+pthread_mutex_init ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_pthread_mutex_init=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_c_pthread_mutex_init=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_pthread_mutex_init" >&5
+echo "${ECHO_T}$ac_cv_lib_c_pthread_mutex_init" >&6
+if test $ac_cv_lib_c_pthread_mutex_init = yes; then
+ tcl_ok=yes
+else
+ tcl_ok=no
+fi
+
+ if test "$tcl_ok" = "no"; then
+ echo "$as_me:$LINENO: checking for pthread_mutex_init in -lc_r" >&5
+echo $ECHO_N "checking for pthread_mutex_init in -lc_r... $ECHO_C" >&6
+if test "${ac_cv_lib_c_r_pthread_mutex_init+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc_r $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_mutex_init ();
+int
+main ()
+{
+pthread_mutex_init ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_c_r_pthread_mutex_init=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_c_r_pthread_mutex_init=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5
+echo "${ECHO_T}$ac_cv_lib_c_r_pthread_mutex_init" >&6
+if test $ac_cv_lib_c_r_pthread_mutex_init = 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
+ { echo "$as_me:$LINENO: WARNING: \"Don t know how to find pthread lib on your system - thread support disabled\"" >&5
+echo "$as_me: WARNING: \"Don t know how to find pthread lib on your system - thread support disabled\"" >&2;}
+ fi
+ fi
+ fi
+ fi
+
+ # Does the pthread-implementation provide
+ # 'pthread_attr_setstacksize' ?
+
+for ac_func in pthread_attr_setstacksize
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* 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_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+ fi
+ else
+ TCL_THREADS=0
+ fi
+ # Do checking message here to not mess up interleaved configure output
+ echo "$as_me:$LINENO: checking for building with threads" >&5
+echo $ECHO_N "checking for building with threads... $ECHO_C" >&6
+ if test "${TCL_THREADS}" = "1"; then
+ cat >>confdefs.h <<\_ACEOF
+#define TCL_THREADS 1
+_ACEOF
+
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ else
+ echo "$as_me:$LINENO: result: no (default)" >&5
+echo "${ECHO_T}no (default)" >&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
+ { echo "$as_me:$LINENO: WARNING:
+ Building ${PACKAGE} without threads enabled, but building against a Tcl
+ that IS thread-enabled." >&5
+echo "$as_me: WARNING:
+ Building ${PACKAGE} without threads enabled, but building against a Tcl
+ that IS thread-enabled." >&2;}
+ fi
+ ;;
+ *)
+ if test "${TCL_THREADS}" = "1"; then
+ { echo "$as_me:$LINENO: WARNING:
+ --enable-threads requested, but attempting building against a Tcl
+ that is NOT thread-enabled." >&5
+echo "$as_me: WARNING:
+ --enable-threads requested, but attempting building against a Tcl
+ that is NOT thread-enabled." >&2;}
+ fi
+ ;;
+ esac
+
+
+
+#--------------------------------------------------------------------
+# The statement below defines a collection of symbols related to
+# building as a shared library instead of a static library.
+#--------------------------------------------------------------------
+
+
+ echo "$as_me:$LINENO: checking how to build libraries" >&5
+echo $ECHO_N "checking how to build libraries... $ECHO_C" >&6
+ # Check whether --enable-shared or --disable-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
+ echo "$as_me:$LINENO: result: shared" >&5
+echo "${ECHO_T}shared" >&6
+ SHARED_BUILD=1
+ else
+ echo "$as_me:$LINENO: result: static" >&5
+echo "${ECHO_T}static" >&6
+ SHARED_BUILD=0
+ cat >>confdefs.h <<\_ACEOF
+#define STATIC_BUILD 1
+_ACEOF
+
+ 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.
+#--------------------------------------------------------------------
+
+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
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&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
+ echo $ECHO_N "(cached) $ECHO_C" >&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.
+ # 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 >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <assert.h>
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f 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
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$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.
+ # 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 >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <assert.h>
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+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
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f 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 >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_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 >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_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 >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#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))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+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=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+ if test x"${TEA_INITED}" = x ; then
+ # Can't refer to exact macro name or it will be substituted
+ { { echo "$as_me:$LINENO: error: Must call TEA INIT before CONFIG_CFLAGS" >&5
+echo "$as_me: error: Must call TEA INIT before CONFIG_CFLAGS" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ # Step 0: Enable 64 bit support?
+
+ echo "$as_me:$LINENO: checking if 64bit support is enabled" >&5
+echo $ECHO_N "checking if 64bit support is enabled... $ECHO_C" >&6
+ # Check whether --enable-64bit or --disable-64bit was given.
+if test "${enable_64bit+set}" = set; then
+ enableval="$enable_64bit"
+ do64bit=$enableval
+else
+ do64bit=no
+fi;
+ echo "$as_me:$LINENO: result: $do64bit" >&5
+echo "${ECHO_T}$do64bit" >&6
+
+ # Step 0.b: Enable Solaris 64 bit VIS support?
+
+ echo "$as_me:$LINENO: checking if 64bit Sparc VIS support is requested" >&5
+echo $ECHO_N "checking if 64bit Sparc VIS support is requested... $ECHO_C" >&6
+ # Check whether --enable-64bit-vis or --disable-64bit-vis was given.
+if test "${enable_64bit_vis+set}" = set; then
+ enableval="$enable_64bit_vis"
+ do64bitVIS=$enableval
+else
+ do64bitVIS=no
+fi;
+ echo "$as_me:$LINENO: result: $do64bitVIS" >&5
+echo "${ECHO_T}$do64bitVIS" >&6
+
+ if test "$do64bitVIS" = "yes"; then
+ # Force 64bit on with VIS
+ do64bit=yes
+ fi
+
+ # Step 1: set the variable "system" to hold the name and version number
+ # for the system. This can usually be done via the "uname" command, but
+ # there are a few systems, like Next, where this doesn't work.
+
+ echo "$as_me:$LINENO: checking system version (for dynamic loading)" >&5
+echo $ECHO_N "checking system version (for dynamic loading)... $ECHO_C" >&6
+ if test -f /usr/lib/NextStep/software_version; then
+ system=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version`
+ else
+ system=`uname -s`-`uname -r`
+ if test "$?" -ne 0 ; then
+ echo "$as_me:$LINENO: result: unknown (can't find uname command)" >&5
+echo "${ECHO_T}unknown (can't find uname command)" >&6
+ system=unknown
+ else
+ # Special check for weird MP-RAS system (uname returns weird
+ # results, and the version is kept in special file).
+
+ if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then
+ system=MP-RAS-`awk '{print }' /etc/.relid'`
+ fi
+ if test "`uname -s`" = "AIX" ; then
+ system=AIX-`uname -v`.`uname -r`
+ fi
+ if test "${TEA_PLATFORM}" = "windows" ; then
+ system=windows
+ fi
+ echo "$as_me:$LINENO: result: $system" >&5
+echo "${ECHO_T}$system" >&6
+ fi
+ fi
+
+ # Step 2: check for existence of -ldl library. This is needed because
+ # Linux can use either -ldl or -ldld for dynamic loading.
+
+ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+ have_dl=yes
+else
+ have_dl=no
+fi
+
+
+ # Step 3: set configuration options based on system name and version.
+
+ do64bit_ok=no
+ EXTRA_CFLAGS=""
+ TCL_EXPORT_FILE_SUFFIX=""
+ UNSHARED_LIB_SUFFIX=""
+ TCL_TRIM_DOTS='`echo ${VERSION} | tr -d .`'
+ ECHO_VERSION='`echo ${VERSION}`'
+ TCL_LIB_VERSIONS_OK=ok
+ CFLAGS_DEBUG=-g
+ CFLAGS_OPTIMIZE=-O
+ if test "$GCC" = "yes" ; then
+ CFLAGS_WARNING="-Wall -Wconversion -Wno-implicit-int"
+ else
+ CFLAGS_WARNING=""
+ fi
+ TCL_NEEDS_EXP_FILE=0
+ TCL_BUILD_EXP_FILE=""
+ TCL_EXP_FILE=""
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&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 $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="ar"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ STLIB_LD='${AR} cr'
+ case $system in
+ 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.
+ if test "$do64bit" = "yes" ; then
+ if test "x${MSSDK}x" = "xx" ; then
+ MSSDK="C:/Progra~1/Microsoft SDK"
+ fi
+ # In order to work in the tortured autoconf environment,
+ # we need to ensure that this path has no spaces
+ MSSDK=`cygpath -w -s "$MSSDK" | sed -e 's!\\\!/!g'`
+ if test ! -d "${MSSDK}/bin/win64" ; then
+ { echo "$as_me:$LINENO: WARNING: \"could not find 64-bit SDK to enable 64bit mode\"" >&5
+echo "$as_me: WARNING: \"could not find 64-bit SDK to enable 64bit mode\"" >&2;}
+ do64bit="no"
+ else
+ do64bit_ok="yes"
+ fi
+ fi
+
+ if test "${SHARED_BUILD}" = "0" ; then
+ runtime=-MT
+ else
+ runtime=-MD
+ fi
+
+ if test "$do64bit" = "yes" ; then
+ # All this magic is necessary for the Win64 SDK RC1 - hobbs
+ export CC="${MSSDK}/Bin/Win64/cl.exe \
+ -I${MSSDK}/Include/prerelease -I${MSSDK}/Include/Win64/crt \
+ -I${MSSDK}/Include"
+ export RC="${MSSDK}/bin/rc.exe"
+ export lflags="-MACHINE:IA64 -LIBPATH:${MSSDK}/Lib/IA64 \
+ -LIBPATH:${MSSDK}/Lib/Prerelease/IA64"
+ export STLIB_LD="${MSSDK}/bin/win64/lib.exe -nologo ${lflags}"
+ export LINKBIN="${MSSDK}/bin/win64/link.exe ${lflags}"
+ CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d"
+ CFLAGS_OPTIMIZE="-nologo -O2 -Gs -W2 ${runtime}"
+ else
+ RC="rc"
+ STLIB_LD="lib -nologo"
+ LINKBIN="link -link50compat"
+ CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d"
+ CFLAGS_OPTIMIZE="-nologo -O2 -Gs -GD -W2 ${runtime}"
+ fi
+
+ if test "$MINGW32" = "yes"; then
+ # mingw gcc mode
+ CFLAGS_DEBUG="-g"
+ CFLAGS_OPTIMIZE="-O2"
+ SHLIB_LD="gcc -shared"
+ STLIB_LD='${AR} cr'
+ UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
+ LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}"
+ LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}"
+ else
+ SHLIB_LD="${LINKBIN} -dll -nologo"
+ UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.lib'
+ EXTRA_CFLAGS="-YX"
+ # For information on what debugtype is most useful, see:
+ # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp
+ # This essentially turns it all on.
+ LDFLAGS_DEBUG="-debug:full -debugtype:both -warn:2"
+ LDFLAGS_OPTIMIZE="-release"
+ LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}"
+ LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}"
+ PATHTYPE=-w
+ fi
+
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".dll"
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.dll'
+
+ TCL_LIB_VERSIONS_OK=nodots
+ # Bogus to avoid getting this turned off
+ DL_OBJS="tclLoadNone.obj"
+ ;;
+ AIX-*)
+ if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then
+ # AIX requires the _r compiler when gcc isn't being used
+ if test "${CC}" != "cc_r" ; then
+ CC=${CC}_r
+ fi
+ echo "$as_me:$LINENO: result: Using $CC for compiling with threads" >&5
+echo "${ECHO_T}Using $CC for compiling with threads" >&6
+ fi
+ LIBS="$LIBS -lc"
+ SHLIB_CFLAGS=""
+ SHLIB_SUFFIX=".so"
+ SHLIB_LD_LIBS='${LIBS}'
+ 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"
+ # AIX-5 has dl* in libc.so
+ DL_LIBS=""
+ if test "$GCC" = "yes" ; then
+ LD_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ else
+ LD_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}'
+ fi
+ else
+ SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry"
+ DL_LIBS="-ldl"
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ TCL_NEEDS_EXP_FILE=1
+ TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp'
+ fi
+ DL_OBJS="tclLoadDl.o"
+ LDFLAGS=""
+
+ # AIX v<=4.1 has some different flags than 4.2+
+ if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then
+ LIBOBJS="$LIBOBJS tclLoadAix.o"
+ DL_LIBS="-lld"
+ fi
+
+ # On AIX <=v4 systems, libbsd.a has to be linked in to support
+ # non-blocking file IO. This library has to be linked in after
+ # the MATH_LIBS or it breaks the pow() function. The way to
+ # insure proper sequencing, is to add it to the tail of MATH_LIBS.
+ # This library also supplies gettimeofday.
+ #
+ # AIX does not have a timezone field in struct tm. When the AIX
+ # bsd library is used, the timezone global and the gettimeofday
+ # methods are to be avoided for timezone deduction instead, we
+ # deduce the timezone by comparing the localtime result on a
+ # known GMT value.
+
+ echo "$as_me:$LINENO: checking for gettimeofday in -lbsd" >&5
+echo $ECHO_N "checking for gettimeofday in -lbsd... $ECHO_C" >&6
+if test "${ac_cv_lib_bsd_gettimeofday+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gettimeofday ();
+int
+main ()
+{
+gettimeofday ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_bsd_gettimeofday=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_bsd_gettimeofday=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_gettimeofday" >&5
+echo "${ECHO_T}$ac_cv_lib_bsd_gettimeofday" >&6
+if test $ac_cv_lib_bsd_gettimeofday = yes; then
+ libbsd=yes
+else
+ libbsd=no
+fi
+
+ if test $libbsd = yes; then
+ MATH_LIBS="$MATH_LIBS -lbsd"
+ cat >>confdefs.h <<\_ACEOF
+#define USE_DELTA_FOR_TZ 1
+_ACEOF
+
+ fi
+
+ # Check to enable 64-bit flags for compiler/linker on AIX 4+
+ if test "$do64bit" = "yes" -a "`uname -v`" -gt "3" ; then
+ if test "$GCC" = "yes" ; then
+ { echo "$as_me:$LINENO: WARNING: \"64bit mode not supported with GCC on $system\"" >&5
+echo "$as_me: WARNING: \"64bit mode not supported with GCC on $system\"" >&2;}
+ else
+ do64bit_ok=yes
+ EXTRA_CFLAGS="-q64"
+ LDFLAGS="-q64"
+ RANLIB="${RANLIB} -X64"
+ AR="${AR} -X64"
+ SHLIB_LDFLAGS="-b64"
+ fi
+ fi
+ ;;
+ BSD/OS-2.1*|BSD/OS-3*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="shlicc -r"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ BSD/OS-4.*)
+ SHLIB_CFLAGS="-export-dynamic -fPIC"
+ SHLIB_LD="cc -shared"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS="-export-dynamic"
+ LD_SEARCH_FLAGS=""
+ ;;
+ dgux*)
+ SHLIB_CFLAGS="-K PIC"
+ SHLIB_LD="cc -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ HP-UX-*.11.*)
+ # Use updated header definitions where possible
+ cat >>confdefs.h <<\_ACEOF
+#define _XOPEN_SOURCE_EXTENDED 1
+_ACEOF
+
+
+ SHLIB_SUFFIX=".sl"
+ echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+ tcl_ok=yes
+else
+ tcl_ok=no
+fi
+
+ if test "$tcl_ok" = yes; then
+ SHLIB_CFLAGS="+z"
+ SHLIB_LD="ld -b"
+ SHLIB_LD_LIBS='${LIBS}'
+ DL_OBJS="tclLoadShl.o"
+ DL_LIBS="-ldld"
+ LDFLAGS="-Wl,-E"
+ LD_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.'
+ fi
+
+ # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc
+ #EXTRA_CFLAGS="+DAportable"
+
+ # Check to enable 64-bit flags for compiler/linker
+ if test "$do64bit" = "yes" ; then
+ if test "$GCC" = "yes" ; then
+ hpux_arch=`gcc -dumpmachine`
+ case $hpux_arch in
+ hppa64*)
+ # 64-bit gcc in use. Fix flags for GNU ld.
+ do64bit_ok=yes
+ SHLIB_LD="gcc -shared"
+ SHLIB_LD_LIBS=""
+ LD_SEARCH_FLAGS=''
+ ;;
+ *)
+ { echo "$as_me:$LINENO: WARNING: \"64bit mode not supported with GCC on $system\"" >&5
+echo "$as_me: WARNING: \"64bit mode not supported with GCC on $system\"" >&2;}
+ ;;
+ esac
+ else
+ do64bit_ok=yes
+ EXTRA_CFLAGS="+DA2.0W"
+ LDFLAGS="+DA2.0W $LDFLAGS"
+ fi
+ fi
+ ;;
+ HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*)
+ SHLIB_SUFFIX=".sl"
+ echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char shl_load ();
+int
+main ()
+{
+shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dld_shl_load=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dld_shl_load=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6
+if test $ac_cv_lib_dld_shl_load = yes; then
+ tcl_ok=yes
+else
+ tcl_ok=no
+fi
+
+ if test "$tcl_ok" = yes; then
+ SHLIB_CFLAGS="+z"
+ SHLIB_LD="ld -b"
+ SHLIB_LD_LIBS=""
+ DL_OBJS="tclLoadShl.o"
+ DL_LIBS="-ldld"
+ LDFLAGS="-Wl,-E"
+ LD_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.'
+ fi
+ ;;
+ IRIX-4.*)
+ SHLIB_CFLAGS="-G 0"
+ SHLIB_SUFFIX=".a"
+ SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0"
+ SHLIB_LD_LIBS='${LIBS}'
+ DL_OBJS="tclLoadAout.o"
+ DL_LIBS=""
+ LDFLAGS="-Wl,-D,08000000"
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ SHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}.a'
+ ;;
+ IRIX-5.*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="ld -shared -rdata_shared"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ EXTRA_CFLAGS=""
+ LDFLAGS=""
+ ;;
+ IRIX-6.*|IRIX64-6.5*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="ld -n32 -shared -rdata_shared"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ if test "$GCC" = "yes" ; then
+ EXTRA_CFLAGS="-mabi=n32"
+ LDFLAGS="-mabi=n32"
+ else
+ case $system in
+ IRIX-6.3)
+ # Use to build 6.2 compatible binaries on 6.3.
+ EXTRA_CFLAGS="-n32 -D_OLD_TERMIOS"
+ ;;
+ *)
+ EXTRA_CFLAGS="-n32"
+ ;;
+ esac
+ LDFLAGS="-n32"
+ fi
+ ;;
+ IRIX64-6.*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="ld -n32 -shared -rdata_shared"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+
+ # Check to enable 64-bit flags for compiler/linker
+
+ if test "$do64bit" = "yes" ; then
+ if test "$GCC" = "yes" ; then
+ { echo "$as_me:$LINENO: WARNING: 64bit mode not supported by gcc" >&5
+echo "$as_me: WARNING: 64bit mode not supported by gcc" >&2;}
+ else
+ do64bit_ok=yes
+ SHLIB_LD="ld -64 -shared -rdata_shared"
+ EXTRA_CFLAGS="-64"
+ LDFLAGS="-64"
+ fi
+ fi
+ ;;
+ Linux*)
+ SHLIB_CFLAGS="-fPIC"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+
+ # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings
+ # when you inline the string and math operations. Turn this off to
+ # get rid of the warnings.
+
+ CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES"
+
+ if test "$have_dl" = yes; then
+ SHLIB_LD="${CC} -shared"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS="-rdynamic"
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ else
+ if test "${ac_cv_header_dld_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for dld.h" >&5
+echo $ECHO_N "checking for dld.h... $ECHO_C" >&6
+if test "${ac_cv_header_dld_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_dld_h" >&5
+echo "${ECHO_T}$ac_cv_header_dld_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking dld.h usability" >&5
+echo $ECHO_N "checking dld.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <dld.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking dld.h presence" >&5
+echo $ECHO_N "checking dld.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <dld.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: dld.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: dld.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dld.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: dld.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: dld.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: dld.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dld.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: dld.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dld.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: dld.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for dld.h" >&5
+echo $ECHO_N "checking for dld.h... $ECHO_C" >&6
+if test "${ac_cv_header_dld_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_dld_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_dld_h" >&5
+echo "${ECHO_T}$ac_cv_header_dld_h" >&6
+
+fi
+if test $ac_cv_header_dld_h = yes; then
+
+ SHLIB_LD="ld -shared"
+ DL_OBJS="tclLoadDld.o"
+ DL_LIBS="-ldld"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+fi
+
+
+ fi
+ if test "`uname -m`" = "alpha" ; then
+ EXTRA_CFLAGS="-mieee"
+ 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"${LIBOBJS}" != x ; then
+ EXTRA_CFLAGS="${EXTRA_CFLAGS} -fno-inline"
+ fi
+
+ ;;
+ GNU*)
+ SHLIB_CFLAGS="-fPIC"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+
+ if test "$have_dl" = yes; then
+ SHLIB_LD="${CC} -shared"
+ DL_OBJS=""
+ DL_LIBS="-ldl"
+ LDFLAGS="-rdynamic"
+ LD_SEARCH_FLAGS=""
+ else
+ if test "${ac_cv_header_dld_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for dld.h" >&5
+echo $ECHO_N "checking for dld.h... $ECHO_C" >&6
+if test "${ac_cv_header_dld_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_dld_h" >&5
+echo "${ECHO_T}$ac_cv_header_dld_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking dld.h usability" >&5
+echo $ECHO_N "checking dld.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <dld.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking dld.h presence" >&5
+echo $ECHO_N "checking dld.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <dld.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: dld.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: dld.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dld.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: dld.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: dld.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: dld.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dld.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: dld.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dld.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: dld.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for dld.h" >&5
+echo $ECHO_N "checking for dld.h... $ECHO_C" >&6
+if test "${ac_cv_header_dld_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_dld_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_dld_h" >&5
+echo "${ECHO_T}$ac_cv_header_dld_h" >&6
+
+fi
+if test $ac_cv_header_dld_h = yes; then
+
+ SHLIB_LD="ld -shared"
+ DL_OBJS=""
+ DL_LIBS="-ldld"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+fi
+
+
+ fi
+ if test "`uname -m`" = "alpha" ; then
+ EXTRA_CFLAGS="-mieee"
+ fi
+ ;;
+ MP-RAS-02*)
+ SHLIB_CFLAGS="-K PIC"
+ SHLIB_LD="cc -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ MP-RAS-*)
+ SHLIB_CFLAGS="-K PIC"
+ SHLIB_LD="cc -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS="-Wl,-Bexport"
+ LD_SEARCH_FLAGS=""
+ ;;
+ NetBSD-*|FreeBSD-[1-2].*|OpenBSD-*)
+ # Not available on all versions: check for include file.
+ if test "${ac_cv_header_dlfcn_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for dlfcn.h" >&5
+echo $ECHO_N "checking for dlfcn.h... $ECHO_C" >&6
+if test "${ac_cv_header_dlfcn_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_dlfcn_h" >&5
+echo "${ECHO_T}$ac_cv_header_dlfcn_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking dlfcn.h usability" >&5
+echo $ECHO_N "checking dlfcn.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <dlfcn.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking dlfcn.h presence" >&5
+echo $ECHO_N "checking dlfcn.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <dlfcn.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: dlfcn.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: dlfcn.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: dlfcn.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: dlfcn.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dlfcn.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: dlfcn.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for dlfcn.h" >&5
+echo $ECHO_N "checking for dlfcn.h... $ECHO_C" >&6
+if test "${ac_cv_header_dlfcn_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_dlfcn_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_dlfcn_h" >&5
+echo "${ECHO_T}$ac_cv_header_dlfcn_h" >&6
+
+fi
+if test $ac_cv_header_dlfcn_h = yes; then
+
+ # NetBSD/SPARC needs -fPIC, -fpic will not do.
+ SHLIB_CFLAGS="-fPIC"
+ SHLIB_LD="ld -Bshareable -x"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ echo "$as_me:$LINENO: checking for ELF" >&5
+echo $ECHO_N "checking for ELF... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#ifdef __ELF__
+ yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "yes" >/dev/null 2>&1; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so'
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0'
+
+fi
+rm -f conftest*
+
+
+else
+
+ SHLIB_CFLAGS=""
+ SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".a"
+ DL_OBJS="tclLoadAout.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
+
+fi
+
+
+
+ # FreeBSD doesn't handle version numbers with dots.
+
+ UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
+ TCL_LIB_VERSIONS_OK=nodots
+ ;;
+ FreeBSD-*)
+ # FreeBSD 3.* and greater have ELF.
+ SHLIB_CFLAGS="-fPIC"
+ SHLIB_LD="ld -Bshareable -x"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LDFLAGS="-export-dynamic"
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ if test "${TCL_THREADS}" = "1" ; then
+ # The -pthread needs to go in the CFLAGS, not LIBS
+ LIBS=`echo $LIBS | sed s/-pthread//`
+ EXTRA_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}\$\{DBGX\}.a'
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so'
+ TCL_LIB_VERSIONS_OK=nodots
+ ;;
+ esac
+ ;;
+ Rhapsody-*|Darwin-*)
+ SHLIB_CFLAGS="-fno-common"
+ SHLIB_LD="cc -dynamiclib \${LDFLAGS}"
+ TCL_SHLIB_LD_EXTRAS="-compatibility_version ${TCL_MAJOR_VERSION} -current_version \${VERSION} -install_name \${LIB_RUNTIME_DIR}/\${TCL_LIB_FILE} -prebind -seg1addr 0xa000000"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".dylib"
+ DL_OBJS="tclLoadDyld.o"
+ DL_LIBS=""
+ LDFLAGS="-prebind"
+ LD_SEARCH_FLAGS=""
+ CFLAGS_OPTIMIZE="-O3"
+ EXTRA_CFLAGS="-arch ppc -pipe"
+ ;;
+ NEXTSTEP-*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="cc -nostdlib -r"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadNext.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ OS/390-*)
+ CFLAGS_OPTIMIZE="" # Optimizer is buggy
+ cat >>confdefs.h <<\_ACEOF
+#define _OE_SOCKETS 1
+_ACEOF
+ # needed in sys/socket.h
+ ;;
+ OSF1-1.0|OSF1-1.1|OSF1-1.2)
+ # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1
+ SHLIB_CFLAGS=""
+ # Hack: make package name same as library name
+ SHLIB_LD='ld -R -export :'
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadOSF.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ OSF1-1.*)
+ # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2
+ SHLIB_CFLAGS="-fPIC"
+ if test "$SHARED_BUILD" = "1" ; then
+ SHLIB_LD="ld -shared"
+ else
+ SHLIB_LD="ld -non_shared"
+ fi
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ 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_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
+ if test "$GCC" != "yes" ; then
+ EXTRA_CFLAGS="-DHAVE_TZSET -std1"
+ fi
+ # see pthread_intro(3) for pthread support on osf1, k.furukawa
+ if test "${TCL_THREADS}" = "1" ; then
+ EXTRA_CFLAGS="${EXTRA_CFLAGS} -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
+ EXTRA_CFLAGS="${EXTRA_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
+ EXTRA_CFLAGS="${EXTRA_CFLAGS} -pthread"
+ 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"
+ DL_OBJS="tclLoadDl.o"
+ # dlopen is in -lc on QNX
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ RISCos-*)
+ SHLIB_CFLAGS="-G 0"
+ SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".a"
+ DL_OBJS="tclLoadAout.o"
+ DL_LIBS=""
+ LDFLAGS="-Wl,-D,08000000"
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ ;;
+ SCO_SV-3.2*)
+ # Note, dlopen is available only on SCO 3.2.5 and greater. However,
+ # this test works, since "uname -s" was non-standard in 3.2.4 and
+ # below.
+ if test "$GCC" = "yes" ; then
+ SHLIB_CFLAGS="-fPIC -melf"
+ LDFLAGS="-melf -Wl,-Bexport"
+ else
+ SHLIB_CFLAGS="-Kpic -belf"
+ LDFLAGS="-belf -Wl,-Bexport"
+ fi
+ SHLIB_LD="ld -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ SINIX*5.4*)
+ SHLIB_CFLAGS="-K PIC"
+ SHLIB_LD="cc -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ SunOS-4*)
+ SHLIB_CFLAGS="-PIC"
+ SHLIB_LD="ld"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+
+ # SunOS can't handle version numbers with dots in them in library
+ # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it
+ # requires an extra version number at the end of .so file names.
+ # So, the library has to have a name like libtcl75.so.1.0
+
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0'
+ UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
+ TCL_LIB_VERSIONS_OK=nodots
+ ;;
+ SunOS-5.[0-6]*)
+
+ # Note: If _REENTRANT isn't defined, then Solaris
+ # won't define thread-safe library routines.
+
+ cat >>confdefs.h <<\_ACEOF
+#define _REENTRANT 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define _POSIX_PTHREAD_SEMANTICS 1
+_ACEOF
+
+
+ SHLIB_CFLAGS="-KPIC"
+
+ # Note: need the LIBS below, otherwise Tk won't find Tcl's
+ # symbols when dynamically loaded into tclsh.
+
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ if test "$GCC" = "yes" ; then
+ SHLIB_LD="$CC -shared"
+ LD_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ else
+ SHLIB_LD="/usr/ccs/bin/ld -G -z text"
+ LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
+ fi
+ ;;
+ SunOS-5*)
+
+ # Note: If _REENTRANT isn't defined, then Solaris
+ # won't define thread-safe library routines.
+
+ cat >>confdefs.h <<\_ACEOF
+#define _REENTRANT 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define _POSIX_PTHREAD_SEMANTICS 1
+_ACEOF
+
+
+ SHLIB_CFLAGS="-KPIC"
+ LDFLAGS=""
+
+ # 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
+ { echo "$as_me:$LINENO: WARNING: \"64bit mode not supported with GCC on $system\"" >&5
+echo "$as_me: WARNING: \"64bit mode not supported with GCC on $system\"" >&2;}
+ else
+ do64bit_ok=yes
+ if test "$do64bitVIS" = "yes" ; then
+ EXTRA_CFLAGS="-xarch=v9a"
+ LDFLAGS="-xarch=v9a"
+ else
+ EXTRA_CFLAGS="-xarch=v9"
+ LDFLAGS="-xarch=v9"
+ fi
+ fi
+ else
+ { echo "$as_me:$LINENO: WARNING: \"64bit mode only supported sparcv9 system\"" >&5
+echo "$as_me: WARNING: \"64bit mode only supported sparcv9 system\"" >&2;}
+ fi
+ fi
+
+ # Note: need the LIBS below, otherwise Tk won't find Tcl's
+ # symbols when dynamically loaded into tclsh.
+
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ if test "$GCC" = "yes" ; then
+ SHLIB_LD="$CC -shared"
+ LD_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ else
+ SHLIB_LD="/usr/ccs/bin/ld -G -z text"
+ LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
+ fi
+ ;;
+ ULTRIX-4.*)
+ SHLIB_CFLAGS="-G 0"
+ SHLIB_SUFFIX=".a"
+ SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0"
+ SHLIB_LD_LIBS='${LIBS}'
+ DL_OBJS="tclLoadAout.o"
+ DL_LIBS=""
+ LDFLAGS="-Wl,-D,08000000"
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ if test "$GCC" != "yes" ; then
+ EXTRA_CFLAGS="-DHAVE_TZSET -std1"
+ fi
+ ;;
+ UNIX_SV* | UnixWare-5*)
+ SHLIB_CFLAGS="-KPIC"
+ SHLIB_LD="cc -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers
+ # that don't grok the -Bexport option. Test that it does.
+ hold_ldflags=$LDFLAGS
+ echo "$as_me:$LINENO: checking for ld accepts -Bexport flag" >&5
+echo $ECHO_N "checking for ld accepts -Bexport flag... $ECHO_C" >&6
+ LDFLAGS="${LDFLAGS} -Wl,-Bexport"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ found=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+found=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$hold_ldflags
+ echo "$as_me:$LINENO: result: $found" >&5
+echo "${ECHO_T}$found" >&6
+ if test $found = yes; then
+ LDFLAGS="-Wl,-Bexport"
+ else
+ LDFLAGS=""
+ fi
+ LD_SEARCH_FLAGS=""
+ ;;
+ esac
+
+ if test "$do64bit" = "yes" -a "$do64bit_ok" = "no" ; then
+ { echo "$as_me:$LINENO: WARNING: \"64bit support being disabled -- don\'t know magic for this platform\"" >&5
+echo "$as_me: WARNING: \"64bit support being disabled -- don\'t know magic for this platform\"" >&2;}
+ fi
+
+ # Step 4: If pseudo-static linking is in use (see K. B. Kenny, "Dynamic
+ # Loading for Tcl -- What Became of It?". Proc. 2nd Tcl/Tk Workshop,
+ # New Orleans, LA, Computerized Processes Unlimited, 1994), then we need
+ # to determine which of several header files defines the a.out file
+ # format (a.out.h, sys/exec.h, or sys/exec_aout.h). At present, we
+ # support only a file format that is more or less version-7-compatible.
+ # In particular,
+ # - a.out files must begin with `struct exec'.
+ # - the N_TXTOFF on the `struct exec' must compute the seek address
+ # of the text segment
+ # - The `struct exec' must contain a_magic, a_text, a_data, a_bss
+ # and a_entry fields.
+ # The following compilation should succeed if and only if either sys/exec.h
+ # or a.out.h is usable for the purpose.
+ #
+ # Note that the modified COFF format used on MIPS Ultrix 4.x is usable; the
+ # `struct exec' includes a second header that contains information that
+ # duplicates the v7 fields that are needed.
+
+ if test "x$DL_OBJS" = "xtclLoadAout.o" ; then
+ echo "$as_me:$LINENO: checking sys/exec.h" >&5
+echo $ECHO_N "checking sys/exec.h... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/exec.h>
+int
+main ()
+{
+
+ struct exec foo;
+ unsigned long seek;
+ int flag;
+#if defined(__mips) || defined(mips)
+ seek = N_TXTOFF (foo.ex_f, foo.ex_o);
+#else
+ seek = N_TXTOFF (foo);
+#endif
+ flag = (foo.a_magic == OMAGIC);
+ return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tcl_ok=usable
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_ok=unusable
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ echo "$as_me:$LINENO: result: $tcl_ok" >&5
+echo "${ECHO_T}$tcl_ok" >&6
+ if test $tcl_ok = usable; then
+ cat >>confdefs.h <<\_ACEOF
+#define USE_SYS_EXEC_H 1
+_ACEOF
+
+ else
+ echo "$as_me:$LINENO: checking a.out.h" >&5
+echo $ECHO_N "checking a.out.h... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <a.out.h>
+int
+main ()
+{
+
+ struct exec foo;
+ unsigned long seek;
+ int flag;
+#if defined(__mips) || defined(mips)
+ seek = N_TXTOFF (foo.ex_f, foo.ex_o);
+#else
+ seek = N_TXTOFF (foo);
+#endif
+ flag = (foo.a_magic == OMAGIC);
+ return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tcl_ok=usable
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_ok=unusable
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ echo "$as_me:$LINENO: result: $tcl_ok" >&5
+echo "${ECHO_T}$tcl_ok" >&6
+ if test $tcl_ok = usable; then
+ cat >>confdefs.h <<\_ACEOF
+#define USE_A_OUT_H 1
+_ACEOF
+
+ else
+ echo "$as_me:$LINENO: checking sys/exec_aout.h" >&5
+echo $ECHO_N "checking sys/exec_aout.h... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/exec_aout.h>
+int
+main ()
+{
+
+ struct exec foo;
+ unsigned long seek;
+ int flag;
+#if defined(__mips) || defined(mips)
+ seek = N_TXTOFF (foo.ex_f, foo.ex_o);
+#else
+ seek = N_TXTOFF (foo);
+#endif
+ flag = (foo.a_midmag == OMAGIC);
+ return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry;
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tcl_ok=usable
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_ok=unusable
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ echo "$as_me:$LINENO: result: $tcl_ok" >&5
+echo "${ECHO_T}$tcl_ok" >&6
+ if test $tcl_ok = usable; then
+ cat >>confdefs.h <<\_ACEOF
+#define USE_SYS_EXEC_AOUT_H 1
+_ACEOF
+
+ else
+ DL_OBJS=""
+ fi
+ fi
+ fi
+ fi
+
+ # Step 5: disable dynamic loading if requested via a command-line switch.
+
+ # Check whether --enable-load or --disable-load was given.
+if test "${enable_load+set}" = set; then
+ enableval="$enable_load"
+ tcl_ok=$enableval
+else
+ tcl_ok=yes
+fi;
+ if test "$tcl_ok" = "no"; then
+ DL_OBJS=""
+ fi
+
+ if test "x$DL_OBJS" != "x" ; then
+ BUILD_DLTEST="\$(DLTEST_TARGETS)"
+ else
+ echo "Can't figure out how to do dynamic loading or shared libraries"
+ echo "on this system."
+ SHLIB_CFLAGS=""
+ SHLIB_LD=""
+ SHLIB_SUFFIX=""
+ DL_OBJS="tclLoadNone.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ BUILD_DLTEST=""
+ fi
+
+ # 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 "$DL_OBJS" != "tclLoadNone.o" ; then
+ if test "$GCC" = "yes" ; then
+ case $system in
+ AIX-*)
+ ;;
+ BSD/OS*)
+ ;;
+ IRIX*)
+ ;;
+ NetBSD-*|FreeBSD-*|OpenBSD-*)
+ ;;
+ Rhapsody-*|Darwin-*)
+ ;;
+ RISCos-*)
+ ;;
+ SCO_SV-3.2*)
+ ;;
+ ULTRIX-4.*)
+ ;;
+ windows)
+ if test "$MINGW32" != "yes"; then
+ SHLIB_CFLAGS="-fPIC"
+ fi
+ ;;
+ *)
+ SHLIB_CFLAGS="-fPIC"
+ ;;
+ esac
+ fi
+ fi
+
+ if test "$SHARED_LIB_SUFFIX" = "" ; then
+ SHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}${SHLIB_SUFFIX}'
+ fi
+ if test "$UNSHARED_LIB_SUFFIX" = "" ; then
+ UNSHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}.a'
+ fi
+
+
+
+
+
+
+
+ SHLIB_LDFLAGS='$(LDFLAGS_DEFAULT)'
+
+
+
+
+
+
+
+
+
+#--------------------------------------------------------------------
+# Set the default compiler switches based on the --enable-symbols option.
+#--------------------------------------------------------------------
+
+
+ if test x"${TEA_INITED}" = x ; then
+ # Can't refer to exact macro name or it will be substituted
+ { { echo "$as_me:$LINENO: error: Must call TEA INIT before ENABLE_SYMBOLS" >&5
+echo "$as_me: error: Must call TEA INIT before ENABLE_SYMBOLS" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+ if test "${TEA_PLATFORM}" = "windows" ; then
+ tcl_dbgx=d
+ else
+ tcl_dbgx=g
+ fi
+
+ echo "$as_me:$LINENO: checking for build with symbols" >&5
+echo $ECHO_N "checking for build with symbols... $ECHO_C" >&6
+ # Check whether --enable-symbols or --disable-symbols was given.
+if test "${enable_symbols+set}" = set; then
+ enableval="$enable_symbols"
+ tcl_ok=$enableval
+else
+ tcl_ok=no
+fi;
+ if test "$tcl_ok" = "no"; then
+ CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)'
+ LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)'
+ DBGX=""
+ TCL_DBGX=""
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ else
+ CFLAGS_DEFAULT='$(CFLAGS_DEBUG)'
+ LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)'
+ DBGX=${tcl_dbgx}
+ TCL_DBGX=${tcl_dbgx}
+ if test "$tcl_ok" = "yes"; then
+ echo "$as_me:$LINENO: result: yes (standard debugging)" >&5
+echo "${ECHO_T}yes (standard debugging)" >&6
+ fi
+ fi
+
+
+
+
+
+ if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then
+ cat >>confdefs.h <<\_ACEOF
+#define TCL_MEM_DEBUG 1
+_ACEOF
+
+ fi
+
+ if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then
+ if test "$tcl_ok" = "all"; then
+ echo "$as_me:$LINENO: result: enabled symbols mem debugging" >&5
+echo "${ECHO_T}enabled symbols mem debugging" >&6
+ else
+ echo "$as_me:$LINENO: result: enabled $tcl_ok debugging" >&5
+echo "${ECHO_T}enabled $tcl_ok debugging" >&6
+ fi
+ 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.
+#--------------------------------------------------------------------
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_TCL_STUBS 1
+_ACEOF
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_TK_STUBS 1
+_ACEOF
+
+
+#--------------------------------------------------------------------
+# 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:\$@ \$(\$(PACKAGE)_OBJECTS)"
+ MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LDFLAGS} \${SHLIB_LD_LIBS} \$(LDFLAGS) -out:\$@ \$(\$(PACKAGE)_OBJECTS)"
+ MAKE_STUB_LIB="\${STLIB_LD} -out:\$@ \$(\$(PACKAGE)stub_OBJECTS)"
+ else
+ MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(\$(PACKAGE)_OBJECTS)"
+ MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(\$(PACKAGE)_OBJECTS) \${SHLIB_LDFLAGS} \${SHLIB_LD_LIBS}"
+ MAKE_STUB_LIB="\${STLIB_LD} \$@ \$(\$(PACKAGE)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 the ${DBGX} in the suffix is
+ # substituted.
+ #--------------------------------------------------------------------
+
+ 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 "${PACKAGE}_LIB_FILE=${PACKAGE}${SHARED_LIB_SUFFIX}"
+ RANLIB=:
+ else
+ eval eval "${PACKAGE}_LIB_FILE=${PACKAGE}${UNSHARED_LIB_SUFFIX}"
+ fi
+ # Some packages build there own stubs libraries
+ eval eval "${PACKAGE}stub_LIB_FILE=${PACKAGE}stub${UNSHARED_LIB_SUFFIX}"
+ else
+ 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 "${PACKAGE}_LIB_FILE=lib${PACKAGE}${SHARED_LIB_SUFFIX}"
+ RANLIB=:
+ else
+ eval eval "${PACKAGE}_LIB_FILE=lib${PACKAGE}${UNSHARED_LIB_SUFFIX}"
+ fi
+ # Some packages build there own stubs libraries
+ eval eval "${PACKAGE}stub_LIB_FILE=lib${PACKAGE}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
+
+
+
+
+
+
+
+#--------------------------------------------------------------------
+# __CHANGE__
+# Add platform libs to LIBS or SHLIB_LD_LIBS as necessary.
+#--------------------------------------------------------------------
+
+#LIBS="${LIBS} -lsuperfly"
+LIBS="${LIBS} ${TK_LIBS}"
+
+#--------------------------------------------------------------------
+# 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.
+#--------------------------------------------------------------------
+
+
+ echo "$as_me:$LINENO: checking for tclsh" >&5
+echo $ECHO_N "checking for tclsh... $ECHO_C" >&6
+
+ if test "${ac_cv_path_tclsh+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ search_path=`echo ${TCL_BIN_DIR}:${TCL_BIN_DIR}/../bin:${exec_prefix}/bin:${prefix}/bin:${PATH} | sed -e 's/:/ /g'`
+ for dir in $search_path ; do
+ for j in `ls -r $dir/tclsh[8-9]*${EXEEXT} 2> /dev/null` \
+ `ls -r $dir/tclsh*${EXEEXT} 2> /dev/null` ; do
+ if test x"$ac_cv_path_tclsh" = x ; then
+ if test -f "$j" ; then
+ ac_cv_path_tclsh=$j
+ break
+ fi
+ fi
+ done
+ done
+
+fi
+
+
+ if test -f "$ac_cv_path_tclsh" ; then
+ TCLSH_PROG=$ac_cv_path_tclsh
+ echo "$as_me:$LINENO: result: $TCLSH_PROG" >&5
+echo "${ECHO_T}$TCLSH_PROG" >&6
+ else
+ { { echo "$as_me:$LINENO: error: No tclsh found in PATH: $search_path" >&5
+echo "$as_me: error: No tclsh found in PATH: $search_path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+
+
+ echo "$as_me:$LINENO: checking for wish" >&5
+echo $ECHO_N "checking for wish... $ECHO_C" >&6
+
+ if test "${ac_cv_path_wish+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ search_path=`echo ${TK_BIN_DIR}:${TK_BIN_DIR}/../bin:${TCL_BIN_DIR}:${TCL_BIN_DIR}/../bin:${exec_prefix}/bin:${prefix}/bin:${PATH} | sed -e 's/:/ /g'`
+ for dir in $search_path ; do
+ for j in `ls -r $dir/wish[8-9]*${EXEEXT} 2> /dev/null` \
+ `ls -r $dir/wish*${EXEEXT} 2> /dev/null` ; do
+ if test x"$ac_cv_path_wish" = x ; then
+ if test -f "$j" ; then
+ ac_cv_path_wish=$j
+ break
+ fi
+ fi
+ done
+ done
+
+fi
+
+
+ if test -f "$ac_cv_path_wish" ; then
+ WISH_PROG=$ac_cv_path_wish
+ echo "$as_me:$LINENO: result: $WISH_PROG" >&5
+echo "${ECHO_T}$WISH_PROG" >&6
+ else
+ { { echo "$as_me:$LINENO: error: No wish found in PATH: $search_path" >&5
+echo "$as_me: error: No wish found in PATH: $search_path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+
+
+
+#--------------------------------------------------------------------
+# 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 Makefile pkgIndex.tcl"
+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, don't put newlines in cache variables' values.
+# 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.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *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 \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!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" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ 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}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ 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[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+# 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 we branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+cat >confdef2opt.sed <<\_ACEOF
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g
+t quote
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g
+t quote
+d
+: quote
+s,[ `~#$^&*(){}\\|;'"<>?],\\&,g
+s,\[,\\&,g
+s,\],\\&,g
+s,\$,$$,g
+p
+_ACEOF
+# We use echo to avoid assuming a particular line-breaking character.
+# The extra dot is to prevent the shell from consuming trailing
+# line-breaks from the sub-command output. A line-break within
+# single-quotes doesn't work because, if this script is created in a
+# platform that uses two characters for line-breaks (e.g., DOS), tr
+# would break.
+ac_LF_and_DOT=`echo; echo .`
+DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
+rm -f confdef2opt.sed
+
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $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}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; 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
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# 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
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ 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
+
+ ;;
+ 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
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); 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 sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="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="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.56. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet 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 <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.56,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+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=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ 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
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "pkgIndex.tcl" ) CONFIG_FILES="$CONFIG_FILES pkgIndex.tcl" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ 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 to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@CONFIGDIR@,$CONFIGDIR,;t t
+s,@PACKAGE@,$PACKAGE,;t t
+s,@VERSION@,$VERSION,;t t
+s,@treectrl_LIB_FILE@,$treectrl_LIB_FILE,;t t
+s,@CYGPATH@,$CYGPATH,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@TCL_VERSION@,$TCL_VERSION,;t t
+s,@TCL_BIN_DIR@,$TCL_BIN_DIR,;t t
+s,@TCL_SRC_DIR@,$TCL_SRC_DIR,;t t
+s,@TCL_LIB_FILE@,$TCL_LIB_FILE,;t t
+s,@TCL_LIB_FLAG@,$TCL_LIB_FLAG,;t t
+s,@TCL_LIB_SPEC@,$TCL_LIB_SPEC,;t t
+s,@TCL_STUB_LIB_FILE@,$TCL_STUB_LIB_FILE,;t t
+s,@TCL_STUB_LIB_FLAG@,$TCL_STUB_LIB_FLAG,;t t
+s,@TCL_STUB_LIB_SPEC@,$TCL_STUB_LIB_SPEC,;t t
+s,@TCL_LIBS@,$TCL_LIBS,;t t
+s,@TCL_DEFS@,$TCL_DEFS,;t t
+s,@TCL_EXTRA_CFLAGS@,$TCL_EXTRA_CFLAGS,;t t
+s,@TCL_LD_FLAGS@,$TCL_LD_FLAGS,;t t
+s,@TCL_SHLIB_LD_LIBS@,$TCL_SHLIB_LD_LIBS,;t t
+s,@TK_VERSION@,$TK_VERSION,;t t
+s,@TK_BIN_DIR@,$TK_BIN_DIR,;t t
+s,@TK_SRC_DIR@,$TK_SRC_DIR,;t t
+s,@TK_LIB_FILE@,$TK_LIB_FILE,;t t
+s,@TK_LIB_FLAG@,$TK_LIB_FLAG,;t t
+s,@TK_LIB_SPEC@,$TK_LIB_SPEC,;t t
+s,@TK_STUB_LIB_FILE@,$TK_STUB_LIB_FILE,;t t
+s,@TK_STUB_LIB_FLAG@,$TK_STUB_LIB_FLAG,;t t
+s,@TK_STUB_LIB_SPEC@,$TK_STUB_LIB_SPEC,;t t
+s,@TK_LIBS@,$TK_LIBS,;t t
+s,@TK_XINCLUDES@,$TK_XINCLUDES,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@TCL_TOP_DIR_NATIVE@,$TCL_TOP_DIR_NATIVE,;t t
+s,@TCL_GENERIC_DIR_NATIVE@,$TCL_GENERIC_DIR_NATIVE,;t t
+s,@TCL_UNIX_DIR_NATIVE@,$TCL_UNIX_DIR_NATIVE,;t t
+s,@TCL_WIN_DIR_NATIVE@,$TCL_WIN_DIR_NATIVE,;t t
+s,@TCL_BMAP_DIR_NATIVE@,$TCL_BMAP_DIR_NATIVE,;t t
+s,@TCL_TOOL_DIR_NATIVE@,$TCL_TOOL_DIR_NATIVE,;t t
+s,@TCL_PLATFORM_DIR_NATIVE@,$TCL_PLATFORM_DIR_NATIVE,;t t
+s,@TCL_INCLUDES@,$TCL_INCLUDES,;t t
+s,@TK_TOP_DIR_NATIVE@,$TK_TOP_DIR_NATIVE,;t t
+s,@TK_UNIX_DIR_NATIVE@,$TK_UNIX_DIR_NATIVE,;t t
+s,@TK_WIN_DIR_NATIVE@,$TK_WIN_DIR_NATIVE,;t t
+s,@TK_GENERIC_DIR_NATIVE@,$TK_GENERIC_DIR_NATIVE,;t t
+s,@TK_XLIB_DIR_NATIVE@,$TK_XLIB_DIR_NATIVE,;t t
+s,@TK_PLATFORM_DIR_NATIVE@,$TK_PLATFORM_DIR_NATIVE,;t t
+s,@TK_INCLUDES@,$TK_INCLUDES,;t t
+s,@CLEANFILES@,$CLEANFILES,;t t
+s,@EXTRA_SOURCES@,$EXTRA_SOURCES,;t t
+s,@TCL_THREADS@,$TCL_THREADS,;t t
+s,@SHARED_BUILD@,$SHARED_BUILD,;t t
+s,@AR@,$AR,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@DL_LIBS@,$DL_LIBS,;t t
+s,@CFLAGS_DEBUG@,$CFLAGS_DEBUG,;t t
+s,@CFLAGS_OPTIMIZE@,$CFLAGS_OPTIMIZE,;t t
+s,@CFLAGS_WARNING@,$CFLAGS_WARNING,;t t
+s,@EXTRA_CFLAGS@,$EXTRA_CFLAGS,;t t
+s,@STLIB_LD@,$STLIB_LD,;t t
+s,@SHLIB_LD@,$SHLIB_LD,;t t
+s,@SHLIB_CFLAGS@,$SHLIB_CFLAGS,;t t
+s,@SHLIB_LDFLAGS@,$SHLIB_LDFLAGS,;t t
+s,@SHLIB_LD_LIBS@,$SHLIB_LD_LIBS,;t t
+s,@LDFLAGS_DEBUG@,$LDFLAGS_DEBUG,;t t
+s,@LDFLAGS_OPTIMIZE@,$LDFLAGS_OPTIMIZE,;t t
+s,@TCL_DBGX@,$TCL_DBGX,;t t
+s,@CFLAGS_DEFAULT@,$CFLAGS_DEFAULT,;t t
+s,@LDFLAGS_DEFAULT@,$LDFLAGS_DEFAULT,;t t
+s,@MAKE_LIB@,$MAKE_LIB,;t t
+s,@MAKE_SHARED_LIB@,$MAKE_SHARED_LIB,;t t
+s,@MAKE_STATIC_LIB@,$MAKE_STATIC_LIB,;t t
+s,@MAKE_STUB_LIB@,$MAKE_STUB_LIB,;t t
+s,@TCLSH_PROG@,$TCLSH_PROG,;t t
+s,@WISH_PROG@,$WISH_PROG,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # 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. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;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,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# 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 || { (exit 1); exit 1; }
+fi
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..4e72f88
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,210 @@
+#!/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.
+#
+# RCS: @(#) $Id: configure.ac,v 1.1 2002/12/17 05:04:18 treectrl Exp $
+
+#-----------------------------------------------------------------------
+# Sample configure.in for Tcl Extensions. The only places you should
+# need to modify this file are marked by the string __CHANGE__
+#-----------------------------------------------------------------------
+
+#-----------------------------------------------------------------------
+# __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(generic/tkTreeCtrl.h)
+
+AC_CONFIG_AUX_DIR(tclconfig)
+CONFIGDIR=${srcdir}/tclconfig
+AC_SUBST(CONFIGDIR)
+
+#----------------------------------------------------------------------
+# __CHANGE__
+# Set your package name and version numbers here. The NODOT_VERSION is
+# required for constructing the library name on systems that don't like
+# dots in library names (Windows). The VERSION variable is used on the
+# other systems.
+#----------------------------------------------------------------------
+
+PACKAGE=treectrl
+
+MAJOR_VERSION=1
+MINOR_VERSION=0
+PATCHLEVEL=
+
+VERSION=${MAJOR_VERSION}.${MINOR_VERSION}${PATCHLEVEL}
+NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
+
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+# This package name must be replaced statically for AC_SUBST to work
+AC_SUBST(treectrl_LIB_FILE)
+# Substitute stub_LIB_FILE if your package creates a stub library too.
+#AC_SUBST(samplestub_LIB_FILE)
+
+#--------------------------------------------------------------------
+# We put this here so that you can compile with -DVERSION="1.2" to
+# encode the package version directly into the source files.
+#--------------------------------------------------------------------
+
+eval AC_DEFINE_UNQUOTED(VERSION, "${VERSION}")
+
+#--------------------------------------------------------------------
+# Call TEA_INIT as the first TEA_ macro to set up initial vars.
+# This will define a ${TEA_PLATFORM} variable == "unix" or "windows".
+#--------------------------------------------------------------------
+
+TEA_INIT
+
+#--------------------------------------------------------------------
+# 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__
+# 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
+
+#--------------------------------------------------------------------
+# __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.
+#--------------------------------------------------------------------
+
+if test "${TEA_PLATFORM}" = "windows" ; then
+ AC_DEFINE(BUILD_treectrl)
+ CLEANFILES="pkgIndex.tcl *.lib *.dll *.exp *.ilk *.pdb vc*.pch"
+ EXTRA_SOURCES='$(WIN_SOURCES)'
+else
+ CLEANFILES="pkgIndex.tcl"
+ EXTRA_SOURCES='$(UNIX_SOURCES)'
+fi
+AC_SUBST(CLEANFILES)
+AC_SUBST(EXTRA_SOURCES)
+
+#--------------------------------------------------------------------
+# 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
+
+#--------------------------------------------------------------------
+# 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
+
+#--------------------------------------------------------------------
+# __CHANGE__
+# Add platform libs to LIBS or SHLIB_LD_LIBS as necessary.
+#--------------------------------------------------------------------
+
+#LIBS="${LIBS} -lsuperfly"
+LIBS="${LIBS} ${TK_LIBS}"
+
+#--------------------------------------------------------------------
+# 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([Makefile pkgIndex.tcl])
diff --git a/demo.tcl b/demo.tcl
new file mode 100644
index 0000000..d9c0f77
--- /dev/null
+++ b/demo.tcl
@@ -0,0 +1,935 @@
+#! D:/Programming/Tcl-8.4.1/bin/wish84.exe
+
+# 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 [eval file join [list $::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
+}
+
+if {[catch {
+ package require dbwin 1.0
+}]} {
+ proc dbwin s {puts -nonewline $s}
+}
+if {[file exists libtreectrl1.0[info sharedlibextension]} {
+ load libtreectrl1.0[info sharedlibextension]
+} else {
+ load Build/treectrl[info sharedlibextension]
+}
+
+# Default TreeCtrl bindings
+source [Path library treectrl.tcl]
+
+# Other useful bindings
+source [Path library filelist-bindings.tcl]
+
+# Demo sources
+foreach file [glob -directory [Path demos] *.tcl] {
+ source $file
+}
+
+# Get default colors
+set w [listbox .listbox]
+set SystemButtonFace [$w cget -highlightbackground]
+set SystemHighlight [$w cget -selectbackground]
+set SystemHighlightText [$w cget -selectforeground]
+destroy $w
+
+proc MakeMenuBar {} {
+ set m [menu .menubar]
+ . configure -menu $m
+ set m2 [menu $m.mFile -tearoff no]
+ if {$::tcl_platform(platform) ne "unix"} {
+ console eval {.console conf -height 8}
+ $m2 add command -label "Console" -command {
+ if {[console eval {winfo ismapped .}]} {
+ console hide
+ } else {
+ console show
+ }
+ }
+ }
+ $m2 add command -label "View Source" -command ToggleSourceWindow
+ $m2 add command -label Quit -command exit
+ $m add cascade -label File -menu $m2
+ return
+}
+
+proc MakeSourceWindow {} {
+ set w [toplevel .source]
+ set f [frame $w.f -borderwidth 0]
+ if {$::tcl_platform(platform) eq "unix"} {
+ set font {Courier 16}
+ } else {
+ set font {Courier 9}
+ }
+ text $f.t -font $font -tabs [font measure $font 1234] -wrap none \
+ -yscrollcommand "$f.sv set" -xscrollcommand "$f.sh set"
+ scrollbar $f.sv -orient vertical -command "$f.t yview"
+ scrollbar $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 "wm withdraw $w"
+ wm geom $w -0+0
+ wm withdraw $w
+
+ return
+}
+proc ShowSource {file} {
+ wm title .source "Demo Source: $file"
+ set path [Path demos $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 ToggleSourceWindow {} {
+ set w .source
+ if {[winfo ismapped $w]} {
+ wm withdraw $w
+ } else {
+ wm deiconify $w
+ }
+ return
+}
+
+MakeSourceWindow
+MakeMenuBar
+
+proc TreePlusScrollbarsInAFrame {f h v} {
+ frame $f -borderwidth 1 -relief sunken
+ if {$::tcl_platform(platform) eq "unix"} {
+ set font {Helvetica 16}
+ } else {
+ # There is a bug on my Win98 box with Tk_MeasureChars() and
+ # MS Sans Serif 8.
+ set font {{MS Sans} 8}
+ }
+ treectrl $f.t -highlightthickness 0 -borderwidth 0 -font $font
+ $f.t configure -xscrollincrement 20
+ $f.t debug configure -enable no -display no
+ if {$h} {
+ scrollbar $f.sh -orient horizontal -command "$f.t xview"
+# $f.t configure -xscrollcommand "$f.sh set"
+ $f.t notify bind $f.sh <Scroll-x> { %W set %l %u }
+ bind $f.sh <ButtonPress-1> "focus $f.t"
+ }
+ if {$v} {
+ scrollbar $f.sv -orient vertical -command "$f.t yview"
+# $f.t configure -yscrollcommand "$f.sv set"
+ $f.t notify bind $f.sv <Scroll-y> { %W set %l %u }
+ bind $f.sv <ButtonPress-1> "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
+ }
+ return
+}
+
+proc MakeMainWindow {} {
+
+ wm title . "TkTreeCtrl Demo"
+ wm geometry . +0+0
+
+ panedwindow .pw2 -orient horizontal -borderwidth 0
+ panedwindow .pw1 -orient vertical -borderwidth 0
+
+ # Tree + scrollbar: demos
+ TreePlusScrollbarsInAFrame .f1 0 1
+ .f1.t configure -showbuttons no -showlines no -showroot no -height 100
+ .f1.t column configure 0 -text "List of Demos" -expand yes -button no
+
+ # Tree + scrollbar: styles + elements in list
+ TreePlusScrollbarsInAFrame .f4 0 1
+ .f4.t configure -showroot no -height 140
+ .f4.t column configure 0 -text "Elements and Styles" -expand yes -button no
+
+ # Tree + scrollbar: styles + elements in selected item
+ TreePlusScrollbarsInAFrame .f3 0 1
+ .f3.t configure -showroot no
+ .f3.t column configure 0 -text "Styles in Item" -expand yes -button no
+
+ .pw1 add .f1 .f4 .f3 -height 150
+
+ # Frame on right
+ frame .f2
+
+ # Tree + scrollbars
+ TreePlusScrollbarsInAFrame .f2.f1 1 1
+ .f2.f1.t configure -indent 19
+ .f2.f1.t debug configure -enable no -display yes -erasecolor pink -displaydelay 30
+
+ # Give it a big border to debug drawing
+ .f2.f1.t 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
+
+ .pw2 add .pw1 -width 200
+ .pw2 add .f2 -width 450
+
+ pack .pw2 -expand yes -fill both
+
+ ###
+ .f2.f1.t notify install event Header
+ .f2.f1.t notify install detail Header invoke
+
+ .f2.f1.t notify install event Drag
+ .f2.f1.t notify install detail Drag begin
+ .f2.f1.t notify install detail Drag end
+ .f2.f1.t notify install detail Drag receive
+
+ .f2.f1.t notify install event Edit
+ .f2.f1.t notify install detail Edit accept
+ ###
+
+ return
+}
+
+proc MakeListPopup {} {
+ set m [menu .f2.f1.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.mDebug -tearoff no]
+ $m2 add checkbutton -label Data -variable Popup(debug,data) \
+ -command {.f2.f1.t debug configure -data $Popup(debug,data)}
+ $m2 add checkbutton -label Display -variable Popup(debug,display) \
+ -command {.f2.f1.t debug configure -display $Popup(debug,display)}
+ $m2 add checkbutton -label Enable -variable Popup(debug,enable) \
+ -command {.f2.f1.t debug configure -enable $Popup(debug,enable)}
+ $m add cascade -label Debug -menu $m2
+
+ set m2 [menu $m.mBuffer -tearoff no]
+ $m2 add radiobutton -label "none" -variable Popup(doublebuffer) -value none \
+ -command {.f2.f1.t configure -doublebuffer $Popup(doublebuffer)}
+ $m2 add radiobutton -label "item" -variable Popup(doublebuffer) -value item \
+ -command {.f2.f1.t configure -doublebuffer $Popup(doublebuffer)}
+ $m2 add radiobutton -label "window" -variable Popup(doublebuffer) -value window \
+ -command {.f2.f1.t configure -doublebuffer $Popup(doublebuffer)}
+ $m add cascade -label Buffering -menu $m2
+
+ set m2 [menu $m.mLineStyle -tearoff no]
+ $m2 add radiobutton -label "dot" -variable Popup(linestyle) -value dot \
+ -command {.f2.f1.t configure -linestyle $Popup(linestyle)}
+ $m2 add radiobutton -label "solid" -variable Popup(linestyle) -value solid \
+ -command {.f2.f1.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 {.f2.f1.t configure -orient $Popup(orient)}
+ $m2 add radiobutton -label "Vertical" -variable Popup(orient) -value vertical \
+ -command {.f2.f1.t configure -orient $Popup(orient)}
+ $m add cascade -label Orient -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 {.f2.f1.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 {.f2.f1.t configure -showbuttons $Popup(showbuttons)}
+ $m2 add checkbutton -label "Header" -variable Popup(showheader) \
+ -command {.f2.f1.t configure -showheader $Popup(showheader)}
+ $m2 add checkbutton -label "Lines" -variable Popup(showlines) \
+ -command {.f2.f1.t configure -showlines $Popup(showlines)}
+ $m2 add checkbutton -label "Root" -variable Popup(showroot) \
+ -command {.f2.f1.t configure -showroot $Popup(showroot)}
+ $m2 add checkbutton -label "Root Button" -variable Popup(showrootbutton) \
+ -command {.f2.f1.t configure -showrootbutton $Popup(showrootbutton)}
+ $m add cascade -label Show -menu $m2
+
+ set m2 [menu $m.mVisible -tearoff no]
+ $m add cascade -label Visible -menu $m2
+ return
+}
+
+proc MakeHeaderPopup {} {
+ set m [menu .f2.f1.t.mHeader -tearoff no]
+
+ set m2 [menu $m.mArrow -tearoff no]
+ $m add cascade -label Arrow -menu $m2
+ $m2 add radiobutton -label "None" -variable Popup(arrow) -value none -command {.f2.f1.t column configure $Popup(column) -arrow none}
+ $m2 add radiobutton -label "Up" -variable Popup(arrow) -value up -command {.f2.f1.t column configure $Popup(column) -arrow up}
+ $m2 add radiobutton -label "Down" -variable Popup(arrow) -value down -command {.f2.f1.t column configure $Popup(column) -arrow down}
+ $m2 add separator
+ $m2 add radiobutton -label "Side Left" -variable Popup(arrow,side) -value left -command {.f2.f1.t column configure $Popup(column) -arrowside left}
+ $m2 add radiobutton -label "Side Right" -variable Popup(arrow,side) -value right -command {.f2.f1.t column configure $Popup(column) -arrowside right}
+ $m2 add separator
+ $m2 add radiobutton -label "Gravity Left" -variable Popup(arrow,gravity) -value left -command {.f2.f1.t column configure $Popup(column) -arrowgravity left}
+ $m2 add radiobutton -label "Gravity Right" -variable Popup(arrow,gravity) -value right -command {.f2.f1.t column configure $Popup(column) -arrowgravity right}
+
+ $m add checkbutton -label "Expand" -variable Popup(expand) -command {.f2.f1.t column configure $Popup(column) -expand $Popup(expand)}
+
+ set m2 [menu $m.mJustify -tearoff no]
+ $m add cascade -label Justify -menu $m2
+ $m2 add radiobutton -label "Left" -variable Popup(justify) -value left -command {.f2.f1.t column configure $Popup(column) -justify left}
+ $m2 add radiobutton -label "Center" -variable Popup(justify) -value center -command {.f2.f1.t column configure $Popup(column) -justify center}
+ $m2 add radiobutton -label "Right" -variable Popup(justify) -value right -command {.f2.f1.t column configure $Popup(column) -justify right}
+ return
+}
+
+MakeMainWindow
+MakeListPopup
+MakeHeaderPopup
+
+bind .f2.f1.t <ButtonPress-3> {
+ set id [%W identify %x %y]
+ if {$id ne ""} {
+ if {[lindex $id 0] eq "header"} {
+ set Popup(column) [lindex $id 1]
+ set Popup(arrow) [%W column cget $Popup(column) -arrow]
+ set Popup(arrow,side) [%W column cget $Popup(column) -arrowside]
+ set Popup(arrow,gravity) [%W column cget $Popup(column) -arrowgravity]
+ set Popup(expand) [%W column cget $Popup(column) -expand]
+ set Popup(justify) [%W column cget $Popup(column) -justify]
+ tk_popup %W.mHeader %X %Y
+ return
+ }
+ }
+ set m %W.mTree.mCollapse
+ $m delete 0 end
+ $m add command -label "All" -command {%W collapse all}
+ if {$id ne ""} {
+ if {[lindex $id 0] eq "item"} {
+ set item [lindex $id 1]
+ $m add command -label "Item $item" -command "%W collapse $item"
+ $m add command -label "Item $item (recurse)" -command "%W collapse -recurse $item"
+ }
+ }
+ set m %W.mTree.mExpand
+ $m delete 0 end
+ $m add command -label "All" -command {%W expand all}
+ if {$id ne ""} {
+ if {[lindex $id 0] eq "item"} {
+ set item [lindex $id 1]
+ $m add command -label "Item $item" -command "%W expand $item"
+ $m add command -label "Item $item (recurse)" -command "%W expand -recurse $item"
+ }
+ }
+ foreach option {data display enable} {
+ set Popup(debug,$option) [%W debug cget -$option]
+ }
+ set Popup(doublebuffer) [%W cget -doublebuffer]
+ set Popup(linestyle) [%W cget -linestyle]
+ set Popup(orient) [%W cget -orient]
+ set Popup(selectmode) [%W cget -selectmode]
+ set Popup(showbuttons) [%W cget -showbuttons]
+ set Popup(showheader) [%W cget -showheader]
+ set Popup(showlines) [%W cget -showlines]
+ set Popup(showroot) [%W cget -showroot]
+ set Popup(showrootbutton) [%W cget -showrootbutton]
+ set m %W.mTree.mVisible
+ $m delete 0 end
+ for {set i 0} {$i < [%W numcolumns]} {incr i} {
+ set Popup(visible,$i) [%W column cget $i -visible]
+ $m add checkbutton -label "Column $i \"[%W column cget $i -text]\" \[[%W column cget $i -image]\]" -variable Popup(visible,$i) \
+ -command "%W column configure $i -visible \$Popup(visible,$i)"
+ }
+ tk_popup %W.mTree %X %Y
+}
+
+bind TreeCtrlXXX <ButtonPress-1> {
+ focus %W
+ set id [%W identify %x %y]
+ puts "identify: $id"
+ if {$id ne "" && [lindex $id 0] eq "item"} {
+ foreach {where item arg1 arg2} $id {}
+ if {$arg1 eq "button"} {
+ %W toggle $item
+ return
+ } elseif {$arg1 eq "line"} {
+ %W toggle $arg2
+ return
+ }
+ }
+ TreeCtrl::ButtonPress1 %W %x %y
+}
+
+#
+# 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] -ipadw 2 -ipade 2 -ipads 1 -iexpand e
+
+ # "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)" DemoExplorerDetails explorer.tcl \
+ "Explorer (List)" DemoExplorerList explorer.tcl \
+ "Explorer (Large icons)" DemoExplorerLargeIcons 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 \
+ ] {
+ set item [$t item create]
+ $t item lastchild root $item
+ $t item style set $item 0 s1
+ $t item text $item 0 $label
+ set DemoCmd($item) $command
+ set DemoFile($item) $file
+ }
+ $t yview moveto 0.0
+ return
+}
+
+InitDemoList
+
+proc ClicksToSeconds {clicks} {
+ return [format "%.2g" [expr {$clicks / 1000000.0}]]
+}
+
+proc DemoSet {cmd file} {
+ DemoClear
+ set clicks [clock clicks]
+ uplevel #0 $cmd
+ set clicks [expr {[clock clicks] - $clicks}]
+ puts "set list in [ClicksToSeconds $clicks] seconds ($clicks clicks)"
+ .f2.f1.t xview moveto 0
+ .f2.f1.t yview moveto 0
+ update
+ DisplayStylesInList
+ ShowSource $file
+}
+
+.f1.t notify bind .f1.t <Selection> {
+ if {%c == 1} {
+ set selection [%T selection get]
+ set item [lindex $selection 0]
+ DemoSet $DemoCmd($item) $DemoFile($item)
+ }
+}
+
+proc DisplayStylesInList {} {
+
+ set T .f2.f1.t
+ 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] -ipadw 1 -ipade 1 -ipadn 0 -ipads 1
+
+ $t style create s2
+ $t style elements s2 {e3 e1 e2}
+ $t style layout s2 e1 -pade 4
+ $t style layout s2 e3 -union [list e1 e2] -ipade 1 -ipadw 1 -ipadn 0 -ipads 1
+ }
+
+ # Clear the list
+ $t item delete all
+
+ # One item for each element in the demo list
+ foreach elem [lsort [$T element names]] {
+ set item [$t item create]
+ $t collapse $item
+ $t item hasbutton $item yes
+ $t item style set $item 0 s1
+ $t item text $item 0 "Element $elem ([$T element type $elem])"
+
+ # One item for each configuration option for this element
+ foreach list [$T element configure $elem] {
+ foreach {name x y default current} $list {}
+ set item2 [$t item create]
+ if {[string equal $default $current]} {
+ $t item style set $item2 0 s1
+ $t item complex $item2 [list [list e1 -text [list $name $current]]]
+ } else {
+ $t item style set $item2 0 s2
+ $t item complex $item2 [list [list e1 -text $name] [list 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 [$T style names]] {
+ set item [$t item create]
+ $t collapse $item
+ $t item hasbutton $item yes
+ $t item style set $item 0 s1
+ $t item text $item 0 "Style $style"
+
+ # One item for each element in the style
+ foreach elem [$T style elements $style] {
+ set item2 [$t item create]
+ $t collapse $item2
+ $t item hasbutton $item2 yes
+ $t item style set $item2 0 s1
+ $t item text $item2 0 "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 0 s1
+ $t item text $item3 0 [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 .f2.f1.t
+ set t .f3.t
+ $t column configure 0 -text "Styles in item [$T index $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] -ipade 1 -ipadw 2 -ipadn 0 -ipads 1
+
+ $t style create s2
+ $t style elements s2 {e3 e1 e2}
+ $t style layout s2 e1 -pade 4
+ $t style layout s2 e3 -union [list e1 e2] -ipadw 1 -ipade 1 -ipadn 0 -ipads 1
+ }
+
+ # Clear the list
+ $t item delete all
+
+ # One item for each item-column
+ set column 0
+ foreach style [$T item style set $item] {
+ set item2 [$t item create]
+ $t collapse $item2
+ $t item style set $item2 0 s1
+ $t item element configure $item2 0 e1 -text "Column $column: Style $style"
+ set button 0
+
+ # One item for each element in this style
+ if {[string length $style]} {
+ foreach elem [$T item style elements $item $column] {
+ set button 1
+ set item3 [$t item create]
+ $t collapse $item3
+ $t item hasbutton $item3 yes
+ $t item style set $item3 0 s1
+ $t item element configure $item3 0 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] {
+ foreach {name x y default current} $list {}
+ 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 0 s1
+ $t item complex $item4 [list [list e1 -text "$name [list $current]"]]
+ } else {
+ $t item style set $item4 0 s2
+ $t item complex $item4 [list [list e1 -text $name] [list e2 -text [list $current]]]
+ }
+ $t item lastchild $item3 $item4
+ }
+ $t item lastchild $item2 $item3
+ }
+ if {$button} {
+ $t item hasbutton $item2 yes
+ }
+ }
+ $t item lastchild root $item2
+ incr column
+ }
+ $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
+.f2.f1.t notify bind DontDelete <Selection> {
+ if {%c == 1} {
+ set selection [%T selection get]
+ DisplayStylesInItem [lindex $selection 0]
+ }
+}
+
+proc DemoClear {} {
+
+ set T .f2.f1.t
+
+ # Clear the demo list
+ $T item delete all
+
+ # Clear all bindings on the demo list added by the previous demo.
+ # This is why DontDelete it used for the <Selection> binding.
+ foreach pattern [$T notify bind $T] {
+ $T notify bind $T $pattern {}
+ }
+
+ # Clear all run-time states
+ foreach state [$T state names] {
+ $T state undefine $state
+ }
+
+ # Clear the styles-in-item list
+ .f3.t item delete all
+
+ # Delete columns in demo list
+ while {[$T numcolumns]} {
+ $T column delete 0
+ }
+
+ # 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]
+
+ $T item hasbutton root no
+ $T expand root
+
+ # Restore some happy defaults to the demo list
+ $T configure -orient vertical -wrap "" -xscrollincrement 0 \
+ -yscrollincrement 0 -itemheight 0 -showheader yes \
+ -background white -scrollmargin 0 -xscrolldelay 50 -yscrolldelay 50 \
+ -openbuttonimage "" -closedbuttonimage "" -backgroundmode row
+
+ # Restore default bindings to the demo list
+ bindtags $T [list $T TreeCtrl [winfo toplevel $T] all]
+
+ catch {destroy $T.entry}
+ catch {destroy $T.text}
+
+ return
+}
+
+#
+# Demo: Picture catalog
+#
+proc DemoPictureCatalog {} {
+
+ set T .f2.f1.t
+
+ $T configure -showroot no -showbuttons no -showlines no \
+ -selectmode multiple -orient horizontal -wrap window \
+ -yscrollincrement 50 -showheader no
+
+ $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 -ipadn 6 -ipads 6 -ipadw 6 -ipade 6
+ $T style layout $S elemSelTxt -union elemTxt
+ $T style layout $S elemImg -pads 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 .f2.f1.t
+
+ $T configure -showroot no -showbuttons no -showlines no \
+ -selectmode multiple -orient horizontal -wrap window \
+ -yscrollincrement 50 -showheader no
+
+ $T element create elemTxt text -fill {SystemHighlightText {selected focus}} \
+ -justify left -wrap word -lines 2
+ $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 \
+ -ipadn 6 -ipads 6 -ipadw 6 -ipade 6
+ $T style layout $S elemSelTxt -union elemTxt
+ $T style layout $S elemImg -pads 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 <Enter> "
+ $c configure -cursor $cursor
+ $c itemconfigure $cursor.rect -fill linen
+ "
+ $c bind $cursor.rect <Leave> "
+ $c configure -cursor {}
+ $c itemconfigure $cursor.rect -fill gray90
+ "
+ $c bind $cursor.text <Enter> "
+ $c configure -cursor $cursor
+ "
+ $c bind $cursor.text <Leave> "
+ $c configure -cursor {}
+ "
+ }
+ $c configure -height [expr {($row + 1) * 40}]
+ return
+}
+
+proc compare {i1 i2} {
+ if {$i1 < $i2} { return -1 }
+ if {$i1 == $i2} { return 0 }
+ return 1
+}
+
+# A little screen magnifier for X11
+if {$::tcl_platform(platform) eq "unix"} {
+
+set Loupe(zoom) 3
+set Loupe(x) 0
+set Loupe(y) 0
+set Loupe(auto) 1
+
+proc LoupeAfter {} {
+
+ global Loupe
+
+ set x [winfo pointerx .]
+ set y [winfo pointery .]
+ if {$Loupe(auto) || ($Loupe(x) != $x) || ($Loupe(y) != $y)} {
+ set w [image width $Loupe(image)]
+ set h [image height $Loupe(image)]
+ loupe $Loupe(image) $x $y $w $h $::Loupe(zoom)
+ set Loupe(x) $x
+ set Loupe(y) $y
+ }
+ after $Loupe(delay) LoupeAfter
+ return
+}
+
+proc MakeLoupeWindow {} {
+
+ global Loupe
+
+ set w [toplevel .loupe]
+ wm geometry $w -0+0
+ image create photo ImageLoupe -width 150 -height 150
+ pack [label $w.label -image ImageLoupe]
+ set Loupe(image) ImageLoupe
+ set Loupe(delay) 500
+ after $Loupe(delay) LoupeAfter
+ return
+}
+MakeLoupeWindow
+
+# unix
+}
+
diff --git a/demos/bitmaps.tcl b/demos/bitmaps.tcl
new file mode 100644
index 0000000..36917af
--- /dev/null
+++ b/demos/bitmaps.tcl
@@ -0,0 +1,55 @@
+#
+# Demo: Bitmaps
+#
+proc DemoBitmaps {} {
+
+ set T .f2.f1.t
+
+ $T configure -showroot no -showbuttons no -showlines no \
+ -selectmode browse -orient horizontal -wrap "5 items" \
+ -showheader no
+
+ $T column configure 0 -itembackground {gray90 {}}
+
+ $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}}
+
+ set S [$T style create STYLE -orient vertical]
+ $T style elements $S {elemSelBmp elemBmp elemSelTxt elemTxt}
+ $T style layout $S elemSelBmp -union elemBmp \
+ -ipadn 6 -ipads 6 -ipadw 6 -ipade 6
+ $T style layout $S elemBmp -pads 6 -expand we
+ $T style layout $S elemSelTxt -union elemTxt -ipadw 2 -ipade 2
+ $T style layout $S elemTxt -expand we
+
+ set bitmapNames [list error gray75 gray50 gray25 gray12 hourglass info \
+ questhead question warning]
+
+ foreach name $bitmapNames {
+ set I [$T item create]
+ $T item style set $I 0 $S
+ $T item text $I 0 $name
+ $T item element configure $I 0 elemBmp -bitmap $name
+ $T item lastchild root $I
+ }
+
+ foreach name $bitmapNames {
+ set I [$T item create]
+ $T item style set $I 0 $S
+ $T item text $I 0 $name
+ $T item element configure $I 0 elemBmp -bitmap $name \
+ -foreground [list $::SystemHighlight {selected focus} brown {}] \
+ -background {"" {}}
+ $T item lastchild root $I
+ }
+
+ return
+}
+
diff --git a/demos/explorer.tcl b/demos/explorer.tcl
new file mode 100644
index 0000000..ab388f7
--- /dev/null
+++ b/demos/explorer.tcl
@@ -0,0 +1,367 @@
+set Dir [file dirname [Path]]
+
+proc DemoExplorerAux {scriptDir scriptFile} {
+
+ set T .f2.f1.t
+
+ set clicks [clock clicks]
+ set globDirs [glob -nocomplain -types d -dir $::Dir *]
+ set clickGlobDirs [expr {[clock clicks] - $clicks}]
+
+ set clicks [clock clicks]
+ set list [lsort -dictionary $globDirs]
+ set clickSortDirs [expr {[clock clicks] - $clicks}]
+
+ set clicks [clock clicks]
+ foreach file $list $scriptDir
+ set clickAddDirs [expr {[clock clicks] - $clicks}]
+
+ set clicks [clock clicks]
+ set globFiles [glob -nocomplain -types f -dir $::Dir *]
+ set clickGlobFiles [expr {[clock clicks] - $clicks}]
+
+ set clicks [clock clicks]
+ set list [lsort -dictionary $globFiles]
+ set clickSortFiles [expr {[clock clicks] - $clicks}]
+
+ set clicks [clock clicks]
+ foreach file $list $scriptFile
+ set clickAddFiles [expr {[clock clicks] - $clicks}]
+
+ set gd [ClicksToSeconds $clickGlobDirs]
+ set sd [ClicksToSeconds $clickSortDirs]
+ set ad [ClicksToSeconds $clickAddDirs]
+ set gf [ClicksToSeconds $clickGlobFiles]
+ set sf [ClicksToSeconds $clickSortFiles]
+ set af [ClicksToSeconds $clickAddFiles]
+ puts "dirs([llength $globDirs]) glob/sort/add $gd/$sd/$ad files([llength $globFiles]) glob/sort/add $gf/$sf/$af"
+
+ set ::TreeCtrl::Priv(DirCnt,$T) [llength $globDirs]
+
+ return
+}
+
+#
+# Demo: explorer files
+#
+proc DemoExplorerDetails {} {
+
+ set T .f2.f1.t
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -showroot no -showbuttons no -showlines no -itemheight $height \
+ -selectmode extended -xscrollincrement 20 \
+ -scrollmargin 16 -xscrolldelay "500 50" -yscrolldelay "500 50"
+
+ InitPics small-*
+
+ $T column configure 0 -text Name -tag name -width 200 \
+ -arrow up -arrowpadw 6 -arrowpade 6
+ $T column configure 1 -text Size -tag size -justify right -width 60 \
+ -arrowside left -arrowgravity right
+ $T column configure 2 -text Type -tag type -width 120
+ $T column configure 3 -text Modified -tag modified -width 120
+
+ $T element create e1 image -image {small-folderSel {selected} small-folder {}}
+ $T element create e2 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 e4 rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] -showfocus yes
+
+ # image + text
+ set S [$T style create styName -orient horizontal]
+ $T style elements $S {e4 e1 e2}
+ $T style layout $S e1 -expand ns
+ $T style layout $S e2 -padw 2 -squeeze x -expand ns
+ $T style layout $S e4 -union [list e2] -iexpand ns -ipadw 2 -ipade 2
+
+ # column 1: text
+ set S [$T style create stySize]
+ $T style elements $S txtSize
+ $T style layout $S txtSize -padw 6 -pade 6 -squeeze x -expand ns
+
+ # column 2: text
+ set S [$T style create styType]
+ $T style elements $S txtType
+ $T style layout $S txtType -padw 6 -pade 6 -squeeze x -expand ns
+
+ # column 3: text
+ set S [$T style create styDate]
+ $T style elements $S txtDate
+ $T style layout $S txtDate -padw 6 -pade 6 -squeeze x -expand ns
+
+ set ::TreeCtrl::Priv(edit,$T) {e2}
+ set ::TreeCtrl::Priv(sensitive,$T) {e1 e2}
+ set ::TreeCtrl::Priv(dragimage,$T) {
+ {0 styName e1 e2}
+ }
+
+ $T notify bind $T <Edit-accept> {
+ %T item text %I 0 %t
+ }
+
+ set scriptDir {
+ set item [$T item create]
+ $T item style set $item 0 styName 2 styType 3 styDate
+ $T item complex $item \
+ [list [list e2 -text [file tail $file]]] \
+ [list] \
+ [list [list txtType -text "Folder"]] \
+ [list [list txtDate -data [file mtime $file]]]
+ $T item lastchild root $item
+ }
+
+ set scriptFile {
+ set item [$T item create]
+ $T item style set $item 0 styName 1 stySize 2 styType 3 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"
+ $T item complex $item \
+ [list [list e1 -image [list ${img}Sel {selected} $img {}]] [list e2 -text [file tail $file]]] \
+ [list [list txtSize -data [expr {[file size $file] / 1024 + 1}]]] \
+ [list [list txtType -text $type]] \
+ [list [list txtDate -data [file mtime $file]]]
+ $T item lastchild root $item
+ }
+
+ DemoExplorerAux $scriptDir $scriptFile
+
+ set ::SortColumn 0
+ $T notify bind $T <Header-invoke> { ExplorerHeaderInvoke %T %C }
+
+ bindtags $T [list $T TreeCtrlFileList TreeCtrl [winfo toplevel $T] all]
+
+ return
+}
+
+proc ExplorerHeaderInvoke {T C} {
+ global SortColumn
+ if {$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
+ set dirCount $::TreeCtrl::Priv(DirCnt,$T)
+ set lastDir [expr {$dirCount - 1}]
+ switch [$T column cget $C -tag] {
+ name {
+ if {$dirCount} {
+ $T item sort root $order -last "root child $lastDir" -column $C -dictionary
+ }
+ if {$dirCount < [$T numitems] - 1} {
+ $T item sort root $order -first "root child $dirCount" -column $C -dictionary
+ }
+ }
+ size {
+ if {$dirCount < [$T numitems] - 1} {
+ $T item sort root $order -first "root child $dirCount" -column $C -integer -column name -dictionary
+ }
+ }
+ type {
+ if {$dirCount < [$T numitems] - 1} {
+ $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 $dirCount prevsibling" -column $C -integer -column name -dictionary
+ }
+ if {$dirCount < [$T numitems] - 1} {
+ $T item sort root $order -first "root child $dirCount" -column $C -integer -column name -dictionary
+ }
+ }
+ }
+ return
+}
+
+proc DemoExplorerLargeIcons {} {
+
+ set T .f2.f1.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}]
+
+ $T configure -showroot no -showbuttons no -showlines no \
+ -selectmode extended -wrap window -orient horizontal \
+ -itemheight $itemHeight -showheader no \
+ -scrollmargin 16 -xscrolldelay "500 50" -yscrolldelay "500 50"
+
+ InitPics big-*
+
+ $T column configure 0 -width 75
+
+ $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
+
+ # 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 -padn 4 -padw 2 -pade 2 -squeeze x -expand we
+ $T style layout $S elemSel -union [list elemTxt]
+
+ set ::TreeCtrl::Priv(edit,$T) {elemTxt}
+ set ::TreeCtrl::Priv(sensitive,$T) {elemImg elemTxt}
+ set ::TreeCtrl::Priv(dragimage,$T) {
+ {0 STYLE elemImg elemTxt}
+ }
+
+ $T notify bind $T <Edit-accept> {
+ %T item text %I 0 %t
+ }
+
+ set scriptDir {
+ set item [$T item create]
+ $T item style set $item 0 STYLE
+ $T item text $item 0 [file tail $file]
+ $T item lastchild root $item
+ }
+
+ set scriptFile {
+ set item [$T item create]
+ $T item style set $item 0 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"
+ $T item complex $item \
+ [list [list elemImg -image [list ${img}Sel {selected} $img {}]] [list elemTxt -text [file tail $file]]]
+ $T item lastchild root $item
+ }
+
+ DemoExplorerAux $scriptDir $scriptFile
+
+ $T activate [$T index "root firstchild"]
+
+ $T notify bind $T <ActiveItem> {
+ %T item element configure %p 0 elemTxt -lines {}
+ %T item element configure %c 0 elemTxt -lines 3
+ }
+
+ bindtags $T [list $T 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
+proc DemoExplorerSmallIcons {} {
+ set T .f2.f1.t
+ DemoExplorerList
+ $T configure -orient horizontal -xscrollincrement 0
+ $T column configure 0 -width {} -stepwidth 110 -widthhack no
+}
+
+# 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
+proc DemoExplorerList {} {
+
+ set T .f2.f1.t
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -showroot no -showbuttons no -showlines no -itemheight $height \
+ -selectmode extended -wrap window -showheader no \
+ -scrollmargin 16 -xscrolldelay "500 50" -yscrolldelay "500 50"
+
+ InitPics small-*
+
+ $T column configure 0 -widthhack yes
+
+ $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
+
+ # 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 -padw 2
+ $T style layout $S elemSel -union [list elemTxt] -iexpand ns -ipadw 2 -ipade 2
+
+ set ::TreeCtrl::Priv(edit,$T) {elemTxt}
+ set ::TreeCtrl::Priv(sensitive,$T) {elemImg elemTxt}
+ set ::TreeCtrl::Priv(dragimage,$T) {
+ {0 STYLE elemImg elemTxt}
+ }
+
+ $T notify bind $T <Edit-accept> {
+ %T item text %I 0 %t
+ }
+
+ set scriptDir {
+ set item [$T item create]
+ $T item style set $item 0 STYLE
+ $T item text $item 0 [file tail $file]
+ $T item lastchild root $item
+ }
+
+ set scriptFile {
+ set item [$T item create]
+ $T item style set $item 0 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"
+ $T item complex $item \
+ [list [list elemImg -image [list ${img}Sel {selected} $img {}]] [list elemTxt -text [file tail $file]]]
+ $T item lastchild root $item
+ }
+
+ DemoExplorerAux $scriptDir $scriptFile
+
+ $T activate [$T item firstchild root]
+
+ bindtags $T [list $T TreeCtrlFileList TreeCtrl [winfo toplevel $T] all]
+
+ return
+}
+
diff --git a/demos/help.tcl b/demos/help.tcl
new file mode 100644
index 0000000..fc67589
--- /dev/null
+++ b/demos/help.tcl
@@ -0,0 +1,347 @@
+#
+# Demo: Help contents
+#
+proc DemoHelpContents {} {
+
+ set T .f2.f1.t
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -showroot no -showbuttons no -showlines no -itemheight $height \
+ -selectmode browse
+
+ InitPics help-*
+
+ $T column configure 0 -text "Help Contents"
+
+ # Define a new item state
+ $T state define mouseover
+
+ $T element create e1 image -image help-page
+ $T element create e2 image -image {help-book-open {open} help-book-closed {}}
+ $T element create e3 text -fill [list $::SystemHighlightText {selected focus} blue {mouseover}] \
+ -font [list "[$T cget -font] underline" {mouseover}]
+ $T element create e4 rect -fill [list $::SystemHighlight {selected focus}] -showfocus yes
+
+ # book
+ set S [$T style create s1]
+ $T style elements $S {e4 e1 e3}
+ $T style layout $S e1 -pade 4 -expand ns
+ $T style layout $S e3 -expand ns
+ $T style layout $S e4 -union [list e3] -iexpand ns -ipadw 2 -ipade 2
+
+ # page
+ set S [$T style create s2]
+ $T style elements $S {e4 e2 e3}
+ $T style layout $S e2 -pade 4 -expand ns
+ $T style layout $S e3 -expand ns
+ $T style layout $S e4 -union [list e3] -iexpand ns -ipadw 2 -ipade 2
+
+ set parentList [list root {} {} {} {} {} {}]
+ set parent root
+ foreach {depth style text} {
+ 0 s1 "Welcome to Help"
+ 0 s2 "Introducing Windows 98"
+ 1 s2 "How to Use Help"
+ 2 s1 "Find a topic"
+ 2 s1 "Get more out of help"
+ 1 s2 "Register Your Software"
+ 2 s1 "Registering Windows 98 online"
+ 1 s2 "What's New in Windows 98"
+ 2 s1 "Innovative, easy-to-use features"
+ 2 s1 "Improved reliability"
+ 2 s1 "A faster operating system"
+ 2 s1 "True Web integration"
+ 2 s1 "More entertaining and fun"
+ 1 s2 "If You're New to Windows 98"
+ 2 s2 "Tips for Macintosh Users"
+ 3 s1 "Why does the mouse have two buttons?"
+ } {
+ set item [$T item create]
+ $T item style set $item 0 $style
+ $T item element configure $item 0 e3 -text $text
+ $T collapse $item
+ $T item lastchild [lindex $parentList $depth] $item
+ incr depth
+ set parentList [lreplace $parentList $depth $depth $item]
+ }
+
+ bind TreeCtrlHelp <Double-ButtonPress-1> {
+ TreeCtrl::DoubleButton1 %W %x %y
+ }
+ bind TreeCtrlHelp <ButtonPress-1> {
+ TreeCtrl::HelpButton1 %W %x %y
+ break
+ }
+ bind TreeCtrlHelp <Button1-Motion> {
+ TreeCtrl::HelpMotion1 %W %x %y
+ break
+ }
+ bind TreeCtrlHelp <Button1-Leave> {
+ TreeCtrl::HelpLeave1 %W %x %y
+ break
+ }
+ bind TreeCtrlHelp <ButtonRelease-1> {
+ TreeCtrl::HelpRelease1 %W %x %y
+ break
+ }
+ bind TreeCtrlHelp <Motion> {
+ TreeCtrl::HelpMotion %W %x %y
+ }
+ bind TreeCtrlHelp <Leave> {
+ TreeCtrl::HelpMotion %W %x %y
+ }
+ bind TreeCtrlHelp <KeyPress-Return> {
+ if {[llength [%W selection get]] == 1} {
+ %W toggle [%W selection get]
+ }
+ break
+ }
+
+ set ::TreeCtrl::Priv(help,prev) ""
+ bindtags $T [list $T TreeCtrlHelp 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 DemoHelpContents2 {} {
+
+ set T .f2.f1.t
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -showroot no -showbuttons no -showlines no -itemheight $height \
+ -selectmode browse
+
+ InitPics help-*
+
+ $T column configure 0 -text "Help Contents"
+
+ $T element create e1 image -image help-page
+ $T element create e2 image -image {help-book-open {open} help-book-closed {}}
+ $T element create e3 text -fill [list $::SystemHighlightText {selected focus}]
+ $T element create e4 rect -fill [list $::SystemHighlight {selected focus}] -showfocus yes
+ $T element create e5 text -fill [list $::SystemHighlightText {selected focus} blue {}] \
+ -font "[$T cget -font] underline"
+
+ # book
+ set S [$T style create s1]
+ $T style elements $S {e4 e1 e3}
+ $T style layout $S e1 -pade 4 -expand ns
+ $T style layout $S e3 -expand ns
+ $T style layout $S e4 -union [list e3] -iexpand ns -ipadw 2 -ipade 2
+
+ # page
+ set S [$T style create s2]
+ $T style elements $S {e4 e2 e3}
+ $T style layout $S e2 -pade 4 -expand ns
+ $T style layout $S e3 -expand ns
+ $T style layout $S e4 -union [list e3] -iexpand ns -ipadw 2 -ipade 2
+
+ # book (focus)
+ set S [$T style create s1.f]
+ $T style elements $S {e4 e1 e5}
+ $T style layout $S e1 -pade 4 -expand ns
+ $T style layout $S e5 -expand ns
+ $T style layout $S e4 -union [list e5] -iexpand ns -ipadw 1 -ipade 2
+
+ # page (focus)
+ set S [$T style create s2.f]
+ $T style elements $S {e4 e2 e5}
+ $T style layout $S e2 -pade 4 -expand ns
+ $T style layout $S e5 -expand ns
+ $T style layout $S e4 -union [list e5] -iexpand ns -ipadw 1 -ipade 2
+
+ set parentList [list root {} {} {} {} {} {}]
+ set parent root
+ foreach {depth style text} {
+ 0 s1 "Welcome to Help"
+ 0 s2 "Introducing Windows 98"
+ 1 s2 "How to Use Help"
+ 2 s1 "Find a topic"
+ 2 s1 "Get more out of help"
+ 1 s2 "Register Your Software"
+ 2 s1 "Registering Windows 98 online"
+ 1 s2 "What's New in Windows 98"
+ 2 s1 "Innovative, easy-to-use features"
+ 2 s1 "Improved reliability"
+ 2 s1 "A faster operating system"
+ 2 s1 "True Web integration"
+ 2 s1 "More entertaining and fun"
+ 1 s2 "If You're New to Windows 98"
+ 2 s2 "Tips for Macintosh Users"
+ 3 s1 "Why does the mouse have two buttons?"
+ } {
+ set item [$T item create]
+ $T item style set $item 0 $style
+ $T item element configure $item 0 e3 -text $text
+ $T collapse $item
+ $T item lastchild [lindex $parentList $depth] $item
+ incr depth
+ set parentList [lreplace $parentList $depth $depth $item]
+ }
+
+ bind TreeCtrlHelp <Double-ButtonPress-1> {
+ TreeCtrl::DoubleButton1 %W %x %y
+ }
+ bind TreeCtrlHelp <ButtonPress-1> {
+ TreeCtrl::HelpButton1 %W %x %y
+ break
+ }
+ bind TreeCtrlHelp <Button1-Motion> {
+ TreeCtrl::HelpMotion1 %W %x %y
+ break
+ }
+ bind TreeCtrlHelp <Button1-Leave> {
+ TreeCtrl::HelpLeave1 %W %x %y
+ break
+ }
+ bind TreeCtrlHelp <ButtonRelease-1> {
+ TreeCtrl::HelpRelease1 %W %x %y
+ break
+ }
+ bind TreeCtrlHelp <Motion> {
+ TreeCtrl::HelpMotion2 %W %x %y
+ }
+ bind TreeCtrlHelp <Leave> {
+ TreeCtrl::HelpMotion2 %W %x %y
+ }
+ bind TreeCtrlHelp <KeyPress-Return> {
+ if {[llength [%W selection get]] == 1} {
+ %W toggle [%W selection get]
+ }
+ break
+ }
+
+ set ::TreeCtrl::Priv(help,prev) ""
+ bindtags $T [list $T TreeCtrlHelp TreeCtrl [winfo toplevel $T] all]
+
+ return
+}
+
+proc TreeCtrl::HelpButton1 {w x y} {
+ variable Priv
+ focus $w
+ set id [$w identify $x $y]
+ set Priv(buttonMode) ""
+ if {[lindex $id 0] eq "header"} {
+ 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 toggle $item
+ return
+ }
+ if {[llength [$w selection get]} {
+ set item2 [$w selection get]
+ $w collapse $item2
+ foreach item2 [$w item ancestors $item2] {
+ if {[$w compare $item != $item2]} {
+ $w collapse $item2
+ }
+ }
+ }
+ $w selection modify $item all
+ $w activate $item
+ eval $w expand [$w item ancestors $item]
+ $w toggle $item
+ }
+ return
+}
+proc TreeCtrl::HelpMotion1 {w x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Motion1 $w $x $y
+ }
+ }
+ return
+}
+proc TreeCtrl::HelpLeave1 {w x y} {
+ variable Priv
+ # This is called when I do ButtonPress-1 on Unix for some reason,
+ # and buttonMode is undefined.
+ if {![info exists Priv(buttonMode)]} return
+ switch $Priv(buttonMode) {
+ "header" {
+ $w column configure $Priv(column) -sunken no
+ }
+ }
+ return
+}
+proc TreeCtrl::HelpRelease1 {w x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Release1 $w $x $y
+ }
+ }
+ set Priv(buttonMode) ""
+ return
+}
+
+proc TreeCtrl::HelpMotion {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(help,prev)} {
+ if {$Priv(help,prev) ne ""} {
+ $w item state $Priv(help,prev) !mouseover
+ }
+ $w item state $item mouseover
+ set Priv(help,prev) $item
+ }
+ return
+ }
+ }
+ if {$Priv(help,prev) ne ""} {
+ $w item state $Priv(help,prev) !mouseover
+ set Priv(help,prev) ""
+ }
+ return
+}
+
+# Alternate implementation doesn't rely on mouseover state
+proc TreeCtrl::HelpMotion2 {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(help,prev)} {
+ if {$Priv(help,prev) ne ""} {
+ set style [$w item style set $Priv(help,prev) 0]
+ set style [string trim $style .f]
+ $w item style map $Priv(help,prev) 0 $style {e5 e3}
+ }
+ set style [$w item style set $item 0]
+ $w item style map $item 0 $style.f {e3 e5}
+ set Priv(help,prev) $item
+ }
+ return
+ }
+ }
+ if {$Priv(help,prev) ne ""} {
+ set style [$w item style set $Priv(help,prev) 0]
+ set style [string trim $style .f]
+ $w item style map $Priv(help,prev) 0 $style {e5 e3}
+ set Priv(help,prev) ""
+ }
+ return
+}
+
diff --git a/demos/imovie.tcl b/demos/imovie.tcl
new file mode 100644
index 0000000..7540dfe
--- /dev/null
+++ b/demos/imovie.tcl
@@ -0,0 +1,111 @@
+#
+# Demo: iMovie
+#
+proc DemoIMovie {} {
+
+ set T .f2.f1.t
+
+ $T configure -showroot no -showbuttons no -showlines no \
+ -selectmode browse -orient horizontal -wrap window \
+ -showheader no -background #dcdcdc
+
+ InitPics imovie-*
+
+ if {$::tcl_platform(platform) eq "unix"} {
+ set font1 {Helvetica 12}
+ set font2 {Helvetica 14}
+ } else {
+ set font1 {Helvetica 8}
+ set font2 {Helvetica 10}
+ }
+
+ $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
+
+ set S [$T style create STYLE -orient vertical]
+ $T style elements $S {elemShadow elemRect elemTime elemImg elemName}
+ $T style layout $S elemShadow -detach yes -pade 2 -pads 2 -padn 1 -padw 1 -iexpand es
+ $T style layout $S elemTime -padw 2
+ $T style layout $S elemImg -pads 1
+ $T style layout $S elemName -expand we -ipads 2 -pade 3 -squeeze x
+ $T style layout $S elemRect -union {elemTime elemImg elemName} \
+ -ipadw 6 -ipade 6 -pade 3 -pads 3
+
+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 0 $S
+ $T item element configure $I 0 elemTime -text $time
+ $T item element configure $I 0 elemImg -image $image
+ $T item element configure $I 0 elemName -text $name
+ $T item lastchild root $I
+ }
+}
+
+ $T notify bind $T <Edit-accept> {
+ %T item element configure %I %C %E -text %t
+ }
+
+ bind iMovie <ButtonPress-1> {
+ iMovieButton1 %W %x %y
+ }
+
+ bindtags $T [list $T iMovie TreeCtrl [winfo toplevel $T] all]
+
+ return
+}
+
+proc iMovieButton1 {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
+ foreach {where item arg1 arg2 arg3 arg4} $id {}
+ 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 0 $E
+ if {!$exists} {
+ $T.entry configure -borderwidth 0 -justify center \
+ -background #ffdc5a
+ scan [$T item bbox $I 0 $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] "%d %d %d %d" x1 y1 x2 y2
+ place $T.entry -x [expr {$x1 + 1}] -width [expr {$x2 - $x1 - 5}]
+puts @[expr {$x - ($x1 + 1)}]
+ $T.entry icursor [$T.entry index @[expr {$x - ($x1 + 1)}]]
+ }
+ }
+ }
+ }
+ }
+ return -code break
+}
diff --git a/demos/layout.tcl b/demos/layout.tcl
new file mode 100644
index 0000000..504cd26
--- /dev/null
+++ b/demos/layout.tcl
@@ -0,0 +1,98 @@
+#
+# Demo: Layout
+#
+proc DemoLayout {} {
+
+ set T .f2.f1.t
+
+ $T configure -showroot yes -showrootbutton yes -showbuttons yes \
+ -showlines yes -itemheight 0 -selectmode browse
+
+ $T column configure 0 -text Layout
+
+ $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 "{sky blue}" -width 30 -height 16
+ $T element create e7 rect -fill "{sky blue}" -width 30 -height 16
+
+ set S [$T style create s1]
+ $T style elements $S {e4 e3 e1 e2 e5 e6 e7}
+ $T style layout $S e1 -padw 28 -pade 4 -padn 4 -pads 4
+ $T style layout $S e2 -expand es -pade 38
+ $T style layout $S e3 -union [list e1 e2] -ipadw 4 -ipade 4 -ipadn 4 -ipads 4 -padn 2 -pads 2
+ $T style layout $S e4 -detach yes -iexpand es
+ $T style layout $S e5 -detach yes -padw 2 -padn 2 -pads 2 -iexpand s
+ $T style layout $S e6 -detach yes -expand ws -pade 2 -padn 2
+ $T style layout $S e7 -detach yes -expand wn -pade 2 -pads 2
+
+ $T item style set root 0 $S
+ $T item hasbutton root yes
+
+ set item [$T item create]
+ $T item hasbutton $item no
+ $T item style set $item 0 $S
+ $T item lastchild root $item
+
+ ###
+
+ set S [$T style create s2]
+ $T style elements $S {e4 e3 e1}
+ $T style layout $S e1 -padw 8 -pade 8 -padn 8 -pads 8 -iexpand e
+ $T style layout $S e3 -union e1 -ipadw 20 -ipade 4 -ipadn 4 -ipads 12
+ $T style layout $S e4 -detach yes -iexpand es
+
+ set I [$T item create]
+ $T item hasbutton $I yes
+ $T item style set $I 0 $S
+ $T item lastchild root $I
+
+ set I2 [$T item create]
+ $T item hasbutton $I2 no
+ $T item style set $I2 0 $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} -ipadw 8 -ipadn 8 -ipade 8
+ $T style layout $S e3 -union {e1 e5} -ipadw 4 -ipadn 4 -ipade 4 -ipads 4
+ $T style layout $S e5 -ipads 20
+
+ set I [$T item create]
+ $T item hasbutton $I yes
+ $T item style set $I 0 $S
+ $T item lastchild root $I
+
+ set I2 [$T item create]
+ $T item hasbutton $I2 no
+ $T item style set $I2 0 $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
+
+ set S [$T style create s4]
+ $T style elements $S {eb et}
+ $T style layout $S eb -union et -ipadw 2 -ipadn 2 -ipade 2 -ipads 2
+ $T style layout $S et -squeeze x
+
+for {set i 0} {$i < 2} {incr i} {
+ set I [$T item create]
+ $T item hasbutton $I no
+ $T item style set $I 0 $S
+ $T item text $I 0 "Here is a text element surrounded by a border element\nResize the column to watch me wrap"
+ $T item lastchild root $I
+}
+
+ return
+}
+
diff --git a/demos/mailwasher.tcl b/demos/mailwasher.tcl
new file mode 100644
index 0000000..d97dcbb
--- /dev/null
+++ b/demos/mailwasher.tcl
@@ -0,0 +1,183 @@
+#
+# Demo: MailWasher
+#
+proc DemoMailWasher {} {
+
+ set T .f2.f1.t
+
+ InitPics *checked
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -showroot no -showrootbutton no -showbuttons no \
+ -showlines no -itemheight $height -selectmode browse \
+ -xscrollincrement 1
+
+ set pad 4
+ $T column configure 0 -text Delete -textpadw $pad -textpade $pad -tag delete
+ $T column configure 1 -text Bounce -textpadw $pad -textpade $pad -tag bounce
+ $T column configure 2 -text Status -width 80 -textpadw $pad -textpade $pad -tag status
+ $T column configure 3 -text Size -width 40 -textpadw $pad -textpade $pad -justify right -tag size
+ $T column configure 4 -text From -width 140 -textpadw $pad -textpade $pad -tag from
+ $T column configure 5 -text Subject -width 240 -textpadw $pad -textpade $pad -tag subject
+ $T column configure 6 -text Received -textpadw $pad -textpade $pad -arrow up -arrowpadw 4 -tag received
+ $T column configure 7 -text Attachments -textpadw $pad -textpade $pad -tag attachments
+
+ $T element create border rect -open nw -outline gray -outlinewidth 1 \
+ -fill [list $::SystemHighlight {selected}]
+ $T element create imgOff image -image unchecked
+ $T element create imgOn image -image checked
+ $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
+
+ foreach name {Off On} {
+ set S [$T style create sty$name]
+ $T style elements $S [list border img$name]
+ $T style layout $S border -detach yes -iexpand es
+ $T style layout $S img$name -expand wnes
+ }
+
+ 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 es
+ $T style layout $S txt$name -padw $pad -pade $pad -squeeze x -expand ns
+ }
+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 [lindex [list styOn styOff] [expr int(rand() * 2)]]
+ set bounce [lindex [list styOn styOff] [expr int(rand() * 2)]]
+ set attachments [lindex [list styNone styYes] [expr int(rand() * 2)]]
+ $T item style set $item 0 $delete 1 $bounce 2 $status 3 styAny \
+ 4 styAny 5 styAny 6 styAny 7 $attachments
+ 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 3 $size 4 $from 5 $subject 6 $received
+ $T item lastchild root $item
+ }
+}
+ if 0 {
+ $T notify bind MailWasher <Button1-ElementPress-imgOn> {
+ %T item style set %I %C styOff
+ }
+ $T notify bind MailWasher <Button1-ElementPress-imgOff> {
+ %T item style set %I %C styOn
+ }
+ }
+
+ set ::SortColumn 6
+ $T notify bind $T <Header-invoke> {
+ if {%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 -tag] {
+ bounce -
+ delete {
+ %T item sort root $order -column %C -command [list 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 MailWasher <ButtonPress-1> {
+ set id [%W identify %x %y]
+ if {$id eq ""} {
+ } elseif {[lindex $id 0] eq "header"} {
+ } else {
+ foreach {what item where arg1 arg2 arg3} $id {}
+ if {$where eq "column"} {
+ set tag [%W column cget $arg1 -tag]
+ if {$tag eq "delete" || $tag eq "bounce"} {
+ set style [%W item style set $item $arg1]
+ if {$style eq "styOn"} {
+ set style styOff
+ } else {
+ set style styOn
+ }
+ %W item style set $item $arg1 $style
+ DisplayStylesInItem $item
+# return -code break
+ }
+ }
+ }
+ }
+
+ bindtags $T [list $T MailWasher TreeCtrl [winfo toplevel $T] all]
+
+ return
+}
+
+proc CompareOnOff {T C item1 item2} {
+ set s1 [$T item style set $item1 $C]
+ set s2 [$T item style set $item2 $C]
+ if {$s1 eq $s2} { return 0 }
+ if {$s1 eq "styOff"} { return -1 }
+ return 1
+}
+
diff --git a/demos/outlook-folders.tcl b/demos/outlook-folders.tcl
new file mode 100644
index 0000000..4eac92f
--- /dev/null
+++ b/demos/outlook-folders.tcl
@@ -0,0 +1,106 @@
+#
+# Demo: Outlook Express folder list
+#
+proc DemoOutlookFolders {} {
+
+ InitPics outlook-*
+
+ set T .f2.f1.t
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -itemheight $height -selectmode browse \
+ -showroot yes -showrootbutton no -showbuttons yes -showlines yes
+
+ $T column configure 0 -text Folders
+
+ $T element create e1 image
+ $T element create e2 text -fill [list $::SystemHighlightText {selected focus}] \
+ -lines 1
+ $T element create e3 text -fill [list $::SystemHighlightText {selected focus}] \
+ -font [list "[$T cget -font] bold"] -lines 1
+ $T element create e4 text -fill blue
+ $T element create e5 image -image outlook-folder
+ $T element create e6 rect -fill [list $::SystemHighlight {selected focus} gray {selected !focus}] \
+ -showfocus yes
+
+ # image + text
+ set S [$T style create s1]
+ $T style elements $S {e6 e1 e2}
+ $T style layout $S e1 -expand ns
+ $T style layout $S e2 -padw 4 -expand ns -squeeze x
+ $T style layout $S e6 -union [list e2] -iexpand ns -ipadw 2 -ipade 2
+
+ # image + text + text
+ set S [$T style create s2]
+ $T style elements $S {e6 e1 e3 e4}
+ $T style layout $S e1 -expand ns
+ $T style layout $S e3 -padw 4 -pade 4 -expand ns -squeeze x
+ $T style layout $S e4 -expand ns
+ $T style layout $S e6 -union [list e3] -iexpand ns -ipadw 2 -ipade 2
+
+ # folder + text
+ set S [$T style create s3]
+ $T style elements $S {e6 e5 e2}
+ $T style layout $S e5 -expand ns
+ $T style layout $S e2 -padw 4 -expand ns -squeeze x
+ $T style layout $S e6 -union [list e2] -iexpand ns -ipadw 2 -ipade 2
+
+ # folder + text + text
+ set S [$T style create s4]
+ $T style elements $S {e6 e5 e3 e4}
+ $T style layout $S e5 -expand ns
+ $T style layout $S e3 -padw 4 -pade 4 -expand ns -squeeze x
+ $T style layout $S e4 -expand ns
+ $T style layout $S e6 -union [list e3] -iexpand ns -ipadw 2 -ipade 2
+
+ $T item style set root 0 s1
+ $T item complex root [list [list e1 -image outlook-main] [list e2 -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 0
+ 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]
+ $T item hasbutton $item $button
+ if {[string equal $img folder]} {
+ if {$unread} {
+ $T item style set $item 0 s4
+ $T item complex $item [list [list e3 -text $text] [list e4 -text "($unread)"]]
+ } else {
+ $T item style set $item 0 s3
+ $T item complex $item [list [list e2 -text $text]]
+ }
+ } else {
+ if {$unread} {
+ $T item style set $item 0 s2
+ $T item complex $item [list [list e1 -image outlook-$img] [list e3 -text $text] [list e4 -text "($unread)"]]
+ } else {
+ $T item style set $item 0 s1
+ $T item complex $item [list [list e1 -image outlook-$img] [list e2 -text $text]]
+ }
+ }
+ $T item lastchild [lindex $parentList $depth] $item
+ incr depth
+ set parentList [lreplace $parentList $depth $depth $item]
+ }
+
+ return
+}
+
diff --git a/demos/outlook-newgroup.tcl b/demos/outlook-newgroup.tcl
new file mode 100644
index 0000000..1a18e91
--- /dev/null
+++ b/demos/outlook-newgroup.tcl
@@ -0,0 +1,382 @@
+#
+# Demo: Outlook Express newsgroup messages
+#
+proc DemoOutlookNewsgroup {} {
+
+ global Message
+
+ InitPics outlook-*
+
+ set T .f2.f1.t
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -itemheight $height -selectmode browse \
+ -showroot no -showrootbutton no -showbuttons yes -showlines no
+
+ $T column configure 0 -image outlook-clip -tag clip
+ $T column configure 1 -image outlook-arrow -tag arrow
+ $T column configure 2 -image outlook-watch -tag watch
+ $T column configure 3 -text Subject -width 250 -tag subject
+ $T column configure 4 -text From -width 150 -tag from
+ $T column configure 5 -text Sent -width 150 -tag sent
+ $T column configure 6 -text Size -width 60 -justify right -tag size
+
+ # Would be nice if I could specify a column -tag too
+ $T configure -treecolumn 3
+
+ # State for a read message
+ $T state define read
+
+ # State for a message with unread descendants
+ $T state define unread
+
+ $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 "[$T cget -font] bold" {read unread !open} "[$T cget -font] bold" {!read}] -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
+
+ # Image + text
+ set S [$T style create s1]
+ $T style elements $S {sel.e elemImg elemTxt}
+ $T style layout $S elemImg -expand ns
+ $T style layout $S elemTxt -padw 2 -pade 6 -squeeze x -expand ns
+ $T style layout $S sel.e -union [list elemTxt] -iexpand nes -ipadw 2
+
+ # Text
+ set S [$T style create s2.we]
+ $T style elements $S {sel.we elemTxt}
+ $T style layout $S elemTxt -padw 6 -pade 6 -squeeze x -expand ns
+ $T style layout $S sel.we -detach yes -iexpand es
+
+ # Text
+ set S [$T style create s2.w]
+ $T style elements $S {sel.w elemTxt}
+ $T style layout $S elemTxt -padw 6 -pade 6 -squeeze x -expand ns
+ $T style layout $S sel.w -detach yes -iexpand es
+
+ set msgCnt 100
+
+ set thread 0
+ set Message(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 {$Message(count,$Message(thread,$j)) == 15} continue
+ break
+ }
+ $T item lastchild $j $i
+
+ set Message(read,$i) [expr rand() * 2 > 1]
+ if {$j == 0} {
+ set Message(thread,$i) [incr thread]
+ set Message(seconds,$i) [expr {[clock seconds] - int(rand() * 500000)}]
+ set Message(seconds2,$i) $Message(seconds,$i)
+ set Message(count,$thread) 1
+ } else {
+ set Message(thread,$i) $Message(thread,$j)
+ set Message(seconds,$i) [expr {$Message(seconds2,$j) + int(rand() * 10000)}]
+ set Message(seconds2,$i) $Message(seconds,$i)
+ set Message(seconds2,$j) $Message(seconds,$i)
+ incr Message(count,$Message(thread,$j))
+ }
+ }
+
+ for {set i 1} {$i < $msgCnt} {incr i} {
+ set subject "This is thread number $Message(thread,$i)"
+ set from somebody@somewhere.net
+ set sent [clock format $Message(seconds,$i) -format "%d/%m/%y %I:%M %p"]
+ set size [expr {1 + int(rand() * 10)}]KB
+
+ # This message has been read
+ if {$Message(read,$i)} {
+ $T item state $i read
+ }
+
+ # This message has unread descendants
+ if {[AnyUnreadDescendants $T $i]} {
+ $T item state $i unread
+ }
+
+ if {[$T item numchildren $i]} {
+ $T item hasbutton $i yes
+
+ # Collapse some messages
+ if {rand() * 2 > 1} {
+ $T collapse $i
+ }
+ }
+
+ $T item style set $i 3 s1 4 s2.we 5 s2.we 6 s2.w
+ $T item text $i 3 $subject 4 $from 5 $sent 6 $size
+ }
+
+ # Do something when the selection changes
+ $T notify bind $T <Selection> {
+
+ # One item is selected
+ if {[%T selection count] == 1} {
+ if {[info exists Message(afterId)]} {
+ after cancel $Message(afterId)
+ }
+ set Message(afterId,item) [lindex [%T selection get] 0]
+ set Message(afterId) [after 500 MessageReadDelayed]
+ }
+ }
+
+ return
+}
+
+proc MessageReadDelayed {} {
+
+ global Message
+
+ set T .f2.f1.t
+
+ unset Message(afterId)
+ set I $Message(afterId,item)
+ if {![$T selection includes $I]} return
+
+ # This message is not read
+ if {!$Message(read,$I)} {
+
+ # Read the message
+ $T item state $I read
+ set Message(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 $I2 !unread
+ }
+ }
+ }
+}
+
+# Alternate implementation which does not rely on run-time states
+proc DemoOutlookNewsgroup2 {} {
+
+ global Message
+
+ InitPics outlook-*
+
+ set T .f2.f1.t
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -itemheight $height -selectmode browse \
+ -showroot no -showrootbutton no -showbuttons yes -showlines no
+
+ $T column configure 0 -image outlook-clip -tag clip
+ $T column configure 1 -image outlook-arrow -tag arrow
+ $T column configure 2 -image outlook-watch -tag watch
+ $T column configure 3 -text Subject -width 250 -tag subject
+ $T column configure 4 -text From -width 150 -tag from
+ $T column configure 5 -text Sent -width 150 -tag sent
+ $T column configure 6 -text Size -width 60 -justify right -tag size
+
+ $T configure -treecolumn 3
+
+ $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 "[$T cget -font] bold"] -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
+
+ # 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 -padw 2 -pade 6 -squeeze x -expand ns
+ $T style layout $S sel.e -union [list text.unread] -iexpand nes -ipadw 2
+
+ # 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 -padw 2 -pade 6 -squeeze x -expand ns
+ $T style layout $S sel.e -union [list text.read] -iexpand nes -ipadw 2
+
+ # 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 -padw 2 -pade 6 -squeeze x -expand ns
+ $T style layout $S sel.e -union [list text.unread] -iexpand nes -ipadw 2
+
+ # Text
+ set S [$T style create unread.we]
+ $T style elements $S {sel.we text.unread}
+ $T style layout $S text.unread -padw 6 -pade 6 -squeeze x -expand ns
+ $T style layout $S sel.we -detach yes -iexpand es
+
+ # Text
+ set S [$T style create read.we]
+ $T style elements $S {sel.we text.read}
+ $T style layout $S text.read -padw 6 -pade 6 -squeeze x -expand ns
+ $T style layout $S sel.we -detach yes -iexpand es
+
+ # Text
+ set S [$T style create unread.w]
+ $T style elements $S {sel.w text.unread}
+ $T style layout $S text.unread -padw 6 -pade 6 -squeeze x -expand ns
+ $T style layout $S sel.w -detach yes -iexpand es
+
+ # Text
+ set S [$T style create read.w]
+ $T style elements $S {sel.w text.read}
+ $T style layout $S text.read -padw 6 -pade 6 -squeeze x -expand ns
+ $T style layout $S sel.w -detach yes -iexpand es
+
+ set msgCnt 100
+
+ set thread 0
+ set Message(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 {$Message(count,$Message(thread,$j)) == 15} continue
+ break
+ }
+ $T item lastchild $j $i
+
+ set Message(read,$i) [expr rand() * 2 > 1]
+ if {$j == 0} {
+ set Message(thread,$i) [incr thread]
+ set Message(seconds,$i) [expr {[clock seconds] - int(rand() * 500000)}]
+ set Message(seconds2,$i) $Message(seconds,$i)
+ set Message(count,$thread) 1
+ } else {
+ set Message(thread,$i) $Message(thread,$j)
+ set Message(seconds,$i) [expr {$Message(seconds2,$j) + int(rand() * 10000)}]
+ set Message(seconds2,$i) $Message(seconds,$i)
+ set Message(seconds2,$j) $Message(seconds,$i)
+ incr Message(count,$Message(thread,$j))
+ }
+ }
+
+ for {set i 1} {$i < $msgCnt} {incr i} {
+ set subject "This is thread number $Message(thread,$i)"
+ set from somebody@somewhere.net
+ set sent [clock format $Message(seconds,$i) -format "%d/%m/%y %I:%M %p"]
+ set size [expr {1 + int(rand() * 10)}]KB
+ if {$Message(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 hasbutton $i yes
+ }
+ }
+
+ $T notify bind $T <Selection> {
+ if {[%T selection count] == 1} {
+ set I [lindex [%T selection get] 0]
+ if {!$Message(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 Message(read,$I) 1
+ DisplayStylesInItem $I
+ }
+ }
+ }
+
+ $T notify bind $T <Expand-after> {
+ if {$Message(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 <Collapse-after> {
+ if {$Message(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 collapse $i
+ }
+ }
+ }
+
+ return
+}
+proc AnyUnreadDescendants {T I} {
+
+ global Message
+
+ set itemList [$T item firstchild $I]
+ while {[llength $itemList]} {
+ # Pop
+ set item [lindex $itemList end]
+ set itemList [lrange $itemList 0 end-1]
+
+ if {!$Message(read,$item)} {
+ return 1
+ }
+
+ set item2 [$T item nextsibling $item]
+ if {$item2 ne ""} {
+ # Push
+ lappend itemList $item2
+ }
+ set item2 [$T item firstchild $item]
+ if {$item2 ne ""} {
+ # Push
+ lappend itemList $item2
+ }
+ }
+
+ return 0
+}
diff --git a/demos/random.tcl b/demos/random.tcl
new file mode 100644
index 0000000..be9e9ba
--- /dev/null
+++ b/demos/random.tcl
@@ -0,0 +1,475 @@
+set RandomN 500
+
+#
+# Demo: random N items
+#
+proc DemoRandom {} {
+
+ set T .f2.f1.t
+
+ InitPics folder-* small-*
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -itemheight $height -selectmode extended \
+ -showroot yes -showrootbutton yes -showbuttons yes -showlines yes \
+ -scrollmargin 16 -xscrolldelay "500 50" -yscrolldelay "500 50"
+
+ $T column configure 0 -expand yes -text Item -itembackground {#e0e8f0 {}}
+ $T column configure 1 -text Parent -justify center -itembackground {gray90 {}}
+ $T column configure 2 -text Depth -justify center -itembackground {linen {}}
+
+ $T element create e1 image -image {folder-open {open} folder-closed {}}
+ $T element create e2 image -image small-file
+ $T element create e3 text \
+ -fill [list $::SystemHighlightText {selected focus}]
+ $T element create e4 text -fill blue
+ $T element create e6 text
+ $T element create e5 rect -showfocus yes \
+ -fill [list $::SystemHighlight {selected focus} gray {selected !focus}]
+
+ $T style create s1
+ $T style elements s1 {e5 e1 e3 e4}
+ $T style layout s1 e1 -pade 4 -expand ns
+ $T style layout s1 e3 -pade 4 -expand ns
+ $T style layout s1 e4 -pade 6 -expand ns
+ $T style layout s1 e5 -union [list e3] -iexpand ns -ipadw 2 -ipade 2
+
+ $T style create s2
+ $T style elements s2 {e5 e2 e3}
+ $T style layout s2 e2 -pade 4 -expand ns
+ $T style layout s2 e3 -pade 6 -expand ns
+ $T style layout s2 e5 -union [list e3] -iexpand ns -ipadw 2 -ipade 2
+
+ $T style create s3
+ $T style elements s3 {e6}
+ $T style layout s3 e6 -padw 6 -pade 6 -expand ns
+
+ set ::TreeCtrl::Priv(sensitive,$T) {e5 e1 e2 e3}
+ set ::TreeCtrl::Priv(dragimage,$T) {
+ {0 s1 e1 e3}
+ {0 s2 e2 e3}
+ }
+
+ set clicks [clock clicks]
+ for {set i 1} {$i < $::RandomN} {incr i} {
+ $T item create
+ while 1 {
+ set j [expr {int(rand() * $i)}]
+ if {[$T depth $j] < 5} break
+ }
+ if {rand() * 2 > 1} {
+ $T collapse $i
+ }
+ if {rand() * 2 > 1} {
+ $T item lastchild $j $i
+ } else {
+ $T item firstchild $j $i
+ }
+ }
+ puts "created $::RandomN-1 items in [expr [clock clicks] - $clicks] clicks"
+ set clicks [clock clicks]
+ for {set i 0} {$i < $::RandomN} {incr i} {
+ set numChildren [$T item numchildren $i]
+ if {$numChildren} {
+ $T item hasbutton $i yes
+ $T item style set $i 0 s1 1 s3 2 s3
+ $T item complex $i \
+ [list [list e3 -text "Item $i"] [list e4 -text "($numChildren)"]] \
+ [list [list e6 -text "[$T item parent $i]"]] \
+ [list [list e6 -text "[$T depth $i]"]]
+ } else {
+ $T item style set $i 1 s3 2 s3 0 s2
+ $T item complex $i \
+ [list [list e3 -text "Item $i"]] \
+ [list [list e6 -text "[$T item parent $i]"]] \
+ [list [list e6 -text "[$T depth $i]"]]
+ }
+ }
+ puts "configured $::RandomN items in [expr [clock clicks] - $clicks] clicks"
+
+ bind TreeCtrlRandom <Double-ButtonPress-1> {
+ TreeCtrl::DoubleButton1 %W %x %y
+ }
+ bind TreeCtrlRandom <Control-ButtonPress-1> {
+ set TreeCtrl::Priv(selectMode) toggle
+ TreeCtrl::RandomButton1 %W %x %y
+ break
+ }
+ bind TreeCtrlRandom <Shift-ButtonPress-1> {
+ set TreeCtrl::Priv(selectMode) add
+ TreeCtrl::RandomButton1 %W %x %y
+ break
+ }
+ bind TreeCtrlRandom <ButtonPress-1> {
+ set TreeCtrl::Priv(selectMode) set
+ TreeCtrl::RandomButton1 %W %x %y
+ break
+ }
+ bind TreeCtrlRandom <Button1-Motion> {
+ TreeCtrl::RandomMotion1 %W %x %y
+ break
+ }
+ bind TreeCtrlRandom <Button1-Leave> {
+ TreeCtrl::RandomLeave1 %W %x %y
+ break
+ }
+ bind TreeCtrlRandom <ButtonRelease-1> {
+ TreeCtrl::RandomRelease1 %W %x %y
+ break
+ }
+
+ bindtags $T [list $T TreeCtrlRandom TreeCtrl [winfo toplevel $T] all]
+
+ return
+}
+
+proc TreeCtrl::RandomButton1 {T x y} {
+ variable Priv
+ focus $T
+ set id [$T identify $x $y]
+ puts $id
+ set Priv(buttonMode) ""
+
+ # Click outside any item
+ if {$id eq ""} {
+ $T selection clear
+
+ # Click in header
+ } elseif {[lindex $id 0] eq "header"} {
+ ButtonPress1 $T $x $y
+
+ # Click in item
+ } else {
+ foreach {where item arg1 arg2 arg3 arg4} $id {}
+ switch $arg1 {
+ button {
+ $T toggle $item
+ }
+ line {
+ $T toggle $arg2
+ }
+ column {
+ set ok 0
+ # Clicked an element
+ if {[llength $id] == 6} {
+ set E [lindex $id 5]
+ if {[lsearch -exact $Priv(sensitive,$T) $E] != -1} {
+ set ok 1
+ }
+ }
+ if {!$ok} {
+ $T selection clear
+ return
+ }
+
+ set Priv(drag,motion) 0
+ set Priv(drag,x) [$T canvasx $x]
+ set Priv(drag,y) [$T canvasy $y]
+ set Priv(drop) ""
+
+ if {$Priv(selectMode) eq "add"} {
+ BeginExtend $T $item
+ } elseif {$Priv(selectMode) eq "toggle"} {
+ BeginToggle $T $item
+ } elseif {![$T selection includes $item]} {
+ BeginSelect $T $item
+ }
+ $T activate $item
+
+ if {[$T selection includes $item]} {
+ set Priv(buttonMode) drag
+ }
+ }
+ }
+ }
+ return
+}
+proc TreeCtrl::RandomMotion1 {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Motion1 $T $x $y
+ }
+ "drag" {
+ RandomAutoScanCheck $T $x $y
+ RandomMotion $T $x $y
+ }
+ }
+ return
+}
+proc TreeCtrl::RandomMotion {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Motion1 $T $x $y
+ }
+ "drag" {
+ # Detect initial mouse movement
+ if {!$Priv(drag,motion)} {
+ set Priv(selection) [$T selection get]
+ set Priv(drop) ""
+ $T dragimage clear
+ # For each selected item, add 2nd and 3rd elements of
+ # column zero 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]
+ set ok 0
+ if {($id ne "") && ([lindex $id 0] eq "item") && ([llength $id] == 6)} {
+ set E [lindex $id 5]
+ if {[lsearch -exact $Priv(sensitive,$T) $E] != -1} {
+ set ok 1
+ }
+ }
+ if {$ok} {
+ set item [lindex $id 1]
+ set column [lindex $id 3]
+ if {$column == 0} {
+ # 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 visible yes
+ }
+ }
+ return
+}
+proc TreeCtrl::RandomLeave1 {T x y} {
+ variable Priv
+ # This is called when I do ButtonPress-1 on Unix for some reason,
+ # and buttonMode is undefined.
+ if {![info exists Priv(buttonMode)]} return
+ switch $Priv(buttonMode) {
+ "header" {
+ Leave1 $T $x $y
+ }
+ }
+ return
+}
+proc TreeCtrl::RandomRelease1 {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Release1 $T $x $y
+ }
+ "drag" {
+ AutoScanCancel $T
+ $T dragimage visible no
+ $T selection modify {} $Priv(drop)
+ $T configure -cursor ""
+ if {$Priv(drop) ne ""} {
+ RandomDrop $T $Priv(drop) $Priv(selection) $Priv(drop,pos)
+ }
+ }
+ }
+ set Priv(buttonMode) ""
+ return
+}
+
+proc RandomDrop {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 1 e6 -text $parent
+
+ # Update text: depth
+ $T item element configure $item 2 e6 -text [$T depth $item]
+
+ # Recursively update text: depth
+ set itemList [$T item firstchild $item]
+ while {[llength $itemList]} {
+ # Pop
+ set item [lindex $itemList end]
+ set itemList [lrange $itemList 0 end-1]
+
+ $T item element configure $item 2 e6 -text [$T depth $item]
+
+ set item2 [$T item nextsibling $item]
+ if {$item2 ne ""} {
+ # Push
+ lappend itemList $item2
+ }
+ set item2 [$T item firstchild $item]
+ if {$item2 ne ""} {
+ # Push
+ lappend itemList $item2
+ }
+ }
+ }
+
+ # Update items that lost some children
+ foreach item $parentList {
+ set numChildren [$T item numchildren $item]
+ if {$numChildren == 0} {
+ $T item hasbutton $item no
+ $T item style map $item 0 s2 {e3 e3}
+ } else {
+ $T item element configure $item 0 e4 -text "($numChildren)"
+ }
+ }
+
+ # Update the target that gained some children
+ if {[$T item style set $parent 0] ne "s1"} {
+ $T item hasbutton $parent yes
+ $T item style map $parent 0 s1 {e3 e3}
+ }
+ set numChildren [$T item numchildren $parent]
+ $T item element configure $parent 0 e4 -text "($numChildren)"
+ return
+}
+
+# Same as TreeCtrl::AutoScanCheck, but calls RandomMotion and
+# RandomAutoScanCheckAux
+proc TreeCtrl::RandomAutoScanCheck {T x y} {
+ variable Priv
+ scan [$T contentbox] "%d %d %d %d" x1 y1 x2 y2
+ set margin [winfo pixels $T [$T cget -scrollmargin]]
+ if {($x < $x1 + $margin) || ($x >= $x2 - $margin) ||
+ ($y < $y1 + $margin) || ($y >= $y2 - $margin)} {
+ if {![info exists Priv(autoscan,afterId,$T)]} {
+ if {$y >= $y2 - $margin} {
+ $T yview scroll 1 units
+ set delay [$T cget -yscrolldelay]
+ } elseif {$y < $y1 + $margin} {
+ $T yview scroll -1 units
+ set delay [$T cget -yscrolldelay]
+ } elseif {$x >= $x2 - $margin} {
+ $T xview scroll 1 units
+ set delay [$T cget -xscrolldelay]
+ } elseif {$x < $x1 + $margin} {
+ $T xview scroll -1 units
+ set delay [$T cget -xscrolldelay]
+ }
+ set count [scan $delay "%d %d" d1 d2]
+ if {[info exists Priv(autoscan,scanning,$T)]} {
+ if {$count == 2} {
+ set delay $d2
+ }
+ } else {
+ if {$count == 2} {
+ set delay $d1
+ }
+ set Priv(autoscan,scanning,$T) 1
+ }
+ switch $Priv(buttonMode) {
+ "drag" -
+ "marquee" {
+ RandomMotion $T $x $y
+ }
+ }
+ set Priv(autoscan,afterId,$T) [after $delay [list TreeCtrl::RandomAutoScanCheckAux $T]]
+ }
+ return
+ }
+ AutoScanCancel $T
+ return
+}
+
+proc ::TreeCtrl::RandomAutoScanCheckAux {T} {
+ variable Priv
+ unset Priv(autoscan,afterId,$T)
+ set x [winfo pointerx $T]
+ set y [winfo pointery $T]
+ set x [expr {$x - [winfo rootx $T]}]
+ set y [expr {$y - [winfo rooty $T]}]
+ RandomAutoScanCheck $T $x $y
+ return
+}
+
+#
+# Demo: random N items, button images
+#
+proc DemoRandom2 {} {
+
+ set T .f2.f1.t
+
+ DemoRandom
+
+ InitPics mac-*
+
+ $T configure -openbuttonimage mac-collapse -closedbuttonimage mac-expand \
+ -showlines no
+
+ return
+}
+
diff --git a/demos/www-options.tcl b/demos/www-options.tcl
new file mode 100644
index 0000000..d141f65
--- /dev/null
+++ b/demos/www-options.tcl
@@ -0,0 +1,299 @@
+proc DemoInternetOptions {} {
+
+ set T .f2.f1.t
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -showroot no -showbuttons no -showlines no -itemheight $height \
+ -selectmode browse
+
+ InitPics internet-*
+
+ $T column configure 0 -text "Internet Options"
+
+ $T state define check
+ $T state define radio
+ $T state define on
+
+ $T element create e1 image -image {
+ internet-check-on {check on}
+ internet-check-off {check}
+ internet-radio-on {radio on}
+ internet-radio-off {radio}
+ }
+ $T element create e2 text -fill [list $::SystemHighlightText {selected focus}]
+ $T element create e3 rect -fill [list $::SystemHighlight {selected focus}] -showfocus yes
+
+ set S [$T style create s1]
+ $T style elements $S {e3 e1 e2}
+ $T style layout $S e1 -pade 4 -expand ns
+ $T style layout $S e2 -expand ns
+ $T style layout $S e3 -union [list e2] -iexpand ns -ipadw 2 -ipade 2
+
+ 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 s1
+ $T item element configure $item 0 e2 -text $text
+ set ::Option(option,$item) $option
+ set ::Option(group,$item) $group
+ if {($setting eq "on") || ($setting eq "off")} {
+ set ::Option(setting,$item) $setting
+ if {$group eq ""} {
+ $T item state $item check
+ if {$setting eq "on"} {
+ $T item state $item on
+ }
+ } else {
+ if {$setting eq "on"} {
+ set ::Option(current,$group) $item
+ $T item state $item on
+ }
+ $T item state $item radio
+ }
+ } else {
+ $T item element configure $item 0 e1 -image internet-$setting
+ }
+ $T item lastchild [lindex $parentList $depth] $item
+ incr depth
+ set parentList [lreplace $parentList $depth $depth $item]
+ }
+
+ bind TreeCtrlOption <Double-ButtonPress-1> {
+ TreeCtrl::DoubleButton1 %W %x %y
+ }
+ bind TreeCtrlOption <ButtonPress-1> {
+ TreeCtrl::OptionButton1 %W %x %y
+ break
+ }
+ bind TreeCtrlOption <Button1-Motion> {
+ TreeCtrl::OptionMotion1 %W %x %y
+ break
+ }
+ bind TreeCtrlOption <Button1-Leave> {
+ TreeCtrl::OptionLeave1 %W %x %y
+ break
+ }
+ bind TreeCtrlOption <ButtonRelease-1> {
+ TreeCtrl::OptionRelease1 %W %x %y
+ break
+ }
+
+ bindtags $T [list $T TreeCtrlOption TreeCtrl [winfo toplevel $T] all]
+
+ return
+}
+proc TreeCtrl::OptionButton1 {T x y} {
+ variable Priv
+ focus $T
+ set id [$T identify $x $y]
+ if {[lindex $id 0] eq "header"} {
+ ButtonPress1 $T $x $y
+ } elseif {$id eq ""} {
+ set Priv(buttonMode) ""
+ } else {
+ set Priv(buttonMode) ""
+ set item [lindex $id 1]
+ $T selection modify $item all
+ $T activate $item
+ if {$::Option(option,$item) eq ""} return
+ set group $::Option(group,$item)
+ # a checkbutton
+ if {$group eq ""} {
+ if {$::Option(setting,$item) eq "on"} {
+ set setting off
+ $T item state $item !on
+ } else {
+ set setting on
+ $T item state $item on
+ }
+ set ::Option(setting,$item) $setting
+ # a radiobutton
+ } else {
+ set current $::Option(current,$group)
+ if {$current eq $item} return
+ $T item state $current !on
+ $T item state $item on
+ set ::Option(setting,$item) on
+ set ::Option(current,$group) $item
+ }
+ }
+ return
+}
+
+
+# Alternate implementation that doesn't rely on run-time styles
+proc DemoInternetOptions_2 {} {
+
+ set T .f2.f1.t
+
+ set height [font metrics [$T cget -font] -linespace]
+ if {$height < 18} {
+ set height 18
+ }
+ $T configure -showroot no -showbuttons no -showlines no -itemheight $height \
+ -selectmode browse
+
+ InitPics internet-*
+
+ $T column configure 0 -text "Internet Options"
+
+ $T element create e1 image
+ $T element create e2 text -fill [list $::SystemHighlightText {selected focus}]
+ $T element create e3 rect -fill [list $::SystemHighlight {selected focus}] -showfocus yes
+
+ set S [$T style create s1]
+ $T style elements $S {e3 e1 e2}
+ $T style layout $S e1 -pade 4 -expand ns
+ $T style layout $S e2 -expand ns
+ $T style layout $S e3 -union [list e2] -iexpand ns -ipadw 2 -ipade 2
+
+ 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 s1
+ $T item element configure $item 0 e2 -text $text
+ set ::Option(option,$item) $option
+ set ::Option(group,$item) $group
+ if {$setting eq "on" || $setting eq "off"} {
+ set ::Option(setting,$item) $setting
+ if {$group eq ""} {
+ set img internet-check-$setting
+ $T item element configure $item 0 e1 -image $img
+ } else {
+ if {$setting eq "on"} {
+ set ::Option(current,$group) $item
+ }
+ set img internet-radio-$setting
+ $T item element configure $item 0 e1 -image $img
+ }
+ } else {
+ $T item element configure $item 0 e1 -image internet-$setting
+ }
+ $T item lastchild [lindex $parentList $depth] $item
+ incr depth
+ set parentList [lreplace $parentList $depth $depth $item]
+ }
+
+ bind TreeCtrlOption <Double-ButtonPress-1> {
+ TreeCtrl::DoubleButton1 %W %x %y
+ }
+ bind TreeCtrlOption <ButtonPress-1> {
+ TreeCtrl::OptionButton1 %W %x %y
+ break
+ }
+ bind TreeCtrlOption <Button1-Motion> {
+ TreeCtrl::OptionMotion1 %W %x %y
+ break
+ }
+ bind TreeCtrlOption <Button1-Leave> {
+ TreeCtrl::OptionLeave1 %W %x %y
+ break
+ }
+ bind TreeCtrlOption <ButtonRelease-1> {
+ TreeCtrl::OptionRelease1 %W %x %y
+ break
+ }
+
+ bindtags $T [list $T TreeCtrlOption TreeCtrl [winfo toplevel $T] all]
+
+ return
+}
+proc TreeCtrl::OptionButton1_2 {T x y} {
+ variable Priv
+ focus $T
+ set id [$T identify $x $y]
+ if {[lindex $id 0] eq "header"} {
+ ButtonPress1 $T $x $y
+ } elseif {$id eq ""} {
+ set Priv(buttonMode) ""
+ } else {
+ set Priv(buttonMode) ""
+ set item [lindex $id 1]
+ $T selection modify $item all
+ $T activate $item
+ if {$::Option(option,$item) eq ""} return
+ set group $::Option(group,$item)
+ # a checkbutton
+ if {$group eq ""} {
+ if {$::Option(setting,$item) eq "on"} {
+ set setting off
+ } else {
+ set setting on
+ }
+ $T item element configure $item 0 e1 -image internet-check-$setting
+ set ::Option(setting,$item) $setting
+ # a radiobutton
+ } else {
+ set current $::Option(current,$group)
+ if {$current eq $item} return
+ $T item element configure $current 0 e1 -image internet-radio-off
+ $T item element configure $item 0 e1 -image internet-radio-on
+ set ::Option(setting,$item) on
+ set ::Option(current,$group) $item
+ }
+ }
+ return
+}
+proc TreeCtrl::OptionMotion1 {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Motion1 $T $x $y
+ }
+ }
+ return
+}
+proc TreeCtrl::OptionLeave1 {T x y} {
+ variable Priv
+ # This is called when I do ButtonPress-1 on Unix for some reason,
+ # and buttonMode is undefined.
+ if {![info exists Priv(buttonMode)]} return
+ switch $Priv(buttonMode) {
+ "header" {
+ $T column configure $Priv(column) -sunken no
+ }
+ }
+ return
+}
+proc TreeCtrl::OptionRelease1 {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Release1 $T $x $y
+ }
+ }
+ set Priv(buttonMode) ""
+ return
+}
+
diff --git a/doc/manual.txt b/doc/manual.txt
new file mode 100644
index 0000000..1c546cc
--- /dev/null
+++ b/doc/manual.txt
@@ -0,0 +1,415 @@
+C -- column
+E -- element
+I -- item
+S -- style
+T -- treectrl
+
+==========
+
+T activate I
+
+T canvasx $x
+
+T canvasy $y
+
+T cget $option
+
+T collapse I ...
+
+T column XXX
+ T column bbox C
+
+ T column cget C $option
+
+ T column configure C
+ T column configure C $option
+ T column configure C $option $value ...
+ -arrow
+ -arrowside
+ -arrowgravity
+ -arrowpadw
+ -arrowpade
+ -bitmap
+ -border
+ -borderwidth
+ -button
+ -expand
+ -font
+ -image
+ -imagepade
+ -imagepadw
+ -itembackground
+ -justify
+ -minwidth
+ -relief
+ -stepwidth
+ -sunken
+ -tag
+ -text
+ -textcolor
+ -textpade
+ -textpadw
+ -width
+ -visible
+ -widthhack
+
+ T column delete C
+
+ T column width C
+
+T compare I $op I
+ $op "<", "<=", "==", ">=", ">", "!="
+
+T configure
+T configure $option
+T configure $option $value ...
+ -background
+ -backgroundmode
+ -borderwidth
+ -buttoncolor
+ -buttonsize
+ -buttonthickness
+ -closedbuttonbitmap
+ -closedbuttonimage
+ -columnproxy
+ -cursor
+ -doublebuffer
+ -font
+ -foreground
+ -height
+ -highlightbackground
+ -highlightcolor
+ -highlightthickness
+ -indent
+ -itemheight
+ -linecolor
+ -linestyle
+ -linethickness
+ -openbuttonbitmap
+ -openbuttonimage
+ -orient
+ -relief
+ -scrollmargin
+ -selectmode
+ -showbuttons
+ -showheader
+ -showlines
+ -showroot
+ -showrootbutton
+ -takefocus
+ -treecolumn
+ -width
+ -wrap
+ -xscrollcommand
+ -xscrolldelay
+ -xscrollincrement
+ -yscrollcommand
+ -yscrolldelay
+ -yscrollincrement
+
+T contentbox
+
+T debug XXX
+ T debug cget $option
+
+ T debug configure
+ T debug configure $option
+ T debug configure $option $value ...
+ -displaydelay
+ -data
+ -display
+ -enable
+ -erasecolor
+
+ T debug dinfo
+
+ T debug scroll
+
+T depth
+T depth I
+
+T dragimage XXX
+ T dragimage add I
+ T dragimage add I C
+ T dragimage add I C E ...
+
+ T dragimage cget $option
+
+ T dragimage clear
+
+ T dragimage configure
+ T dragimage configure $option
+ T dragimage configure $option $value ...
+
+ T dragimage offset
+ T dragimage offset $x $y
+
+ T dragimage visible
+ T dragimage visible $boolean
+
+T element XXX
+ T element cget E $option
+
+ T element configure E
+ T element configure E $option
+ T element configure E $option $value ...
+
+ --- bitmap ---
+ -background
+ -bitmap
+ -foreground
+
+ --- border ---
+ -background
+ -filled
+ -height
+ -relief
+ -thickness
+ -width
+
+ --- image ---
+ -height
+ -image
+ -width
+
+ --- rect ---
+ -fill
+ -height
+ -open
+ -outline
+ -outlinewidth
+ -showfocus
+ -width
+
+ --- text ---
+ -data
+ -datatype
+ -format
+ -fill
+ -font
+ -justify
+ -lines
+ -text
+ -width
+ -wrap
+
+ T element create $name $type $option $value ...
+
+ T element delete E ...
+
+ T element names
+
+ T element type E
+
+T expand I ...
+
+T identify $x $y
+
+T index I
+
+T item XXX
+ T item ancestors I
+
+ T item bbox I
+
+ T item children I
+
+ T item complex I {{E $option $value ...} ...} {{E $option $value ...} ...}
+
+ T item create
+
+ T item delete I
+ T item delete I I
+
+ T item dump I
+
+ T item element XXX
+ T item element actual I C E $option
+
+ T item element cget I C E $option
+
+ T item element configure I C E
+ T item element configure I C E $option
+ T item element configure I C E $option $value ...
+
+ T item hasbutton I
+ T item hasbutton I $boolean
+
+ T item firstchild I
+ T item firstchild I I
+
+ T item lastchild I
+ T item lastchild I I
+
+ T item nextsibling I
+ T item nextsibling I I
+
+ T item numchildren I
+
+ T item index I
+
+ T item isancestor I I
+
+ T item parent I
+
+ T item prevsibling I
+ T item prevsibling I I
+
+ T item remove I
+
+ T item rnc I
+
+ T item sort I $option $value ...
+
+ T item state I
+ T item state I $state ...
+
+ T item style XXX
+ T item style elements I C
+
+ T item style map I C S {E E ...}
+
+ T item style set I
+ T item style set I C
+ T item style set I C S ...
+
+ T item text I C
+ T item text I C $text
+
+T marquee XXX
+ T marquee anchor
+ T marquee anchor $x $y
+
+ T marquee cget $option
+
+ T marquee configure
+ T marquee configure $option
+ T marquee configure $option $value ...
+
+ T marquee coords
+ T marquee coords $x $y $x $y
+
+ T marquee corner
+ T marquee corner $x $y
+
+ T marquee identify
+
+ T marquee visible
+ T marquee visible $boolean
+
+T notify XXX
+ T notify bind
+ T notify bind $object
+ T notify bind $object $pattern
+ T notify bind $object $pattern $script
+
+ T notify configure $object $pattern $option $value ...
+ -active
+
+ T notify detailnames $eventName
+
+ T notify eventnames
+
+ T notify generate $pattern -$char $value ...
+
+ T notify install event $eventName
+
+ T notify install detail $eventName $detailName
+ T notify install detail $eventName $detailName $percentsCmd
+
+ T notify linkage $eventName
+ T notify linkage $eventName $detailName
+
+ T notify uninstall event $eventName
+
+ T notify uninstall detail $eventName $detailName
+
+T numcolumns
+
+T numitems
+
+T orphans
+
+T range I I
+
+T see I
+
+T selection XXX
+ T selection add I
+ T selection add I I
+
+ T selection anchor
+ T selection anchor I
+
+ T selection clear
+ T selection clear I
+ T selection clear I I
+
+ T selection count
+
+ T selection get
+
+ T selection includes I
+
+ T selection modify $select $deselect
+
+T state XXX
+ T state define $stateName
+
+ T state undefine $stateName
+
+ T state names
+
+T style XXX
+ T style cget S $option
+
+ T style configure S
+ T style configure S $option
+ T style configure S $option $value ...
+ -orient
+
+ T style create $name $option $value ...
+
+ T style delete S ...
+
+ T style elements S
+ T style elements S {E ...}
+
+ T style layout S E
+ T style layout S E $option $value ...
+ -padw
+ -padn
+ -pade
+ -pads
+ -ipadw
+ -ipadn
+ -ipade
+ -ipads
+ -expand
+ -iexpand
+ -detach
+ -squeeze
+ -union
+
+ T style names
+
+T toggle I ...
+
+T xview XXX
+ T xview
+
+ T xview moveto $fraction
+
+ T xview scroll $number pages
+
+ T xview scroll $number units
+
+T yview XXX
+ T yview
+
+ T yview moveto $fraction
+
+ T yview scroll $number pages
+
+ T yview scroll $number units
+
diff --git a/generic/qebind.c b/generic/qebind.c
new file mode 100644
index 0000000..dbfba8c
--- /dev/null
+++ b/generic/qebind.c
@@ -0,0 +1,1992 @@
+/* File: qebind.c */
+
+/* Purpose: implements quasi-events */
+
+/*
+ * 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 are not automatically
+ * deleted when a widget is destroyed.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <tcl.h>
+#include <tk.h>
+#include "qebind.h"
+#include "dbwin.h"
+
+int debug_bindings = 0;
+
+/*
+ * Allow bindings to be deactivated.
+ */
+#define BIND_ACTIVE 1
+
+#define ALLOW_INSTALL 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;
+ 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() */
+#endif
+ struct EventInfo *next; /* List of all EventInfos */
+} EventInfo;
+
+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 */
+ 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);
+#if ALLOW_INSTALL
+static void Percents_Install(QE_ExpandArgs *args);
+#endif
+static int DeleteBinding(BindingTable *bindPtr, BindValue *valuePtr);
+static EventInfo *FindEvent(BindingTable *bindPtr, int eventType);
+
+static int initialized = 0;
+
+int QE_BindInit(Tcl_Interp *interp)
+{
+ if (initialized)
+ return TCL_OK;
+
+ initialized = 1;
+
+ return TCL_OK;
+}
+
+int QE_InstallEvent(QE_BindingTable bindingTable, char *name, QE_ExpandProc expandProc)
+{
+ BindingTable *bindPtr = (BindingTable *) bindingTable;
+ Tcl_HashEntry *hPtr;
+ EventInfo *eiPtr;
+ int isNew;
+ int type;
+
+ 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(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;
+#endif
+
+ Tcl_SetHashValue(hPtr, (ClientData) eiPtr);
+
+ hPtr = Tcl_CreateHashEntry(&bindPtr->eventTableByType, (char *) 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;
+
+ /* 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);
+ 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 *) 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 *) 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);
+}
+
+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));
+ 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);
+ memset((char *) eiPtr, 0xAA, sizeof(EventInfo));
+ Tcl_Free((char *) eiPtr);
+ }
+
+ Tcl_DeleteHashTable(&bindPtr->eventTableByName);
+ Tcl_DeleteHashTable(&bindPtr->eventTableByType);
+ Tcl_DeleteHashTable(&bindPtr->detailTableByType);
+
+ 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;
+
+ 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 = 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;
+
+ 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;
+ }
+ }
+
+ 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));
+ }
+ 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, string - command);
+ command = string;
+ }
+ if (*command == 0)
+ {
+ break;
+ }
+
+ /* Expand % here */
+ expandArgs.which = command[1];
+ (*expandProc)(&expandArgs);
+
+ command += 2;
+ }
+}
+
+#if 1
+
+static void BindEvent(BindingTable *bindPtr, QE_Event *eventPtr, int wantDetail,
+ EventInfo *eiPtr, Detail *dPtr)
+{
+ Tcl_HashEntry *hPtr;
+ BindValue *valuePtr;
+ ObjectTableKey keyObj;
+ PatternTableKey key;
+ Tcl_DString scripts, savedResult;
+ int code;
+ char *p, *end;
+
+ /* 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, 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
+ /*
+ * Call a Tcl script to expand the percents.
+ */
+ if (dPtr && (dPtr->command != NULL))
+ {
+ ClientData oldClientData = eventPtr->clientData;
+
+ eventPtr->clientData = (ClientData) dPtr;
+ ExpandPercents(bindPtr, valuePtr->object, valuePtr->command,
+ eventPtr, Percents_Install, &scripts);
+ eventPtr->clientData = oldClientData;
+ }
+ else
+#endif /* ALLOW_INSTALL */
+ {
+ 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);
+ }
+
+ /* 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 0
+ if (code == TCL_CONTINUE)
+ {
+ /* Nothing */
+ }
+ else if (code == TCL_BREAK)
+ {
+ break;
+ }
+ else
+#endif
+ {
+ Tcl_AddErrorInfo(bindPtr->interp,
+ "\n (command bound to quasi-event)");
+ Tcl_BackgroundError(bindPtr->interp);
+ break;
+ }
+ }
+ }
+
+ Tcl_DStringFree(&scripts);
+
+ /* Restore the interpreter result */
+ Tcl_DStringResult(bindPtr->interp, &savedResult);
+}
+
+#else /* not 1 */
+
+static void BindEvent(BindingTable *bindPtr, QE_Event *eventPtr, int wantDetail,
+ EventInfo *eiPtr, Detail *dPtr)
+{
+ Tcl_HashEntry *hPtr;
+ BindValue *valuePtr;
+ ObjectTableKey keyObj;
+ PatternTableKey key;
+ Tcl_DString command, savedResult;
+ int code;
+
+ /* 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;
+
+ Tcl_DStringInit(&command);
+
+ /*
+ * 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);
+
+ 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, 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
+ /*
+ * Call a Tcl script to expand the percents.
+ */
+ if (dPtr && (dPtr->command != NULL))
+ {
+ ClientData oldClientData = eventPtr->clientData;
+
+ eventPtr->clientData = (ClientData) dPtr;
+ ExpandPercents(bindPtr, valuePtr->object, valuePtr->command,
+ eventPtr, Percents_Install, &command);
+ eventPtr->clientData = oldClientData;
+ }
+ else
+#endif /* ALLOW_INSTALL */
+ {
+ QE_ExpandProc expandProc =
+ ((dPtr != NULL) && (dPtr->expandProc != NULL)) ?
+ dPtr->expandProc : eiPtr->expandProc;
+
+ ExpandPercents(bindPtr, valuePtr->object, valuePtr->command,
+ eventPtr, expandProc, &command);
+ }
+ code = Tcl_EvalEx(bindPtr->interp, Tcl_DStringValue(&command),
+ Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
+
+ if (code != TCL_OK)
+ {
+#if 0
+ if (code == TCL_CONTINUE)
+ {
+ /* Nothing */
+ }
+ else if (code == TCL_BREAK)
+ {
+ break;
+ }
+ else
+#endif
+ {
+ Tcl_AddErrorInfo(bindPtr->interp,
+ "\n (command bound to quasi-event)");
+ Tcl_BackgroundError(bindPtr->interp);
+ break;
+ }
+ }
+ }
+
+ /* Restore the interpreter result */
+ Tcl_DStringResult(bindPtr->interp, &savedResult);
+
+ Tcl_DStringFree(&command);
+}
+
+#endif /* 0 */
+
+int QE_BindEvent(QE_BindingTable bindingTable, QE_Event *eventPtr)
+{
+ 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);
+ if (eventPtr->detail)
+ BindEvent(bindPtr, eventPtr, 0, eiPtr, dPtr);
+
+ return TCL_OK;
+}
+
+/*
+ * 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))
+
+static char *GetField(char *p, char *copy, int size)
+{
+ int ch = *p;
+
+ while ((ch != '\0') && !isspace(ch) && (ch != '>')
+ && (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 ParseEventDescription(BindingTable *bindPtr, char *eventString,
+ Pattern *patPtr, EventInfo **eventInfoPtr, Detail **detailPtr)
+{
+ Tcl_Interp *interp = bindPtr->interp;
+ Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
+ char *p;
+ Tcl_HashEntry *hPtr;
+ char field[FIELD_SIZE];
+ EventInfo *eiPtr;
+ Detail *dPtr;
+
+ if (eventInfoPtr) *eventInfoPtr = NULL;
+ if (detailPtr) *detailPtr = NULL;
+
+ p = eventString;
+
+ patPtr->type = -1;
+ patPtr->detail = 0;
+
+ /* First char must by opening < */
+ if (*p != '<')
+ {
+ Tcl_AppendResult(interp, "missing \"<\" in event pattern \"",
+ eventString, "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ p++;
+
+ /* Event name (required)*/
+ p = GetField(p, field, FIELD_SIZE);
+
+ if (debug_bindings)
+ dbwin("GetField='%s'\n", field);
+
+ hPtr = Tcl_FindHashEntry(&bindPtr->eventTableByName, field);
+ if (hPtr == NULL)
+ {
+ Tcl_AppendStringsToObj(resultPtr, "unknown event \"",
+ field, "\"", NULL);
+ return TCL_ERROR;
+ }
+ eiPtr = (EventInfo *) Tcl_GetHashValue(hPtr);
+ patPtr->type = eiPtr->type;
+ if (eventInfoPtr) *eventInfoPtr = eiPtr;
+
+ /* Terminating > */
+ if (*p == '>')
+ return TCL_OK;
+
+ /* Detail name (optional) */
+ p = GetField(p, field, FIELD_SIZE);
+
+ if (debug_bindings)
+ dbwin("GetField='%s'\n", field);
+
+ if (*field != '\0')
+ {
+ /* Find detail for the matching event */
+ for (dPtr = eiPtr->detailList;
+ dPtr != NULL;
+ dPtr = dPtr->next)
+ {
+ if (strcmp(dPtr->name, field) == 0)
+ break;
+ }
+ if (dPtr == NULL)
+ {
+ Tcl_AppendStringsToObj(resultPtr, "unknown detail \"",
+ field, "\" for event \"", eiPtr->name, "\"", NULL);
+ return TCL_ERROR;
+ }
+ patPtr->detail = dPtr->code;
+ if (detailPtr) *detailPtr = dPtr;
+ }
+
+ /* Terminating > */
+ if (*p != '>')
+ {
+ Tcl_AppendResult(interp, "missing \">\" in event pattern \"",
+ eventString, "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ 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", 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", 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];
+
+ /* TclFormatInt() */
+ (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 *detailPtr = FindDetail(bindPtr, event, detail);
+
+ if (detailPtr != NULL)
+ QE_ExpandString((char *) detailPtr->name, result);
+ else
+ QE_ExpandString("unknown", result);
+}
+
+int QE_BindCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ BindingTable *bindPtr = (BindingTable *) bindingTable;
+ Tk_Window tkwin = Tk_MainWindow(bindPtr->interp);
+ ClientData object;
+ char *string;
+
+ if ((objc - objOffset < 1) || (objc - objOffset > 4))
+ {
+ Tcl_WrongNumArgs(bindPtr->interp, objOffset, objv,
+ "?object? ?pattern? ?script?");
+ return TCL_ERROR;
+ }
+
+ if (objc - objOffset == 1)
+ {
+ QE_GetAllObjects(bindingTable);
+ return TCL_OK;
+ }
+
+ string = Tcl_GetString(objv[objOffset + 1]);
+
+ if (string[0] == '.')
+ {
+ Tk_Window tkwin2;
+ tkwin2 = Tk_NameToWindow(bindPtr->interp, string, tkwin);
+ if (tkwin2 == NULL)
+ {
+ return TCL_ERROR;
+ }
+ object = (ClientData) Tk_PathName(tkwin2);
+ }
+ else
+ {
+ object = (ClientData) Tk_GetUid(string);
+ }
+
+ if (objc - objOffset == 4)
+ {
+ int append = 0;
+ char *sequence = Tcl_GetString(objv[objOffset + 2]);
+ char *script = Tcl_GetString(objv[objOffset + 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 - objOffset == 3)
+ {
+ char *sequence = Tcl_GetString(objv[objOffset + 2]);
+
+ return QE_GetBinding(bindingTable, object, sequence);
+ }
+ else
+ {
+ QE_GetAllBindings(bindingTable, object);
+ }
+
+ return TCL_OK;
+}
+
+/*
+ * qegenerate -- Generate events from scripts.
+ * Usage: qegenerate pattern ?field value ...?
+ * Desciption: Scripts can generate "fake" quasi-events by providing
+ * a quasi-event pattern and option field/value pairs.
+ */
+
+typedef struct GenerateField {
+ char which;
+ char *string;
+} GenerateField;
+
+static GenerateField generateField[10];
+static int generateCount;
+
+/* Perform %-substitution using args passed to QE_GenerateCmd() */
+static void Percents_Generate(QE_ExpandArgs *args)
+{
+ int i;
+
+ for (i = 0; i < generateCount; i++)
+ {
+ if (args->which == generateField[i].which)
+ {
+ QE_ExpandString(generateField[i].string, args->result);
+ return;
+ }
+ }
+
+ 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 'W': /* object */
+ QE_ExpandString((char *) args->object, args->result);
+ break;
+
+ default: /* unknown */
+ QE_ExpandUnknown(args->which, args->result);
+ break;
+ }
+}
+
+int
+QE_GenerateCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ BindingTable *bindPtr = (BindingTable *) bindingTable;
+ QE_Event fakeEvent;
+ QE_ExpandProc oldExpandProc;
+ Tcl_Obj *CONST *objPtr;
+ EventInfo *eiPtr;
+ Detail *dPtr;
+ GenerateField *fieldPtr;
+ char *p, *t;
+ Pattern pats;
+ int result;
+
+ if (objc - objOffset < 2)
+ {
+ Tcl_WrongNumArgs(bindPtr->interp, objOffset, objv, "pattern ?field value ...?");
+ return TCL_ERROR;
+ }
+
+ p = Tcl_GetStringFromObj(objv[objOffset + 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;
+ }
+
+ fakeEvent.type = pats.type;
+ fakeEvent.detail = pats.detail;
+ fakeEvent.clientData = (ClientData) dPtr;
+
+ objPtr = objv + objOffset + 2;
+ objc -= objOffset + 2;
+
+ fieldPtr = &generateField[0];
+ generateCount = 0;
+
+ while (objc > 1)
+ {
+ int length;
+ t = Tcl_GetStringFromObj(objPtr[0], &length);
+ if ((length != 2) || (t[0] != '-'))
+ {
+ Tcl_AppendResult(bindPtr->interp, "invalid percent char \"", t,
+ "\"", NULL);
+ return TCL_ERROR;
+ }
+ fieldPtr->which = t[1];
+ fieldPtr->string = Tcl_GetStringFromObj(objPtr[1], NULL);
+ fieldPtr++;
+ generateCount++;
+ objPtr += 2;
+ objc -= 2;
+ }
+
+ if (objc != 0)
+ {
+ Tcl_WrongNumArgs(bindPtr->interp, 2, objv, "pattern ?field value ...?");
+ return TCL_ERROR;
+ }
+
+ /*
+ * XXX Hack -- Swap in our own %-substitution routine. Percents_Generate()
+ * uses the values the caller passed us.
+ */
+ if ((dPtr != NULL) && (dPtr->expandProc != NULL))
+ {
+ oldExpandProc = dPtr->expandProc;
+ dPtr->expandProc = Percents_Generate;
+ }
+ else
+ {
+ oldExpandProc = eiPtr->expandProc;
+ eiPtr->expandProc = Percents_Generate;
+ }
+
+ result = QE_BindEvent(bindingTable, &fakeEvent);
+
+ if ((dPtr != NULL) && (dPtr->expandProc != NULL))
+ dPtr->expandProc = oldExpandProc;
+ else
+ eiPtr->expandProc = oldExpandProc;
+
+ return result;
+}
+
+#if BIND_ACTIVE
+
+/* qeconfigure $win <Term-fresh> -active no */
+
+int
+QE_ConfigureCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ 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 - objOffset < 3)
+ {
+ Tcl_WrongNumArgs(interp, objOffset, objv, "window pattern ?option? ?value? ?option value ...?");
+ return TCL_ERROR;
+ }
+
+ t = Tcl_GetStringFromObj(objv[objOffset + 1], NULL);
+ eventString = Tcl_GetStringFromObj(objv[objOffset + 2], NULL);
+
+ if (t[0] == '.')
+ {
+ Tk_Window tkwin2;
+ tkwin2 = Tk_NameToWindow(interp, t, tkwin);
+ if (tkwin2 == NULL)
+ {
+ return TCL_ERROR;
+ }
+ object = (ClientData) Tk_PathName(tkwin2);
+ }
+ else
+ {
+ object = (ClientData) Tk_GetUid(t);
+ }
+
+ if (FindSequence(bindPtr, object, eventString, 0, NULL, &valuePtr) != TCL_OK)
+ return TCL_ERROR;
+
+ 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;
+ }
+
+ 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 */
+
+#if ALLOW_INSTALL
+
+#if 0 /* comment */
+
+qeinstall detail <Setting> show_icons 500 QEExpandCmd_Setting
+
+proc QEExpandCmd_Setting {char object event detail} {
+
+ switch -- $char {
+ c {
+ return [Setting $detail]
+ }
+ d {
+ return $detail
+ }
+ W {
+ return $object
+ }
+ default {
+ return $char
+ }
+ }
+}
+
+#endif /* comment */
+
+/* Perform %-substitution by calling a Tcl command */
+static void Percents_Install(QE_ExpandArgs *args)
+{
+ BindingTable *bindPtr = (BindingTable *) args->bindingTable;
+ Tcl_Interp *interp = bindPtr->interp;
+ Detail *dPtr = (Detail *) args->clientData;
+ Tcl_DString command;
+ Tcl_SavedResult state;
+
+ if (dPtr->command != NULL)
+ {
+ Tcl_DStringInit(&command);
+ Tcl_DStringAppend(&command, dPtr->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, dPtr->event->name, -1);
+ Tcl_DStringAppend(&command, " ", 1);
+ Tcl_DStringAppend(&command, dPtr->name, -1);
+
+ 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
+ {
+ Tcl_AddErrorInfo(interp, "\n (expanding percents)");
+ Tcl_BackgroundError(interp);
+ }
+ Tcl_RestoreResult(interp, &state);
+
+ Tcl_DStringFree(&command);
+ }
+}
+
+int QE_InstallCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ BindingTable *bindPtr = (BindingTable *) bindingTable;
+ static CONST char *commandOption[] = {"detail", "event", NULL};
+ int index;
+
+ if (objc - objOffset < 2)
+ {
+ Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "option arg ...");
+ return TCL_ERROR;
+ }
+
+ if (Tcl_GetIndexFromObj(bindPtr->interp, objv[objOffset + 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 - objOffset < 4) || (objc - objOffset > 5))
+ {
+ Tcl_WrongNumArgs(bindPtr->interp, objOffset + 2, objv,
+ "event detail ?percentsCommand?");
+ return TCL_ERROR;
+ }
+
+ /* Find the event type */
+ eventName = Tcl_GetStringFromObj(objv[objOffset + 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[objOffset + 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 - objOffset == 4)
+ break;
+
+ /* Set the Tcl command for this detail */
+ command = Tcl_GetStringFromObj(objv[objOffset + 4], &length);
+ if (length)
+ {
+ dPtr->command = Tcl_Alloc(length + 1);
+ (void) strcpy(dPtr->command, command);
+ }
+ break;
+ }
+
+ case 1: /* event */
+ {
+ char *eventName;
+ int id;
+ EventInfo *eiPtr;
+ Tcl_HashEntry *hPtr;
+
+ if (objc - objOffset != 3)
+ {
+ Tcl_WrongNumArgs(bindPtr->interp, objOffset + 2, objv,
+ "name");
+ return TCL_ERROR;
+ }
+
+ eventName = Tcl_GetStringFromObj(objv[objOffset + 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;
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
+
+int QE_UninstallCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ BindingTable *bindPtr = (BindingTable *) bindingTable;
+ static CONST char *commandOption[] = {"detail", "event", NULL};
+ int index;
+
+ if (objc - objOffset < 2)
+ {
+ Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "option arg ...");
+ return TCL_ERROR;
+ }
+
+ if (Tcl_GetIndexFromObj(bindPtr->interp, objv[objOffset + 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 - objOffset != 4)
+ {
+ Tcl_WrongNumArgs(bindPtr->interp, objOffset + 2, objv,
+ "event detail");
+ return TCL_ERROR;
+ }
+
+ /* Find the event type */
+ eventName = Tcl_GetStringFromObj(objv[objOffset + 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[objOffset + 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 - objOffset != 3)
+ {
+ Tcl_WrongNumArgs(bindPtr->interp, objOffset + 2, objv,
+ "name");
+ return TCL_ERROR;
+ }
+
+ /* Find the event type */
+ eventName = Tcl_GetStringFromObj(objv[objOffset + 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_LinkageCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ BindingTable *bindPtr = (BindingTable *) bindingTable;
+ char *eventName, *detailName;
+ Detail *dPtr;
+ EventInfo *eiPtr;
+ Tcl_HashEntry *hPtr;
+
+ if (objc - objOffset < 2 || objc - objOffset > 3)
+ {
+ Tcl_WrongNumArgs(bindPtr->interp, objOffset + 1, objv, "event ?detail?");
+ return TCL_ERROR;
+ }
+
+ /* Find the event type */
+ eventName = Tcl_GetStringFromObj(objv[objOffset + 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 - objOffset == 2)
+ {
+ Tcl_SetResult(bindPtr->interp, eiPtr->dynamic ? "dynamic" : "static",
+ TCL_STATIC);
+ return TCL_OK;
+ }
+
+ /* Get the detail name */
+ detailName = Tcl_GetStringFromObj(objv[objOffset + 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;
+}
+
+#endif /* ALLOW_INSTALL */
+
diff --git a/generic/qebind.h b/generic/qebind.h
new file mode 100644
index 0000000..eb5799d
--- /dev/null
+++ b/generic/qebind.h
@@ -0,0 +1,67 @@
+/* File: qebind.c */
+
+/* Purpose: public interface to quasi-event package */
+
+#ifndef INCLUDED_QEBIND_H
+#define INCLUDED_QEBIND_H
+
+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);
+extern QE_BindingTable bindingTable;
+extern int debug_bindings;
+
+extern int QE_BindInit(Tcl_Interp *interp);
+extern QE_BindingTable QE_CreateBindingTable(Tcl_Interp *interp);
+extern void QE_DeleteBindingTable(QE_BindingTable bindingTable);
+extern int QE_InstallEvent(QE_BindingTable bindingTable, char *name, QE_ExpandProc expand);
+extern int QE_InstallDetail(QE_BindingTable bindingTable, char *name, int eventType, QE_ExpandProc expand);
+extern int QE_CreateBinding(QE_BindingTable bindingTable,
+ ClientData object, char *eventString, char *command, int append);
+extern int QE_DeleteBinding(QE_BindingTable bindingTable,
+ ClientData object, char *eventString);
+extern int QE_GetBinding(QE_BindingTable bindingTable,
+ ClientData object, char *eventString);
+extern int QE_GetAllBindings(QE_BindingTable bindingTable,
+ ClientData object);
+extern int QE_GetEventNames(QE_BindingTable bindingTable);
+extern int QE_GetDetailNames(QE_BindingTable bindingTable, char *eventName);
+extern int QE_BindEvent(QE_BindingTable bindingTable, QE_Event *eventPtr);
+extern void QE_ExpandDouble(double number, Tcl_DString *result);
+extern void QE_ExpandNumber(long number, Tcl_DString *result);
+extern void QE_ExpandString(char *string, Tcl_DString *result);
+extern void QE_ExpandEvent(QE_BindingTable bindingTable, int eventType, Tcl_DString *result);
+extern void QE_ExpandDetail(QE_BindingTable bindingTable, int event, int detail, Tcl_DString *result);
+extern void QE_ExpandUnknown(char which, Tcl_DString *result);
+extern int QE_BindCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[]);
+extern int QE_ConfigureCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[]);
+extern int QE_GenerateCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[]);
+extern int QE_InstallCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[]);
+extern int QE_UninstallCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[]);
+extern int QE_LinkageCmd(QE_BindingTable bindingTable, int objOffset, int objc,
+ Tcl_Obj *CONST objv[]);
+
+#endif /* INCLUDED_QEBIND_H */
+
diff --git a/generic/tkTreeColumn.c b/generic/tkTreeColumn.c
new file mode 100644
index 0000000..6d43e1f
--- /dev/null
+++ b/generic/tkTreeColumn.c
@@ -0,0 +1,1547 @@
+#include "tkTreeCtrl.h"
+
+typedef struct Column Column;
+
+struct Column
+{
+ char *text; /* -text */
+ int width; /* -width */
+ Tcl_Obj *widthObj; /* -width */
+ int minWidth; /* -minwidth */
+ Tcl_Obj *minWidthObj; /* -minwidth */
+ int stepWidth; /* -stepwidth */
+ Tcl_Obj *stepWidthObj; /* -stepwidth */
+ int widthHack; /* -widthhack */
+ Tk_Font tkfont; /* -font */
+ Tk_Justify justify; /* -justify */
+ Tk_3DBorder border; /* -border */
+ int borderWidth; /* -borderwidth */
+ int relief; /* -relief */
+ XColor *textColor; /* -textcolor */
+ int expand; /* -expand */
+ int visible; /* -visible */
+ char *tag; /* -tag */
+ char *imageString; /* -image */
+ Pixmap bitmap; /* -bitmap */
+ int sunken; /* -sunken */
+ Tcl_Obj *itemBgObj; /* -itembackground */
+ int button; /* -button */
+
+ TreeCtrl *tree;
+ int index; /* column number */
+ int textLen;
+ int textWidth;
+ Tk_Image image;
+ int neededWidth; /* calculated from borders + text + arrow */
+ int neededHeight; /* calculated from borders + text */
+ int useWidth; /* -width, -minwidth, or required+expansion */
+ int widthOfItems; /* width of all TreeItemColumns */
+ int textPad[2]; /* padding for text */
+ int imagePad[2]; /* padding for image */
+ int itemBgCount;
+ XColor **itemBgColor;
+ GC bitmapGC;
+
+#define ARROW_NONE 0
+#define ARROW_UP 1
+#define ARROW_DOWN 2
+ int arrow;
+
+#define SIDE_LEFT 0
+#define SIDE_RIGHT 1
+ int arrowSide;
+ int arrowGravity;
+
+ int arrowPad[2];
+ Column *next;
+};
+
+static char *arrowST[] = { "none", "up", "down", (char *) NULL };
+static char *arrowSideST[] = { "left", "right", (char *) NULL };
+
+#define COLU_CONF_IMAGE 0x0001
+#define COLU_CONF_NWIDTH 0x0002 /* neededWidth */
+#define COLU_CONF_NHEIGHT 0x0004 /* neededHeight */
+#define COLU_CONF_TWIDTH 0x0008 /* totalWidth */
+#define COLU_CONF_ITEMBG 0x0010
+#define COLU_CONF_DISPLAY 0x0040
+#define COLU_CONF_JUSTIFY 0x0080
+#define COLU_CONF_TAG 0x0100
+#define COLU_CONF_TEXT 0x0200
+#define COLU_CONF_BITMAP 0x0400
+#define COLU_CONF_RANGES 0x0800
+
+static Tk_OptionSpec columnSpecs[] = {
+ {TK_OPTION_STRING_TABLE, "-arrow", (char *) NULL, (char *) NULL,
+ "none", -1, Tk_Offset(Column, arrow),
+ 0, (ClientData) arrowST, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY},
+ {TK_OPTION_STRING_TABLE, "-arrowside", (char *) NULL, (char *) NULL,
+ "right", -1, Tk_Offset(Column, arrowSide),
+ 0, (ClientData) arrowSideST, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY},
+ {TK_OPTION_STRING_TABLE, "-arrowgravity", (char *) NULL, (char *) NULL,
+ "left", -1, Tk_Offset(Column, arrowGravity),
+ 0, (ClientData) arrowSideST, COLU_CONF_DISPLAY},
+ {TK_OPTION_PIXELS, "-arrowpadw", (char *) NULL, (char *) NULL,
+ "6", -1, Tk_Offset(Column, arrowPad[SIDE_LEFT]),
+ 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY},
+ {TK_OPTION_PIXELS, "-arrowpade", (char *) NULL, (char *) NULL,
+ "6", -1, Tk_Offset(Column, arrowPad[SIDE_RIGHT]),
+ 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY},
+ {TK_OPTION_BITMAP, "-bitmap", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(Column, bitmap),
+ TK_OPTION_NULL_OK, (ClientData) NULL,
+ COLU_CONF_BITMAP | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY},
+ {TK_OPTION_BORDER, "-background", (char *) NULL, (char *) NULL,
+ DEF_BUTTON_BG_COLOR, -1, Tk_Offset(Column, border),
+ 0, (ClientData) DEF_BUTTON_BG_MONO, COLU_CONF_DISPLAY},
+ {TK_OPTION_PIXELS, "-borderwidth", (char *) NULL, (char *) NULL,
+ "2", -1, Tk_Offset(Column, borderWidth),
+ 0, (ClientData) NULL, COLU_CONF_TWIDTH | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY},
+ {TK_OPTION_BOOLEAN, "-button", (char *) NULL, (char *) NULL,
+ "1", -1, Tk_Offset(Column, button),
+ 0, (ClientData) NULL, 0},
+ {TK_OPTION_BOOLEAN, "-expand", (char *) NULL, (char *) NULL,
+ "0", -1, Tk_Offset(Column, expand),
+ 0, (ClientData) NULL, COLU_CONF_TWIDTH},
+ {TK_OPTION_FONT, "-font", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(Column, tkfont),
+ TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY},
+ {TK_OPTION_STRING, "-image", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(Column, imageString),
+ TK_OPTION_NULL_OK, (ClientData) NULL,
+ COLU_CONF_IMAGE | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY},
+ {TK_OPTION_PIXELS, "-imagepade", (char *) NULL, (char *) NULL,
+ "6", -1, Tk_Offset(Column, imagePad[SIDE_RIGHT]),
+ 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY},
+ {TK_OPTION_PIXELS, "-imagepadw", (char *) NULL, (char *) NULL,
+ "6", -1, Tk_Offset(Column, imagePad[SIDE_LEFT]),
+ 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY},
+ {TK_OPTION_STRING, "-itembackground", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(Column, itemBgObj), -1,
+ TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_ITEMBG},
+ {TK_OPTION_JUSTIFY, "-justify", (char *) NULL, (char *) NULL,
+ "left", -1, Tk_Offset(Column, justify),
+ 0, (ClientData) NULL, COLU_CONF_DISPLAY | COLU_CONF_JUSTIFY},
+ {TK_OPTION_PIXELS, "-minwidth", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(Column, minWidthObj),
+ Tk_Offset(Column, minWidth),
+ TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TWIDTH},
+ {TK_OPTION_RELIEF, "-relief", (char *) NULL, (char *) NULL,
+ "raised", -1, Tk_Offset(Column, relief),
+ 0, (ClientData) NULL, COLU_CONF_DISPLAY},
+ {TK_OPTION_PIXELS, "-stepwidth", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(Column, stepWidthObj),
+ Tk_Offset(Column, stepWidth),
+ TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_RANGES},
+ {TK_OPTION_BOOLEAN, "-sunken", (char *) NULL, (char *) NULL,
+ "0", -1, Tk_Offset(Column, sunken),
+ 0, (ClientData) NULL, COLU_CONF_DISPLAY},
+ {TK_OPTION_STRING, "-tag", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(Column, tag),
+ TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TAG},
+ {TK_OPTION_STRING, "-text", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(Column, text),
+ TK_OPTION_NULL_OK, (ClientData) NULL,
+ COLU_CONF_TEXT | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT | COLU_CONF_DISPLAY},
+ {TK_OPTION_COLOR, "-textcolor", (char *) NULL, (char *) NULL,
+ DEF_BUTTON_FG, -1, Tk_Offset(Column, textColor),
+ 0, (ClientData) NULL, COLU_CONF_DISPLAY},
+ {TK_OPTION_PIXELS, "-textpade", (char *) NULL, (char *) NULL,
+ "6", -1, Tk_Offset(Column, textPad[SIDE_RIGHT]),
+ 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY},
+ {TK_OPTION_PIXELS, "-textpadw", (char *) NULL, (char *) NULL,
+ "6", -1, Tk_Offset(Column, textPad[SIDE_LEFT]),
+ 0, (ClientData) NULL, COLU_CONF_NWIDTH | COLU_CONF_DISPLAY},
+ {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(Column, widthObj), Tk_Offset(Column, width),
+ TK_OPTION_NULL_OK, (ClientData) NULL, COLU_CONF_TWIDTH},
+ {TK_OPTION_BOOLEAN, "-visible", (char *) NULL, (char *) NULL,
+ "1", -1, Tk_Offset(Column, visible),
+ 0, (ClientData) NULL, COLU_CONF_TWIDTH | COLU_CONF_DISPLAY},
+ {TK_OPTION_BOOLEAN, "-widthhack", (char *) NULL, (char *) NULL,
+ "0", -1, Tk_Offset(Column, widthHack),
+ 0, (ClientData) NULL, COLU_CONF_RANGES},
+ {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, 0, 0}
+};
+
+static Tk_OptionTable columnOptionTable = NULL;
+
+/* Called when Tk_Image is deleted or modified */
+static void ImageChangedProc(
+ ClientData clientData,
+ int x, int y,
+ int width, int height,
+ int imageWidth, int imageHeight)
+{
+ /* I would like to know the image was deleted... */
+}
+
+int Tree_FindColumnByTag(TreeCtrl *tree, Tcl_Obj *obj, TreeColumn *columnPtr, int flags)
+{
+ Column *walk = (Column *) tree->columns;
+ char *string = Tcl_GetString(obj);
+
+ if (!strcmp(string, "tail"))
+ {
+ if (!(flags & CFO_NOT_TAIL))
+ {
+ (*columnPtr) = tree->columnTail;
+ return TCL_OK;
+ }
+ FormatResult(tree->interp, "can't specify \"tail\" for this command");
+ return TCL_ERROR;
+ }
+
+ while (walk != NULL)
+ {
+ if ((walk->tag != NULL) && !strcmp(walk->tag, string))
+ {
+ (*columnPtr) = (TreeColumn) walk;
+ return TCL_OK;
+ }
+ walk = walk->next;
+ }
+ FormatResult(tree->interp, "column with tag \"%s\" doesn't exist",
+ string);
+ return TCL_ERROR;
+}
+
+int TreeColumn_FromObj(TreeCtrl *tree, Tcl_Obj *obj, TreeColumn *columnPtr, int flags)
+{
+ int columnIndex;
+
+ if (Tcl_GetIntFromObj(NULL, obj, &columnIndex) == TCL_OK)
+ {
+ if (columnIndex < 0 || columnIndex >= tree->columnCount)
+ {
+ FormatResult(tree->interp,
+ "bad column index \"%d\": must be from 0 to %d",
+ columnIndex, tree->columnCount - 1);
+ return TCL_ERROR;
+ }
+ (*columnPtr) = Tree_FindColumn(tree, columnIndex);
+ return TCL_OK;
+ }
+
+ return Tree_FindColumnByTag(tree, obj, columnPtr, flags);
+}
+
+TreeColumn Tree_FindColumn(TreeCtrl *tree, int columnIndex)
+{
+ Column *column = (Column *) tree->columns;
+
+ while (column != NULL)
+ {
+ if (column->index == columnIndex)
+ break;
+ column = column->next;
+ }
+ return (TreeColumn) column;
+}
+
+TreeColumn TreeColumn_Next(TreeColumn column_)
+{
+ return (TreeColumn) ((Column *) column_)->next;
+}
+
+static void Column_FreeColors(XColor **colors, int count)
+{
+ int i;
+
+ if (colors == NULL)
+ return;
+ for (i = 0; i < count; i++)
+ if (colors[i] != NULL)
+ Tk_FreeColor(colors[i]);
+ wipefree((char *) colors, sizeof(XColor *) * count);
+}
+
+static int Column_Config(Column *column, int objc, Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = column->tree;
+ Column saved, *walk;
+ Tk_SavedOptions savedOptions;
+ int error;
+ Tcl_Obj *errorResult = NULL;
+ int mask;
+ XGCValues gcValues;
+ unsigned long gcMask;
+
+ for (error = 0; error <= 1; error++)
+ {
+ if (error == 0)
+ {
+ if (Tk_SetOptions(tree->interp, (char *) column, columnOptionTable,
+ objc, objv, tree->tkwin, &savedOptions, &mask) != TCL_OK)
+ {
+ mask = 0;
+ continue;
+ }
+
+ /* Verify -tag is unique */
+ if ((mask & COLU_CONF_TAG) && (column->tag != NULL))
+ {
+ walk = (Column *) tree->columns;
+ if (!strcmp(column->tag, "tail"))
+ {
+ FormatResult(tree->interp, "column tag \"%s\" is not unique",
+ column->tag);
+ continue;
+ }
+ while (walk != NULL)
+ {
+ if ((walk != column) && (walk->tag != NULL) && !strcmp(walk->tag, column->tag))
+ {
+ FormatResult(tree->interp, "column tag \"%s\" is not unique",
+ column->tag);
+ break;
+ }
+ walk = walk->next;
+ }
+ if (walk != NULL)
+ continue;
+ }
+
+ if (mask & COLU_CONF_IMAGE)
+ {
+ saved.image = column->image;
+ column->image = NULL;
+ if (column->imageString != NULL)
+ {
+ column->image = Tk_GetImage(tree->interp, tree->tkwin,
+ column->imageString, ImageChangedProc,
+ (ClientData) column);
+ if (column->image == NULL)
+ continue;
+ }
+ }
+
+ if (mask & COLU_CONF_ITEMBG)
+ {
+ saved.itemBgColor = column->itemBgColor;
+ saved.itemBgCount = column->itemBgCount;
+ column->itemBgColor = NULL;
+ column->itemBgCount = 0;
+ if (column->itemBgObj != NULL)
+ {
+ int i, length, listObjc;
+ Tcl_Obj **listObjv;
+ XColor **colors;
+
+ if (Tcl_ListObjGetElements(tree->interp, column->itemBgObj,
+ &listObjc, &listObjv) != TCL_OK)
+ continue;
+ colors = (XColor **) ckalloc(sizeof(XColor *) * 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] = Tk_AllocColorFromObj(tree->interp,
+ tree->tkwin, listObjv[i]);
+ if (colors[i] == NULL)
+ break;
+ }
+ }
+ if (i < listObjc)
+ {
+ Column_FreeColors(colors, listObjc);
+ continue;
+ }
+ column->itemBgColor = colors;
+ column->itemBgCount = listObjc;
+ }
+ }
+
+ if (mask & COLU_CONF_IMAGE)
+ {
+ if (saved.image != NULL)
+ Tk_FreeImage(saved.image);
+ }
+ if (mask & COLU_CONF_ITEMBG)
+ {
+ Column_FreeColors(saved.itemBgColor, saved.itemBgCount);
+
+ /* Set max -itembackground */
+ tree->columnBgCnt = 0;
+ walk = (Column *) tree->columns;
+ while (walk != NULL)
+ {
+ if (walk->itemBgCount > tree->columnBgCnt)
+ tree->columnBgCnt = walk->itemBgCount;
+ walk = walk->next;
+ }
+ }
+ Tk_FreeSavedOptions(&savedOptions);
+ break;
+ }
+ else
+ {
+ errorResult = Tcl_GetObjResult(tree->interp);
+ Tcl_IncrRefCount(errorResult);
+ Tk_RestoreSavedOptions(&savedOptions);
+
+ if (mask & COLU_CONF_IMAGE)
+ {
+ if (column->image != NULL)
+ Tk_FreeImage(column->image);
+ column->image = saved.image;
+ }
+ if (mask & COLU_CONF_ITEMBG)
+ {
+ Column_FreeColors(column->itemBgColor, column->itemBgCount);
+ column->itemBgColor = saved.itemBgColor;
+ column->itemBgCount = saved.itemBgCount;
+ }
+
+ Tcl_SetObjResult(tree->interp, errorResult);
+ Tcl_DecrRefCount(errorResult);
+ return TCL_ERROR;
+ }
+ }
+
+ if (mask & COLU_CONF_TEXT)
+ {
+ column->textLen = column->text ? strlen(column->text) : 0;
+ if (column->textLen)
+ {
+ Tk_Font tkfont = column->tkfont ? column->tkfont : tree->tkfont;
+ column->textWidth = Tk_TextWidth(tkfont, column->text, column->textLen);
+ }
+ else
+ column->textWidth = 0;
+ }
+
+ if (mask & COLU_CONF_BITMAP)
+ {
+ if (column->bitmapGC != None)
+ {
+ Tk_FreeGC(tree->display, column->bitmapGC);
+ column->bitmapGC = None;
+ }
+ if (column->bitmap != None)
+ {
+ gcValues.clip_mask = column->bitmap;
+ gcValues.graphics_exposures = False;
+ gcMask = GCClipMask | GCGraphicsExposures;
+ column->bitmapGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues);
+ }
+ }
+
+ if (mask & COLU_CONF_ITEMBG)
+ Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_OUT_OF_DATE);
+
+ if (mask & COLU_CONF_NWIDTH)
+ column->neededWidth = -1;
+ if (mask & COLU_CONF_NHEIGHT)
+ {
+ column->neededHeight = -1;
+ tree->headerHeight = -1;
+ }
+
+ if (mask & COLU_CONF_JUSTIFY)
+ Tree_DInfoChanged(tree, DINFO_INVALIDATE | DINFO_OUT_OF_DATE);
+
+ /* -stepwidth and -widthHack */
+ if (mask & COLU_CONF_RANGES)
+ Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
+
+ /* Redraw everything */
+ if (mask & (COLU_CONF_TWIDTH | COLU_CONF_NWIDTH | COLU_CONF_NHEIGHT))
+ {
+ tree->widthOfColumns = -1;
+ Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH | DINFO_DRAW_HEADER);
+ }
+
+ /* Redraw header only */
+ else if (mask & COLU_CONF_DISPLAY)
+ {
+ Tree_DInfoChanged(tree, DINFO_DRAW_HEADER);
+ }
+
+ return TCL_OK;
+}
+
+static Column *Column_Alloc(TreeCtrl *tree)
+{
+ Column *column;
+
+ if (columnOptionTable == NULL)
+ columnOptionTable = Tk_CreateOptionTable(tree->interp, columnSpecs);
+
+ column = (Column *) ckalloc(sizeof(Column));
+ memset(column, '\0', sizeof(Column));
+ column->tree = tree;
+ if (Tk_InitOptions(tree->interp, (char *) column, columnOptionTable,
+ tree->tkwin) != TCL_OK)
+ {
+ WFREE(column, Column);
+ return NULL;
+ }
+#if 0
+ if (Tk_SetOptions(header->tree->interp, (char *) column,
+ columnOptionTable, 0,
+ NULL, header->tree->tkwin, &savedOptions,
+ (int *) NULL) != TCL_OK)
+ {
+ WFREE(column, Column);
+ return NULL;
+ }
+#endif
+ column->neededWidth = column->neededHeight = -1;
+ tree->headerHeight = tree->widthOfColumns = -1;
+ tree->columnCount++;
+ return column;
+}
+
+TreeColumn Tree_CreateColumn(TreeCtrl *tree, int columnIndex, int *isNew)
+{
+ Column *column = (Column *) tree->columns;
+ int i;
+
+ if (isNew != NULL)
+ (*isNew) = FALSE;
+ if (column == NULL)
+ {
+ column = Column_Alloc(tree);
+ column->index = 0;
+ tree->columns = (TreeColumn) column;
+ if (isNew != NULL)
+ (*isNew) = TRUE;
+ }
+ for (i = 0; i < columnIndex; i++)
+ {
+ if (column->next == NULL)
+ {
+ column->next = Column_Alloc(tree);
+ column->next->index = i + 1;
+ if (isNew != NULL)
+ (*isNew) = TRUE;
+ }
+ column = column->next;
+ }
+ return (TreeColumn) column;
+}
+
+static Column *Column_Free(Column *column)
+{
+ TreeCtrl *tree = column->tree;
+ Column *next = column->next;
+
+ Column_FreeColors(column->itemBgColor, column->itemBgCount);
+ if (column->bitmapGC != None)
+ Tk_FreeGC(tree->display, column->bitmapGC);
+ if (column->image != NULL)
+ Tk_FreeImage(column->image);
+ Tk_FreeConfigOptions((char *) column, columnOptionTable, tree->tkwin);
+ WFREE(column, Column);
+ tree->columnCount--;
+ return next;
+}
+
+int TreeColumn_FixedWidth(TreeColumn column_)
+{
+ return ((Column *) column_)->widthObj ? ((Column *) column_)->width : -1;
+}
+
+int TreeColumn_MinWidth(TreeColumn column_)
+{
+ return ((Column *) column_)->minWidthObj ? ((Column *) column_)->minWidth : -1;
+}
+
+int TreeColumn_StepWidth(TreeColumn column_)
+{
+ return ((Column *) column_)->stepWidthObj ? ((Column *) column_)->stepWidth : -1;
+}
+
+int TreeColumn_NeededWidth(TreeColumn column_)
+{
+ Column *column = (Column *) column_;
+ int i, widthList[3], padList[4], n = 0;
+ int arrowWidth = 0;
+
+ if (column->neededWidth >= 0)
+ return column->neededWidth;
+
+ for (i = 0; i < 3; i++) widthList[i] = 0;
+ for (i = 0; i < 4; i++) padList[i] = 0;
+
+ if (column->arrow != ARROW_NONE)
+ {
+ arrowWidth = Tree_HeaderHeight(column->tree) / 2;
+ if (!(arrowWidth & 1))
+ arrowWidth--;
+ }
+ if ((column->arrow != ARROW_NONE) && (column->arrowSide == SIDE_LEFT))
+ {
+ widthList[n] = arrowWidth;
+ padList[n] = column->arrowPad[SIDE_LEFT];
+ padList[n + 1] = column->arrowPad[SIDE_RIGHT];
+ n++;
+ }
+ if ((column->image != NULL) || (column->bitmap != None))
+ {
+ int imgWidth, imgHeight;
+ if (column->image != NULL)
+ Tk_SizeOfImage(column->image, &imgWidth, &imgHeight);
+ else
+ Tk_SizeOfBitmap(column->tree->display, column->bitmap, &imgWidth, &imgHeight);
+ padList[n] = MAX(column->imagePad[SIDE_LEFT], padList[n]);
+ padList[n + 1] = column->imagePad[SIDE_RIGHT];
+ widthList[n] = imgWidth;
+ n++;
+ }
+ if (column->textLen > 0)
+ {
+ padList[n] = MAX(column->textPad[SIDE_LEFT], padList[n]);
+ padList[n + 1] = column->textPad[SIDE_RIGHT];
+ widthList[n] = column->textWidth;
+ n++;
+ }
+ if ((column->arrow != ARROW_NONE) && (column->arrowSide == SIDE_RIGHT))
+ {
+ widthList[n] = arrowWidth;
+ padList[n] = column->arrowPad[SIDE_LEFT];
+ padList[n + 1] = column->arrowPad[SIDE_RIGHT];
+ n++;
+ }
+
+ column->neededWidth = 0;
+ for (i = 0; i < n; i++)
+ column->neededWidth += widthList[i] + padList[i];
+ column->neededWidth += padList[n];
+
+ return column->neededWidth;
+}
+
+int TreeColumn_NeededHeight(TreeColumn column_)
+{
+ Column *column = (Column *) column_;
+
+ if (column->neededHeight >= 0)
+ return column->neededHeight;
+
+ column->neededHeight = 0;
+ if ((column->image != NULL) || (column->bitmap != None))
+ {
+ int imgWidth, imgHeight;
+ if (column->image != NULL)
+ Tk_SizeOfImage(column->image, &imgWidth, &imgHeight);
+ else
+ Tk_SizeOfBitmap(column->tree->display, column->bitmap, &imgWidth, &imgHeight);
+ column->neededHeight = MAX(column->neededHeight, imgHeight);
+ }
+ if (column->text != NULL)
+ {
+ Tk_Font tkfont = column->tkfont ? column->tkfont : column->tree->tkfont;
+ Tk_FontMetrics fm;
+ Tk_GetFontMetrics(tkfont, &fm);
+ column->neededHeight = MAX(column->neededHeight, fm.linespace);
+ }
+ column->neededHeight += column->borderWidth * 2;
+
+ return column->neededHeight;
+}
+
+int TreeColumn_UseWidth(TreeColumn column_)
+{
+ /* Update layout if needed */
+ (void) Tree_WidthOfColumns(((Column *) column_)->tree);
+
+ return ((Column *) column_)->useWidth;
+}
+
+void TreeColumn_SetUseWidth(TreeColumn column_, int width)
+{
+ ((Column *) column_)->useWidth = width;
+}
+
+Tk_Justify TreeColumn_Justify(TreeColumn column_)
+{
+ return ((Column *) column_)->justify;
+}
+
+int TreeColumn_WidthHack(TreeColumn column_)
+{
+ return ((Column *) column_)->widthHack;
+}
+
+GC TreeColumn_BackgroundGC(TreeColumn column_, int index)
+{
+ Column *column = (Column *) column_;
+ XColor *color;
+
+ if ((index < 0) || (column->itemBgCount == 0))
+ return None;
+ color = column->itemBgColor[index % column->itemBgCount];
+ if (color == NULL)
+ return None;
+ return Tk_GCForColor(color, Tk_WindowId(column->tree->tkwin));
+}
+
+int TreeColumn_Visible(TreeColumn column_)
+{
+ return ((Column *) column_)->visible;
+}
+
+int TreeColumn_Index(TreeColumn column_)
+{
+ return ((Column *) column_)->index;
+}
+
+int TreeColumnCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ static CONST char *commandNames[] = { "bbox", "cget", "configure", "delete",
+ "neededwidth", "width", (char *) NULL };
+ enum { COMMAND_BBOX, COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DELETE,
+ COMMAND_NEEDEDWIDTH, COMMAND_WIDTH };
+ int index;
+
+ if (objc < 3)
+ {
+ Tcl_WrongNumArgs(interp, 3, 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_BBOX:
+ {
+ int x = 0;
+ Column *column, *walk;
+
+ if (objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "columnIndex");
+ return TCL_ERROR;
+ }
+ if (TreeColumn_FromObj(tree, objv[3], (TreeColumn *) &column, 0) != TCL_OK)
+ return TCL_ERROR;
+ if (!tree->showHeader || !column->visible)
+ break;
+ /* Update layout */
+ Tree_WidthOfColumns(tree);
+ walk = (Column *) tree->columns;
+ while (walk != column)
+ {
+ if (column->visible)
+ x += walk->useWidth;
+ walk = walk->next;
+ }
+ FormatResult(interp, "%d %d %d %d",
+ x - tree->xOrigin,
+ tree->inset,
+ x - tree->xOrigin + column->useWidth,
+ tree->inset + Tree_HeaderHeight(tree));
+ break;
+ }
+ case COMMAND_CGET:
+ {
+ TreeColumn column;
+ Tcl_Obj *resultObjPtr;
+
+ if (objc != 5)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "columnIndex option");
+ return TCL_ERROR;
+ }
+ if (TreeColumn_FromObj(tree, objv[3], &column, 0) != TCL_OK)
+ return TCL_ERROR;
+ resultObjPtr = Tk_GetOptionValue(interp, (char *) column,
+ columnOptionTable, objv[4], tree->tkwin);
+ if (resultObjPtr == NULL)
+ return TCL_ERROR;
+ Tcl_SetObjResult(interp, resultObjPtr);
+ break;
+ }
+
+ case COMMAND_CONFIGURE:
+ {
+ int columnIndex;
+ Column *column;
+
+ if (objc < 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "columnIndex ?option? ?value?");
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIntFromObj(NULL, objv[3], &columnIndex) == TCL_OK)
+ {
+ if (columnIndex < 0)
+ return TCL_ERROR;
+ column = (Column *) Tree_CreateColumn(tree, columnIndex, NULL);
+ if (column == NULL)
+ return TCL_ERROR;
+ }
+ else if (Tree_FindColumnByTag(tree, objv[3], (TreeColumn *) &column, 0) != TCL_OK)
+ return TCL_ERROR;
+ if (objc <= 5)
+ {
+ Tcl_Obj *resultObjPtr;
+ resultObjPtr = Tk_GetOptionInfo(interp, (char *) column,
+ columnOptionTable,
+ (objc == 4) ? (Tcl_Obj *) NULL : objv[4],
+ tree->tkwin);
+ if (resultObjPtr == NULL)
+ return TCL_ERROR;
+ Tcl_SetObjResult(interp, resultObjPtr);
+ break;
+ }
+ return Column_Config(column, objc - 4, objv + 4);
+ }
+
+ case COMMAND_DELETE:
+ {
+ int columnIndex;
+ Column *column, *prev;
+ TreeItem item;
+ TreeItemColumn itemColumn;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+
+ if (objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "columnIndex");
+ return TCL_ERROR;
+ }
+ if (TreeColumn_FromObj(tree, objv[3], (TreeColumn *) &column,
+ CFO_NOT_TAIL) != TCL_OK)
+ return TCL_ERROR;
+ columnIndex = column->index;
+ if (columnIndex > 0)
+ {
+ prev = (Column *) Tree_FindColumn(tree, columnIndex - 1);
+ prev->next = column->next;
+ }
+ else
+ {
+ tree->columns = (TreeColumn) column->next;
+ }
+ Column_Free(column);
+
+ if (columnIndex == tree->columnTree)
+ tree->columnTree = 0;
+
+ /* Delete all TreeItemColumns */
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ itemColumn = TreeItem_FindColumn(tree, item, columnIndex);
+ if (itemColumn != NULL)
+ TreeItem_RemoveColumn(tree, item, itemColumn);
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+
+ /* Renumber columns */
+ column = (Column *) tree->columns;
+ columnIndex = 0;
+ while (column != NULL)
+ {
+ column->index = columnIndex++;
+ column = column->next;
+ }
+
+ tree->widthOfColumns = tree->headerHeight = -1;
+ Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH);
+ break;
+ }
+
+ case COMMAND_WIDTH:
+ {
+ Column *column;
+
+ if (objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "columnIndex");
+ return TCL_ERROR;
+ }
+ if (TreeColumn_FromObj(tree, objv[3], (TreeColumn *) &column, 0) != TCL_OK)
+ return TCL_ERROR;
+ /* Update layout if needed */
+ (void) Tree_TotalWidth(tree);
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(column->useWidth));
+ break;
+ }
+
+ case COMMAND_NEEDEDWIDTH:
+ {
+ Column *column;
+ int width;
+
+ if (objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "columnIndex");
+ return TCL_ERROR;
+ }
+ if (TreeColumn_FromObj(tree, objv[3], (TreeColumn *) &column, 0) != TCL_OK)
+ return TCL_ERROR;
+ /* Update layout if needed */
+ (void) Tree_TotalWidth(tree);
+ width = TreeColumn_WidthOfItems((TreeColumn) column);
+ width = MAX(width, TreeColumn_NeededWidth((TreeColumn) column));
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(width));
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
+
+struct Layout
+{
+ Tk_Font tkfont;
+ Tk_FontMetrics fm;
+ int width; /* Provided by caller */
+ int height; /* Provided by caller */
+ int textLeft;
+ int textWidth;
+ int bytesThatFit;
+ int imageLeft;
+ int imageWidth;
+ int arrowLeft;
+ int arrowWidth;
+ int arrowHeight;
+};
+
+static void Column_Layout(Column *column, struct Layout *layout)
+{
+ int i, leftList[3], widthList[3], padList[4], n = 0;
+ int iArrow = -1, iImage = -1, iText = -1;
+ int left, right;
+
+ for (i = 0; i < 3; i++) leftList[i] = 0;
+ for (i = 0; i < 3; i++) widthList[i] = 0;
+ for (i = 0; i < 4; i++) padList[i] = 0;
+
+ if (column->arrow != ARROW_NONE)
+ {
+ layout->arrowWidth = Tree_HeaderHeight(column->tree) / 2;
+ if (!(layout->arrowWidth & 1))
+ layout->arrowWidth--;
+ layout->arrowHeight = layout->arrowWidth;
+ }
+ if ((column->arrow != ARROW_NONE) && (column->arrowSide == SIDE_LEFT))
+ {
+ widthList[n] = layout->arrowWidth;
+ padList[n] = column->arrowPad[SIDE_LEFT];
+ padList[n + 1] = column->arrowPad[SIDE_RIGHT];
+ iArrow = n++;
+ }
+ if ((column->image != NULL) || (column->bitmap != None))
+ {
+ int imgWidth, imgHeight;
+ if (column->image != NULL)
+ Tk_SizeOfImage(column->image, &imgWidth, &imgHeight);
+ else
+ Tk_SizeOfBitmap(column->tree->display, column->bitmap, &imgWidth, &imgHeight);
+ padList[n] = MAX(column->imagePad[SIDE_LEFT], padList[n]);
+ padList[n + 1] = column->imagePad[SIDE_RIGHT];
+ widthList[n] = imgWidth;
+ layout->imageWidth = imgWidth;
+ iImage = n++;
+ }
+ if (column->textLen > 0)
+ {
+ layout->tkfont = column->tkfont ? column->tkfont : column->tree->tkfont;
+ Tk_GetFontMetrics(layout->tkfont, &layout->fm);
+ layout->bytesThatFit = 0;
+ if (layout->width >= TreeColumn_NeededWidth((TreeColumn) column))
+ {
+ padList[n] = MAX(column->textPad[SIDE_LEFT], padList[n]);
+ padList[n + 1] = column->textPad[SIDE_RIGHT];
+ widthList[n] = column->textWidth;
+ iText = n++;
+ layout->bytesThatFit = column->textLen;
+ layout->textWidth = column->textWidth;
+ }
+ else
+ {
+ int width = column->neededWidth - layout->width;
+ if (width < column->textWidth)
+ {
+ width = column->textWidth - width;
+ layout->bytesThatFit = Ellipsis(layout->tkfont, column->text,
+ column->textLen, &width, "...");
+ padList[n] = MAX(column->textPad[SIDE_LEFT], padList[n]);
+ padList[n + 1] = column->textPad[SIDE_RIGHT];
+ widthList[n] = width;
+ iText = n++;
+ layout->textWidth = width;
+ }
+ }
+ }
+ if ((column->arrow != ARROW_NONE) && (column->arrowSide == SIDE_RIGHT))
+ {
+ widthList[n] = layout->arrowWidth;
+ padList[n] = column->arrowPad[SIDE_LEFT];
+ padList[n + 1] = column->arrowPad[SIDE_RIGHT];
+ iArrow = n++;
+ }
+
+ if (n == 0)
+ return;
+
+ if (iText != -1)
+ {
+ switch (column->justify)
+ {
+ case TK_JUSTIFY_LEFT:
+ leftList[iText] = 0;
+ break;
+ case TK_JUSTIFY_RIGHT:
+ leftList[iText] = layout->width;
+ break;
+ case TK_JUSTIFY_CENTER:
+ if (iImage == -1)
+ leftList[iText] = (layout->width - widthList[iText]) / 2;
+ else
+ leftList[iText] = (layout->width - widthList[iImage] -
+ padList[iText] - widthList[iText]) / 2 + widthList[iImage] +
+ padList[iText];
+ break;
+ }
+ }
+
+ if (iImage != -1)
+ {
+ switch (column->justify)
+ {
+ case TK_JUSTIFY_LEFT:
+ leftList[iImage] = 0;
+ break;
+ case TK_JUSTIFY_RIGHT:
+ leftList[iImage] = layout->width;
+ break;
+ case TK_JUSTIFY_CENTER:
+ if (iText == -1)
+ leftList[iImage] = (layout->width - widthList[iImage]) / 2;
+ else
+ leftList[iImage] = (layout->width - widthList[iImage] -
+ padList[iText] - widthList[iText]) / 2;
+ break;
+ }
+ }
+
+ if (iArrow == -1)
+ goto finish;
+
+ switch (column->justify)
+ {
+ case TK_JUSTIFY_LEFT:
+ switch (column->arrowSide)
+ {
+ case SIDE_LEFT:
+ leftList[iArrow] = 0;
+ break;
+ case SIDE_RIGHT:
+ switch (column->arrowGravity)
+ {
+ case SIDE_LEFT:
+ leftList[iArrow] = 0;
+ break;
+ case SIDE_RIGHT:
+ leftList[iArrow] = layout->width;
+ break;
+ }
+ break;
+ }
+ break;
+ case TK_JUSTIFY_RIGHT:
+ switch (column->arrowSide)
+ {
+ case SIDE_LEFT:
+ switch (column->arrowGravity)
+ {
+ case SIDE_LEFT:
+ leftList[iArrow] = 0;
+ break;
+ case SIDE_RIGHT:
+ leftList[iArrow] = layout->width;
+ break;
+ }
+ break;
+ case SIDE_RIGHT:
+ leftList[iArrow] = layout->width;
+ break;
+ }
+ break;
+ case TK_JUSTIFY_CENTER:
+ switch (column->arrowSide)
+ {
+ case SIDE_LEFT:
+ switch (column->arrowGravity)
+ {
+ case SIDE_LEFT:
+ leftList[iArrow] = 0;
+ break;
+ case SIDE_RIGHT:
+ if (n == 3)
+ leftList[iArrow] =
+ (layout->width - widthList[1] - padList[2] -
+ widthList[2]) / 2 - padList[1] - widthList[0];
+ else if (n == 2)
+ leftList[iArrow] =
+ (layout->width - widthList[1]) / 2 -
+ padList[1] - widthList[0];
+ else
+ leftList[iArrow] =
+ (layout->width - widthList[0]) / 2;
+ break;
+ }
+ break;
+ case SIDE_RIGHT:
+ switch (column->arrowGravity)
+ {
+ case SIDE_LEFT:
+ if (n == 3)
+ leftList[iArrow] =
+ (layout->width - widthList[0] - padList[1] -
+ widthList[1]) / 2 + widthList[0] + padList[1] +
+ widthList[1] + padList[2];
+ else if (n == 2)
+ leftList[iArrow] =
+ (layout->width - widthList[0]) / 2 +
+ widthList[0] + padList[1];
+ else
+ leftList[iArrow] =
+ (layout->width - widthList[0]) / 2;
+ break;
+ case SIDE_RIGHT:
+ leftList[iArrow] = layout->width;
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+finish:
+ right = layout->width - padList[n];
+ for (i = n - 1; i >= 0; i--)
+ {
+ if (leftList[i] + widthList[i] > right)
+ leftList[i] = right - widthList[i];
+ right -= widthList[i] + padList[i];
+ }
+ left = padList[0];
+ for (i = 0; i < n; i++)
+ {
+ if (leftList[i] < left)
+ leftList[i] = left;
+
+ if (i == iArrow)
+ layout->arrowLeft = leftList[i];
+ else if (i == iText)
+ layout->textLeft = leftList[i];
+ else if (i == iImage)
+ layout->imageLeft = leftList[i];
+
+ left += widthList[i] + padList[i + 1];
+ }
+}
+
+void TreeColumn_Draw(TreeColumn column_, Drawable drawable, int x, int y)
+{
+ Column *column = (Column *) column_;
+ TreeCtrl *tree = column->tree;
+ int height = tree->headerHeight;
+ struct Layout layout;
+ int width = column->useWidth;
+ int relief = column->sunken ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED;
+
+ layout.width = width;
+ layout.height = height;
+ Column_Layout(column, &layout);
+
+ Tk_Fill3DRectangle(tree->tkwin, drawable, column->border,
+ x, y, width, height, 0, TK_RELIEF_FLAT /* column->borderWidth, relief */);
+
+ if (column->image != NULL)
+ {
+ int imgW, imgH;
+ Tk_SizeOfImage(column->image, &imgW, &imgH);
+ Tk_RedrawImage(column->image, 0, 0, imgW, imgH,
+ drawable, x + layout.imageLeft + column->sunken,
+ y + (height - imgH) / 2 + column->sunken);
+ }
+ else if (column->bitmap != None)
+ {
+ int imgW, imgH, bx, by;
+
+ Tk_SizeOfBitmap(tree->display, column->bitmap, &imgW, &imgH);
+ bx = x + layout.imageLeft + column->sunken;
+ by = y + (height - imgH) / 2 + column->sunken;
+ XSetClipOrigin(tree->display, column->bitmapGC, bx, by);
+ XCopyPlane(tree->display, column->bitmap, drawable, column->bitmapGC,
+ 0, 0, (unsigned int) imgW, (unsigned int) imgH,
+ bx, by, 1);
+ XSetClipOrigin(tree->display, column->bitmapGC, 0, 0);
+ }
+
+ if ((column->text != NULL) && (layout.bytesThatFit > 0))
+ {
+ XGCValues gcValues;
+ GC gc;
+ unsigned long mask;
+ char staticStr[256], *text = staticStr;
+ int textLen = column->textLen;
+ char *ellipsis = "...";
+ int ellipsisLen = strlen(ellipsis);
+
+ if (textLen + ellipsisLen > sizeof(staticStr))
+ text = ckalloc(textLen + ellipsisLen);
+ memcpy(text, column->text, textLen);
+ if (layout.bytesThatFit != textLen)
+ {
+ textLen = abs(layout.bytesThatFit);
+ if (layout.bytesThatFit > 0)
+ {
+ memcpy(text + layout.bytesThatFit, ellipsis, ellipsisLen);
+ textLen += ellipsisLen;
+ }
+ }
+
+ gcValues.font = Tk_FontId(layout.tkfont);
+ gcValues.foreground = column->textColor->pixel;
+ gcValues.graphics_exposures = False;
+ mask = GCFont | GCForeground | GCGraphicsExposures;
+ gc = Tk_GetGC(tree->tkwin, mask, &gcValues);
+ Tk_DrawChars(tree->display, drawable, gc,
+ layout.tkfont, text, textLen,
+ x + layout.textLeft + column->sunken,
+ y + (height - layout.fm.linespace) / 2 + layout.fm.ascent + column->sunken);
+ Tk_FreeGC(tree->display, gc);
+ if (text != staticStr)
+ ckfree(text);
+ }
+
+ if (column->arrow != ARROW_NONE)
+ {
+ int arrowWidth = layout.arrowWidth;
+ int arrowHeight = layout.arrowHeight;
+ int arrowTop = y + (height - arrowHeight) / 2;
+ int arrowBottom = arrowTop + arrowHeight;
+ XPoint points[5];
+ int color1 = 0, color2 = 0;
+ int i;
+
+ switch (column->arrow)
+ {
+ case ARROW_UP:
+ points[0].x = x + layout.arrowLeft;
+ points[0].y = arrowBottom - 1;
+ points[1].x = x + layout.arrowLeft + arrowWidth / 2;
+ points[1].y = arrowTop - 1;
+ color1 = TK_3D_DARK_GC;
+ points[4].x = x + layout.arrowLeft + arrowWidth / 2;
+ points[4].y = arrowTop - 1;
+ points[3].x = x + layout.arrowLeft + arrowWidth - 1;
+ points[3].y = arrowBottom - 1;
+ points[2].x = x + layout.arrowLeft;
+ points[2].y = arrowBottom - 1;
+ color2 = TK_3D_LIGHT_GC;
+ break;
+ case ARROW_DOWN:
+ points[0].x = x + layout.arrowLeft + arrowWidth - 1;
+ points[0].y = arrowTop;
+ points[1].x = x + layout.arrowLeft + arrowWidth / 2;
+ points[1].y = arrowBottom;
+ color1 = TK_3D_LIGHT_GC;
+ points[2].x = x + layout.arrowLeft + arrowWidth - 1;
+ points[2].y = arrowTop;
+ points[3].x = x + layout.arrowLeft;
+ points[3].y = arrowTop;
+ points[4].x = x + layout.arrowLeft + arrowWidth / 2;
+ points[4].y = arrowBottom;
+ color2 = TK_3D_DARK_GC;
+ break;
+ }
+ for (i = 0; i < 5; i++)
+ {
+ points[i].x += column->sunken;
+ points[i].y += column->sunken;
+ }
+ XDrawLines(tree->display, drawable,
+ Tk_3DBorderGC(tree->tkwin, column->border, color2),
+ points + 2, 3, CoordModeOrigin);
+ XDrawLines(tree->display, drawable,
+ Tk_3DBorderGC(tree->tkwin, column->border, color1),
+ points, 2, CoordModeOrigin);
+ }
+
+ Tk_Draw3DRectangle(tree->tkwin, drawable, column->border,
+ x, y, width, height, column->borderWidth, relief);
+}
+
+void Tree_DrawHeader(TreeCtrl *tree, Drawable drawable, int x, int y)
+{
+ Column *column = (Column *) tree->columns;
+ Tk_Window tkwin = tree->tkwin;
+ int minX, maxX, width, height;
+ Drawable pixmap;
+
+ /* Update layout if needed */
+ (void) Tree_HeaderHeight(tree);
+ (void) Tree_WidthOfColumns(tree);
+
+ minX = tree->inset;
+ maxX = Tk_Width(tkwin) - tree->inset;
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_ITEM)
+ pixmap = Tk_GetPixmap(tree->display, Tk_WindowId(tkwin),
+ Tk_Width(tkwin), tree->inset + tree->headerHeight, Tk_Depth(tkwin));
+ else
+ pixmap = drawable;
+
+ while (column != NULL)
+ {
+ if (column->visible)
+ {
+ if ((x < maxX) && (x + column->useWidth > minX))
+ TreeColumn_Draw((TreeColumn) column, pixmap, x, y);
+ x += column->useWidth;
+ }
+ column = column->next;
+ }
+
+ /* Draw "tail" column */
+ if (x < maxX)
+ {
+ column = (Column *) tree->columnTail;
+ width = maxX - x + column->borderWidth;
+ height = tree->headerHeight;
+ Tk_Fill3DRectangle(tkwin, pixmap, column->border,
+ x, y, width, height, column->borderWidth, column->relief);
+ Tk_Draw3DRectangle(tkwin, pixmap, column->border,
+ x, y, width, height, column->borderWidth, column->relief);
+ }
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_ITEM)
+ {
+ XCopyArea(tree->display, pixmap, drawable,
+ tree->copyGC, minX, y,
+ maxX - minX, tree->headerHeight,
+ tree->inset, y);
+
+ Tk_FreePixmap(tree->display, pixmap);
+ }
+}
+
+/* Calculate the maximum needed width of all ReallyVisible TreeItemColumns */
+int TreeColumn_WidthOfItems(TreeColumn column_)
+{
+ Column *column = (Column *) column_;
+ TreeCtrl *tree = column->tree;
+ TreeItem item;
+ TreeItemColumn itemColumn;
+ int width;
+
+ if (column->widthOfItems >= 0)
+ return column->widthOfItems;
+
+ column->widthOfItems = 0;
+ item = tree->root;
+ if (!TreeItem_ReallyVisible(tree, item))
+ item = TreeItem_NextVisible(tree, item);
+ while (item != NULL)
+ {
+ itemColumn = TreeItem_FindColumn(tree, item, column->index);
+ if (itemColumn != NULL)
+ {
+ width = TreeItemColumn_NeededWidth(tree, item, itemColumn);
+ if (column->index == tree->columnTree)
+ width += TreeItem_Indent(tree, item);
+ column->widthOfItems = MAX(column->widthOfItems, width);
+ }
+ item = TreeItem_NextVisible(tree, item);
+ }
+
+ return column->widthOfItems;
+}
+
+/* Set useWidth for all columns */
+void Tree_LayoutColumns(TreeCtrl *tree)
+{
+ Column *column = (Column *) tree->columns;
+ int width, visWidth, totalWidth = 0;
+ int numExpand = 0;
+
+ while (column != NULL)
+ {
+ if (column->visible)
+ {
+ if (column->widthObj != NULL)
+ width = column->width;
+ else
+ {
+ width = TreeColumn_WidthOfItems((TreeColumn) column);
+ width = MAX(width, TreeColumn_NeededWidth((TreeColumn) column));
+ width = MAX(width, TreeColumn_MinWidth((TreeColumn) column));
+ if (column->expand)
+ numExpand++;
+ }
+ column->useWidth = width;
+ totalWidth += width;
+ }
+ else
+ column->useWidth = 0;
+ column = column->next;
+ }
+
+ visWidth = Tk_Width(tree->tkwin) - tree->inset * 2;
+ if ((visWidth > totalWidth) && (numExpand > 0))
+ {
+ int extraWidth = (visWidth - totalWidth) / numExpand;
+ int fudge = (visWidth - totalWidth) - extraWidth * numExpand;
+ int seen = 0;
+
+ column = (Column *) tree->columns;
+ while (column != NULL)
+ {
+ if (column->visible && column->expand && (column->widthObj == NULL))
+ {
+ column->useWidth += extraWidth;
+ if (++seen == numExpand)
+ {
+ column->useWidth += fudge;
+ break;
+ }
+ }
+ column = column->next;
+ }
+ }
+}
+
+void Tree_InvalidateColumnWidth(TreeCtrl *tree, int columnIndex)
+{
+ Column *column;
+
+ if (columnIndex == -1)
+ {
+ column = (Column *) tree->columns;
+ while (column != NULL)
+ {
+ column->widthOfItems = -1;
+ column = column->next;
+ }
+ }
+ else
+ {
+ column = (Column *) Tree_FindColumn(tree, columnIndex);
+ if (column != NULL)
+ column->widthOfItems = -1;
+ }
+ tree->widthOfColumns = -1;
+ Tree_DInfoChanged(tree, DINFO_CHECK_COLUMN_WIDTH);
+}
+
+void TreeColumn_TreeChanged(TreeCtrl *tree, int flagT)
+{
+ Column *column;
+
+ /* Column widths are invalidated elsewhere */
+ if (flagT & TREE_CONF_FONT)
+ {
+ column = (Column *) tree->columns;
+ while (column != NULL)
+ {
+ if ((column->tkfont == NULL) && (column->textLen > 0))
+ {
+ column->textWidth = Tk_TextWidth(tree->tkfont, column->text, column->textLen);
+ column->neededHeight = -1;
+ }
+ column = column->next;
+ }
+ tree->headerHeight = -1;
+ }
+}
+
+int Tree_HeaderHeight(TreeCtrl *tree)
+{
+ Column *column;
+ int height;
+
+ if (!tree->showHeader)
+ return 0;
+
+ if (tree->headerHeight >= 0)
+ return tree->headerHeight;
+
+ height = 0;
+ column = (Column *) tree->columns;
+ while (column != NULL)
+ {
+ if (column->visible)
+ height = MAX(height, TreeColumn_NeededHeight((TreeColumn) column));
+ column = column->next;
+ }
+ return tree->headerHeight = height;
+}
+
+int Tree_WidthOfColumns(TreeCtrl *tree)
+{
+ Column *column;
+ int width;
+
+ if (tree->widthOfColumns >= 0)
+ return tree->widthOfColumns;
+
+ Tree_LayoutColumns(tree);
+
+ tree->columnTreeLeft = 0;
+ tree->columnTreeVis = FALSE;
+ tree->columnVis = NULL;
+ tree->columnCountVis = 0;
+ width = 0;
+ column = (Column *) tree->columns;
+ while (column != NULL)
+ {
+ if (column->visible)
+ {
+ if (tree->columnVis == NULL)
+ tree->columnVis = (TreeColumn) column;
+ tree->columnCountVis++;
+ if (column->index == tree->columnTree)
+ {
+ tree->columnTreeLeft = width;
+ tree->columnTreeVis = TRUE;
+ }
+ width += column->useWidth;
+ }
+ column = column->next;
+ }
+
+ return tree->widthOfColumns = width;
+}
+
+void Tree_InitColumns(TreeCtrl *tree)
+{
+ tree->columnTail = (TreeColumn) Column_Alloc(tree);
+ tree->columnCount = 0;
+ ((Column *) tree->columnTail)->index = -1;
+}
+
+void Tree_FreeColumns(TreeCtrl *tree)
+{
+ Column *column = (Column *) tree->columns;
+
+ while (column != NULL)
+ column = Column_Free(column);
+
+ Column_Free((Column *) tree->columnTail);
+ tree->columnCount = 0;
+}
+
diff --git a/generic/tkTreeCtrl.c b/generic/tkTreeCtrl.c
new file mode 100644
index 0000000..5791998
--- /dev/null
+++ b/generic/tkTreeCtrl.c
@@ -0,0 +1,2988 @@
+#include "tkTreeCtrl.h"
+
+static CONST char *bgModeST[] = { "column", "index", "row", "visindex", (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_TABLE, "-backgroundmode", (char *) NULL, (char *) NULL,
+ "row", -1, Tk_Offset(TreeCtrl, backgroundMode),
+ 0, (ClientData) bgModeST, TREE_CONF_REDISPLAY},
+ {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
+ DEF_LISTBOX_BORDER_WIDTH, -1, Tk_Offset(TreeCtrl, borderWidth),
+ 0, (ClientData) NULL, TREE_CONF_RELAYOUT},
+ {TK_OPTION_COLOR, "-buttoncolor", (char *) NULL, (char *) NULL,
+ "#808080", -1, Tk_Offset(TreeCtrl, buttonColor),
+ 0, (ClientData) NULL, TREE_CONF_BUTTON | TREE_CONF_REDISPLAY},
+ {TK_OPTION_PIXELS, "-buttonsize", (char *) NULL, (char *) NULL,
+ "9", Tk_Offset(TreeCtrl, buttonSizeObj),
+ Tk_Offset(TreeCtrl, buttonSize),
+ 0, (ClientData) NULL, TREE_CONF_BUTTON | TREE_CONF_RELAYOUT},
+ {TK_OPTION_PIXELS, "-buttonthickness", (char *) NULL, (char *) NULL,
+ "1", Tk_Offset(TreeCtrl, buttonThicknessObj),
+ Tk_Offset(TreeCtrl, buttonThickness),
+ 0, (ClientData) NULL, TREE_CONF_BUTTON | TREE_CONF_REDISPLAY},
+ {TK_OPTION_BITMAP, "-closedbuttonbitmap", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(TreeCtrl, closedButtonBitmap),
+ TK_OPTION_NULL_OK, (ClientData) NULL,
+ TREE_CONF_BUTTON | TREE_CONF_BUTBMP_CLOSED | TREE_CONF_RELAYOUT},
+ {TK_OPTION_STRING, "-closedbuttonimage", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(TreeCtrl, closedButtonString),
+ TK_OPTION_NULL_OK, (ClientData) NULL,
+ TREE_CONF_BUTTON | TREE_CONF_BUTIMG_CLOSED | TREE_CONF_RELAYOUT},
+ {TK_OPTION_PIXELS, "-columnproxy", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(TreeCtrl, columnProxy.xObj),
+ Tk_Offset(TreeCtrl, columnProxy.x),
+ TK_OPTION_NULL_OK, (ClientData) NULL, TREE_CONF_PROXY},
+ {TK_OPTION_CURSOR, "-cursor", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(TreeCtrl, cursor),
+ TK_OPTION_NULL_OK, (ClientData) NULL, 0},
+ {TK_OPTION_STRING_TABLE, "-doublebuffer", (char *) NULL, (char *) NULL,
+ "item", -1, Tk_Offset(TreeCtrl, doubleBuffer),
+ 0, (ClientData) doubleBufferST, TREE_CONF_REDISPLAY},
+ {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", (char *) NULL, (char *) NULL,
+ DEF_LISTBOX_FG, Tk_Offset(TreeCtrl, fgObj), Tk_Offset(TreeCtrl, fgColorPtr),
+ 0, (ClientData) NULL, TREE_CONF_FG | TREE_CONF_REDISPLAY},
+ {TK_OPTION_PIXELS, "-height", "height", "Height",
+ "200", -1, Tk_Offset(TreeCtrl, height),
+ 0, (ClientData) NULL, 0},
+ {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, -1,
+ Tk_Offset(TreeCtrl, highlightWidth),
+ 0, (ClientData) NULL, 0},
+ {TK_OPTION_PIXELS, "-indent", (char *) NULL, (char *) NULL,
+ "19", -1, Tk_Offset(TreeCtrl, indent),
+ 0, (ClientData) NULL, TREE_CONF_INDENT | TREE_CONF_RELAYOUT},
+ {TK_OPTION_PIXELS, "-itemheight", "itemHeight", "ItemHeight",
+ "0", -1, Tk_Offset(TreeCtrl, itemHeight),
+ 0, (ClientData) NULL, TREE_CONF_ITEMHEIGHT | TREE_CONF_RELAYOUT},
+#if 0
+ {TK_OPTION_PIXELS, "-itempadw", (char *) NULL, (char *) NULL,
+ "0",
+ Tk_Offset(TreeCtrl, itemPadObj[LEFT]),
+ Tk_Offset(TreeCtrl, itemPad[LEFT]),
+ TK_CONFIG_NULL_OK, (ClientData) NULL, 0},
+ {TK_OPTION_PIXELS, "-itempadn", (char *) NULL, (char *) NULL,
+ "0",
+ Tk_Offset(TreeCtrl, itemPadObj[TOP]),
+ Tk_Offset(TreeCtrl, itemPad[TOP]),
+ TK_CONFIG_NULL_OK, (ClientData) NULL, 0},
+ {TK_OPTION_PIXELS, "-itempade", (char *) NULL, (char *) NULL,
+ "0",
+ Tk_Offset(TreeCtrl, itemPadObj[RIGHT]),
+ Tk_Offset(TreeCtrl, itemPad[RIGHT]),
+ TK_CONFIG_NULL_OK, (ClientData) NULL, 0},
+ {TK_OPTION_PIXELS, "-itempads", (char *) NULL, (char *) NULL,
+ "0",
+ Tk_Offset(TreeCtrl, itemPadObj[BOTTOM]),
+ Tk_Offset(TreeCtrl, itemPad[BOTTOM]),
+ TK_CONFIG_NULL_OK, (ClientData) NULL, 0},
+#endif
+ {TK_OPTION_COLOR, "-linecolor", (char *) NULL, (char *) NULL,
+ "#808080", -1, Tk_Offset(TreeCtrl, lineColor),
+ 0, (ClientData) NULL, TREE_CONF_LINE | TREE_CONF_REDISPLAY},
+ {TK_OPTION_STRING_TABLE, "-linestyle", (char *) NULL, (char *) NULL,
+ "dot", -1, Tk_Offset(TreeCtrl, lineStyle),
+ 0, (ClientData) lineStyleST, TREE_CONF_LINE | TREE_CONF_REDISPLAY},
+ {TK_OPTION_PIXELS, "-linethickness", (char *) NULL, (char *) NULL,
+ "1", Tk_Offset(TreeCtrl, lineThicknessObj),
+ Tk_Offset(TreeCtrl, lineThickness),
+ 0, (ClientData) NULL, TREE_CONF_LINE | TREE_CONF_REDISPLAY},
+ {TK_OPTION_BITMAP, "-openbuttonbitmap", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(TreeCtrl, openButtonBitmap),
+ TK_OPTION_NULL_OK, (ClientData) NULL,
+ TREE_CONF_BUTTON | TREE_CONF_BUTBMP_OPEN | TREE_CONF_RELAYOUT},
+ {TK_OPTION_STRING, "-openbuttonimage", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(TreeCtrl, openButtonString),
+ TK_OPTION_NULL_OK, (ClientData) NULL,
+ TREE_CONF_BUTTON | TREE_CONF_BUTIMG_OPEN | TREE_CONF_RELAYOUT},
+ {TK_OPTION_STRING_TABLE, "-orient", (char *) NULL, (char *) NULL,
+ "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_STRING, "-scrollmargin", (char *) NULL, (char *) NULL,
+ "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", (char *) NULL, (char *) NULL,
+ "1", -1, Tk_Offset(TreeCtrl, showHeader),
+ 0, (ClientData) NULL, TREE_CONF_RELAYOUT},
+ {TK_OPTION_BOOLEAN, "-showlines", "showLines",
+ "ShowLines", "1", -1, Tk_Offset(TreeCtrl, showLines),
+ 0, (ClientData) NULL, TREE_CONF_REDISPLAY},
+ {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_STRING, "-takefocus", "takeFocus", "TakeFocus",
+ DEF_LISTBOX_TAKE_FOCUS, -1, Tk_Offset(TreeCtrl, takeFocus),
+ TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_INT, "-treecolumn", (char *) NULL, (char *) NULL,
+ "0", -1, Tk_Offset(TreeCtrl, columnTree),
+ 0, (ClientData) NULL, TREE_CONF_RELAYOUT},
+ {TK_OPTION_PIXELS, "-width", "width", "Width",
+ "200", -1, Tk_Offset(TreeCtrl, width),
+ 0, (ClientData) NULL, 0},
+ {TK_OPTION_STRING, "-wrap", (char *) NULL, (char *) NULL,
+ (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", (char *) NULL, (char *) NULL,
+ "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_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
+ (char *) NULL, -1, Tk_Offset(TreeCtrl, yScrollCmd),
+ TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_STRING, "-yscrolldelay", (char *) NULL, (char *) NULL,
+ "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_END}
+};
+
+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_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_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, 0, 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 TreeStateCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]);
+static int TreeSelectionCmd(Tcl_Interp *interp, TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]);
+static int TreeXviewCmd(Tcl_Interp *interp, TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]);
+static int TreeYviewCmd(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. */
+};
+
+static int TreeObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree;
+ Tk_Window tkwin;
+ Tk_OptionTable optionTable;
+
+ 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;
+
+ tree->stateNames[0] = "open";
+ tree->stateNames[1] = "selected";
+ tree->stateNames[2] = "enabled";
+ tree->stateNames[3] = "active";
+ tree->stateNames[4] = "focus";
+
+ /* 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->elementHash, TCL_STRING_KEYS);
+ Tcl_InitHashTable(&tree->styleHash, TCL_STRING_KEYS);
+ Tcl_InitHashTable(&tree->imageHash, TCL_STRING_KEYS);
+
+ Tree_InitColumns(tree);
+
+ tree->root = TreeItem_AllocRoot(tree);
+ tree->activeItem = tree->root; /* always non-null */
+ tree->anchorItem = tree->root; /* always non-null */
+
+ TreeNotify_Init(tree);
+ TreeMarquee_Init(tree);
+ TreeDragImage_Init(tree);
+ TreeDInfo_Init(tree);
+
+ Tk_CreateEventHandler(tree->tkwin,
+ ExposureMask|StructureNotifyMask|FocusChangeMask,
+ TreeEventProc, (ClientData) tree);
+
+ /* Must do this on Unix because Tk_GCForColor() uses
+ * Tk_WindowId(tree->tkwin) */
+ Tk_MakeWindowExist(tree->tkwin);
+
+ if (Tk_InitOptions(interp, (char *) tree, optionTable, tkwin) != TCL_OK)
+ {
+ Tk_DestroyWindow(tree->tkwin);
+ WFREE(tree, TreeCtrl);
+ 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;
+}
+
+#define W2Cx(x) ((x) + tree->xOrigin)
+#define C2Wx(x) ((x) - tree->xOrigin)
+#define C2Ox(x) ((x) - tree->inset)
+
+#define W2Cy(y) ((y) + tree->yOrigin)
+#define C2Wy(y) ((y) - tree->yOrigin)
+#define C2Oy(y) ((y) - tree->inset - Tree_HeaderHeight(tree))
+
+static int TreeWidgetCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ int result = TCL_OK;
+ static CONST char *commandName[] = { "activate", "canvasx", "canvasy",
+ "cget", "collapse",
+ "column", "compare", "configure", "contentbox", "debug", "depth", "dragimage",
+ "element", "expand", "identify", "index", "item",
+ "marquee", "notify", "numcolumns", "numitems", "orphans",
+ "range", "see", "selection", "state", "style",
+ "toggle", "xview", "yview", (char *) NULL };
+ enum {
+ COMMAND_ACTIVATE, COMMAND_CANVASX, COMMAND_CANVASY, COMMAND_CGET,
+ COMMAND_COLLAPSE, COMMAND_COLUMN, COMMAND_COMPARE, COMMAND_CONFIGURE,
+ COMMAND_CONTENTBOX, COMMAND_DEBUG, COMMAND_DEPTH,
+ COMMAND_DRAGIMAGE, COMMAND_ELEMENT, COMMAND_EXPAND,COMMAND_IDENTIFY,
+ COMMAND_INDEX, COMMAND_ITEM, COMMAND_MARQUEE, COMMAND_NOTIFY,
+ COMMAND_NUMCOLUMNS, COMMAND_NUMITEMS, COMMAND_ORPHANS, COMMAND_RANGE,
+ COMMAND_SEE, COMMAND_SELECTION, COMMAND_STATE, COMMAND_STYLE,
+ COMMAND_TOGGLE, 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);
+
+ switch (index)
+ {
+ case COMMAND_ACTIVATE:
+ {
+ 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 != tree->activeItem)
+ {
+ TreeNotify_ActiveItem(tree, tree->activeItem, item);
+ TreeItem_ChangeState(tree, tree->activeItem, STATE_ACTIVE, 0);
+ tree->activeItem = item;
+ TreeItem_ChangeState(tree, tree->activeItem, 0, STATE_ACTIVE);
+ }
+ 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)
+ return TCL_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)
+ return TCL_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:
+ {
+ if (objc != 2)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
+ goto error;
+ }
+ FormatResult(interp, "%d %d %d %d",
+ tree->inset, tree->inset + Tree_HeaderHeight(tree),
+ Tk_Width(tree->tkwin) - tree->inset,
+ Tk_Height(tree->tkwin) - tree->inset);
+ break;
+ }
+
+ case COMMAND_COLLAPSE:
+ case COMMAND_EXPAND:
+ case COMMAND_TOGGLE:
+ {
+ char *s;
+ int i;
+ int recurse = 0;
+ TreeItem item;
+
+ if (objc < 2)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "options ?item...?");
+ goto error;
+ }
+ if (objc == 2)
+ break;
+ s = Tcl_GetString(objv[2]);
+ if (!strcmp(s, "-recurse"))
+ {
+ recurse = 1;
+ if (objc < 3)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "options ?item...?");
+ goto error;
+ }
+ }
+ for (i = 2 + recurse; i < objc; i++)
+ {
+ int oldRecurse = recurse;
+ if (TreeItem_FromObj(tree, objv[i], &item, IFO_ALLOK) != TCL_OK)
+ goto error;
+ if (item == ITEM_ALL)
+ {
+ item = tree->root;
+ recurse = 1;
+ }
+ switch (index)
+ {
+ case COMMAND_COLLAPSE:
+ TreeItem_OpenClose(tree, item, 0, recurse);
+ break;
+ case COMMAND_EXPAND:
+ TreeItem_OpenClose(tree, item, 1, recurse);
+ break;
+ case COMMAND_TOGGLE:
+ TreeItem_OpenClose(tree, item, -1, recurse);
+ break;
+ }
+ recurse = oldRecurse;
+ }
+#if 0
+ if (tree->debug.enable)
+ Tree_Debug(tree);
+#endif
+ break;
+ }
+
+ case COMMAND_COLUMN:
+ {
+ result = TreeColumnCmd(clientData, interp, objc, objv);
+ break;
+ }
+
+ 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, 0) != 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, 0) != TCL_OK)
+ goto error;
+ if (TreeItem_RootAncestor(tree, item1) !=
+ TreeItem_RootAncestor(tree, item2))
+ {
+ FormatResult(interp,
+ "item %d and item %d don't share a common ancestor",
+ TreeItem_GetID(tree, item1), 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;
+ }
+
+ case COMMAND_DEBUG:
+ {
+ result = TreeDebugCmd(clientData, interp, objc, objv);
+ break;
+ }
+
+ case COMMAND_DEPTH:
+ {
+ TreeItem item;
+
+ if (objc == 3)
+ {
+ if (TreeItem_FromObj(tree, objv[2], &item, 0) != TCL_OK)
+ goto error;
+ Tcl_SetObjResult(interp,
+ Tcl_NewIntObj(TreeItem_GetDepth(tree, item) + 1));
+ break;
+ }
+ if (tree->updateIndex)
+ Tree_UpdateItemIndex(tree);
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(tree->depth + 1));
+ break;
+ }
+
+ case COMMAND_DRAGIMAGE:
+ {
+ result = DragImageCmd(clientData, interp, objc, objv);
+ break;
+ }
+
+ case COMMAND_ELEMENT:
+ {
+ result = TreeElementCmd(clientData, interp, objc, objv);
+ break;
+ }
+
+ case COMMAND_IDENTIFY:
+ {
+ int x, y, depth;
+ TreeItem item;
+ char buf[64];
+/*
+ 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, "x y");
+ goto error;
+ }
+ if (Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK)
+ goto error;
+ if (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)
+ goto error;
+
+ /* Point in header */
+ if ((y >= tree->inset) && (y < tree->inset + Tree_HeaderHeight(tree)))
+ {
+ int left = 0 - tree->xOrigin, columnIndex = 0;
+ TreeColumn column = tree->columns;
+
+ while (column != NULL)
+ {
+ int width = TreeColumn_UseWidth(column);
+ if ((x >= left) && (x < left + width))
+ {
+ sprintf(buf, "header %d", columnIndex);
+ if (x < left + 4)
+ sprintf(buf + strlen(buf), " left");
+ else if (x >= left + width - 4)
+ sprintf(buf + strlen(buf), " right");
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ goto done;
+ }
+ left += width;
+ columnIndex++;
+ column = TreeColumn_Next(column);
+ }
+ strcpy(buf, "header tail");
+ if (x < left + 4)
+ sprintf(buf + strlen(buf), " left");
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ break;
+ }
+
+ item = Tree_ItemUnderPoint(tree, &x, &y, FALSE);
+ if (item == NULL)
+ break;
+
+ sprintf(buf, "item %d", TreeItem_GetID(tree, item)); /* TreeItem_ToObj() */
+ depth = TreeItem_GetDepth(tree, item);
+ if (tree->showRoot || tree->showButtons || tree->showLines)
+ depth++;
+ if (tree->showRoot && tree->showButtons && tree->showRootButton)
+ depth++;
+ if (item == tree->root)
+ depth = (tree->showButtons && tree->showRootButton) ? 1 : 0;
+
+ /* Point is in a line or button */
+ if ((x >= tree->columnTreeLeft) && (x < tree->columnTreeLeft + depth * tree->useIndent))
+ {
+ int column = (x - tree->columnTreeLeft) / tree->useIndent + 1;
+ if (column == depth)
+ {
+ if (tree->showButtons && TreeItem_GetButton(tree, item))
+ sprintf(buf + strlen(buf), " button");
+ }
+ else if (tree->showLines)
+ {
+ do {
+ item = TreeItem_GetParent(tree, item);
+ } while (++column < depth);
+ if (TreeItem_GetNextSibling(tree, item) != NULL)
+ sprintf(buf + strlen(buf), " line %d", TreeItem_GetID(tree, item)); /* TreeItem_ToObj() */
+ }
+ }
+
+ else if (tree->columnCountVis == 1)
+ {
+ char *elem;
+
+ sprintf(buf + strlen(buf), " column %d",
+ TreeColumn_Index(tree->columnVis));
+ elem = TreeItem_Identify(tree, item, x, y);
+ if (elem != NULL)
+ sprintf(buf + strlen(buf), " elem %s", elem);
+ }
+
+ /* Point is in a TreeItemColumn */
+ else
+ {
+ int left = 0;
+ TreeColumn treeColumn;
+ TreeItemColumn itemColumn;
+
+ treeColumn = tree->columns;
+ itemColumn = TreeItem_GetFirstColumn(tree, item);
+ while (itemColumn != NULL)
+ {
+ int width = TreeColumn_UseWidth(treeColumn);
+ if ((x >= left) && (x < left + width))
+ {
+ char *elem;
+ sprintf(buf + strlen(buf), " column %d",
+ TreeColumn_Index(treeColumn));
+ elem = TreeItem_Identify(tree, item, x, y);
+ if (elem != NULL)
+ sprintf(buf + strlen(buf), " elem %s", elem);
+ break;
+ }
+ left += width;
+ treeColumn = TreeColumn_Next(treeColumn);
+ itemColumn = TreeItemColumn_GetNext(tree, itemColumn);
+ }
+ }
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ break;
+ }
+
+ case COMMAND_INDEX:
+ {
+ TreeItem item;
+
+ if (objc != 3)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "item");
+ goto error;
+ }
+ if (TreeItem_FromObj(tree, objv[2], &item, IFO_NULLOK) != TCL_OK)
+ {
+ goto error;
+ }
+ if (item != NULL)
+ Tcl_SetObjResult(interp, TreeItem_ToObj(tree, item));
+ break;
+ }
+
+ 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;
+ }
+
+ case COMMAND_NUMCOLUMNS:
+ {
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(tree->columnCount));
+ break;
+ }
+
+ case COMMAND_NUMITEMS:
+ {
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(tree->itemCount));
+ break;
+ }
+
+ case COMMAND_ORPHANS:
+ {
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ Tcl_Obj *listObj;
+ TreeItem item;
+
+ /* 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;
+ }
+
+ case COMMAND_RANGE:
+ {
+ TreeItem item, itemFirst, itemLast;
+ int indexFirst, indexLast;
+ Tcl_Obj *listObj;
+
+ if (objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "first last");
+ goto error;
+ }
+ if (TreeItem_FromObj(tree, objv[2], &itemFirst, 0) != TCL_OK)
+ goto error;
+ if (TreeItem_FromObj(tree, objv[3], &itemLast, 0) != TCL_OK)
+ goto error;
+ if (TreeItem_RootAncestor(tree, itemFirst) !=
+ TreeItem_RootAncestor(tree, itemLast))
+ {
+ FormatResult(interp,
+ "item %d and item %d don't share a common ancestor",
+ TreeItem_GetID(tree, itemFirst), TreeItem_GetID(tree, itemLast));
+ goto error;
+ }
+ TreeItem_ToIndex(tree, itemFirst, &indexFirst, NULL);
+ TreeItem_ToIndex(tree, itemLast, &indexLast, NULL);
+ if (indexFirst > indexLast)
+ {
+ item = itemFirst;
+ itemFirst = itemLast;
+ itemLast = item;
+ }
+ 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;
+ }
+
+ case COMMAND_SEE:
+ {
+ TreeItem item;
+ int x, y, w, h;
+ int topInset = tree->inset + Tree_HeaderHeight(tree);
+ int visWidth = Tk_Width(tree->tkwin) - tree->inset * 2;
+ int visHeight = Tk_Height(tree->tkwin) - topInset - tree->inset;
+ int xOrigin = tree->xOrigin;
+ int yOrigin = tree->yOrigin;
+ int minX = tree->inset;
+ int minY = topInset;
+ int maxX = minX + visWidth;
+ int maxY = minY + visHeight;
+ int index, offset;
+
+ if (objc != 3)
+ {
+ Tcl_WrongNumArgs(interp, 2, objv, "item");
+ goto error;
+ }
+ if (TreeItem_FromObj(tree, objv[2], &item, 0) != TCL_OK)
+ goto error;
+ if (!TreeItem_ReallyVisible(tree, item))
+ break;
+
+ /* Canvas coords */
+ Tree_ItemBbox(tree, item, &x, &y, &w, &h);
+
+ 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);
+ }
+ }
+
+ 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);
+ break;
+ }
+
+ case COMMAND_SELECTION:
+ {
+ result = TreeSelectionCmd(interp, tree, objc, objv);
+ break;
+ }
+
+ case COMMAND_STATE:
+ {
+ result = TreeStateCmd(tree, objc, objv);
+ break;
+ }
+
+ case COMMAND_STYLE:
+ {
+ result = TreeStyleCmd(clientData, interp, objc, objv);
+ break;
+ }
+
+ case COMMAND_XVIEW:
+ {
+ result = TreeXviewCmd(interp, tree, objc, objv);
+ break;
+ }
+
+ case COMMAND_YVIEW:
+ {
+ result = TreeYviewCmd(interp, tree, objc, objv);
+ break;
+ }
+ }
+done:
+ Tcl_Release((ClientData) tree);
+ return result;
+
+error:
+ Tcl_Release((ClientData) tree);
+ return TCL_ERROR;
+}
+
+static int TreeConfigure(Tcl_Interp *interp, TreeCtrl *tree, int objc,
+ Tcl_Obj *CONST objv[], int createFlag)
+{
+ int error;
+ Tcl_Obj *errorResult = NULL;
+ TreeCtrl saved;
+ Tk_SavedOptions savedOptions;
+ int doubleBuffer = 1;
+ int oldShowRoot = tree->showRoot;
+ int mask;
+ XGCValues gcValues;
+ unsigned long gcMask;
+
+ for (error = 0; error <= 1; error++)
+ {
+ if (error == 0)
+ {
+ if (Tk_SetOptions(interp, (char *) tree, tree->optionTable, objc,
+ objv, tree->tkwin, &savedOptions, &mask) != TCL_OK)
+ {
+ mask = 0;
+ continue;
+ }
+
+ if (mask & TREE_CONF_BUTIMG_CLOSED)
+ {
+ saved.closedButtonImage = tree->closedButtonImage;
+ tree->closedButtonImage = NULL;
+ if (tree->closedButtonString != NULL)
+ {
+ Tk_Image image = Tree_GetImage(tree, tree->closedButtonString);
+ if (image == NULL)
+ continue;
+ tree->closedButtonImage = image;
+ }
+ }
+
+ if (mask & TREE_CONF_BUTIMG_OPEN)
+ {
+ saved.openButtonImage = tree->openButtonImage;
+ tree->openButtonImage = NULL;
+ if (tree->openButtonString != NULL)
+ {
+ Tk_Image image = Tree_GetImage(tree, tree->openButtonString);
+ if (image == NULL)
+ continue;
+ tree->openButtonImage = image;
+ }
+ }
+
+ /* Parse -wrap string into wrapMode and wrapArg */
+ if (mask & TREE_CONF_WRAP)
+ {
+ int listObjc;
+ Tcl_Obj **listObjv;
+
+ saved.wrapMode = tree->wrapMode;
+ saved.wrapArg = tree->wrapArg;
+
+ 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;
+ }
+ }
+ }
+
+ Tk_FreeSavedOptions(&savedOptions);
+ break;
+ }
+ else
+ {
+ errorResult = Tcl_GetObjResult(interp);
+ Tcl_IncrRefCount(errorResult);
+ Tk_RestoreSavedOptions(&savedOptions);
+
+ if (mask & TREE_CONF_BUTIMG_CLOSED)
+ {
+ tree->closedButtonImage = saved.closedButtonImage;
+ }
+
+ if (mask & TREE_CONF_BUTIMG_OPEN)
+ {
+ tree->openButtonImage = saved.openButtonImage;
+ }
+
+ if (mask & TREE_CONF_WRAP)
+ {
+ tree->wrapMode = saved.wrapMode;
+ tree->wrapArg = saved.wrapArg;
+ }
+
+ Tcl_SetObjResult(interp, errorResult);
+ Tcl_DecrRefCount(errorResult);
+ return TCL_ERROR;
+ }
+ }
+
+ Tk_SetWindowBackground(tree->tkwin,
+ Tk_3DBorderColor(tree->border)->pixel);
+
+ if (createFlag)
+ mask |= TREE_CONF_FONT;
+
+ if (mask & (TREE_CONF_FONT | TREE_CONF_FG))
+ {
+ 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);
+ }
+
+ if ((tree->copyGC == None) && (doubleBuffer))
+ {
+ gcValues.function = GXcopy;
+ gcValues.graphics_exposures = False;
+ gcMask = GCFunction | GCGraphicsExposures;
+ tree->copyGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues);
+ }
+
+ if (createFlag)
+ {
+ mask |= TREE_CONF_BUTTON;
+ tree->closedButtonWidth = tree->buttonSize;
+ tree->closedButtonHeight = tree->buttonSize;
+ }
+
+ 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 != None)
+ Tk_FreeGC(tree->display, tree->lineGC);
+ gcValues.foreground = tree->lineColor->pixel;
+ gcValues.line_width = tree->lineThickness;
+ gcMask = GCForeground | GCLineWidth;
+ tree->lineGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues);
+ }
+
+ if (mask & TREE_CONF_PROXY)
+ {
+ TreeColumnProxy_Undisplay(tree);
+ TreeColumnProxy_Display(tree);
+ }
+
+ if (mask & TREE_CONF_BUTBMP_CLOSED)
+ {
+ if (tree->buttonClosedGC != None)
+ {
+ Tk_FreeGC(tree->display, tree->buttonClosedGC);
+ tree->buttonClosedGC = None;
+ }
+ if (tree->closedButtonBitmap != None)
+ {
+ gcValues.clip_mask = tree->closedButtonBitmap;
+ gcValues.graphics_exposures = False;
+ gcMask = GCClipMask | GCGraphicsExposures;
+ tree->buttonClosedGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues);
+ }
+ }
+
+ if (mask & TREE_CONF_BUTBMP_OPEN)
+ {
+ if (tree->buttonOpenGC != None)
+ {
+ Tk_FreeGC(tree->display, tree->buttonOpenGC);
+ tree->buttonOpenGC = None;
+ }
+ if (tree->openButtonBitmap != None)
+ {
+ gcValues.clip_mask = tree->openButtonBitmap;
+ gcValues.graphics_exposures = False;
+ gcMask = GCClipMask | GCGraphicsExposures;
+ tree->buttonOpenGC = Tk_GetGC(tree->tkwin, gcMask, &gcValues);
+
+ Tk_SizeOfBitmap(tree->display, tree->openButtonBitmap,
+ &tree->openButtonWidth, &tree->openButtonHeight);
+ }
+ }
+
+ if (mask & (TREE_CONF_BUTIMG_CLOSED | TREE_CONF_BUTBMP_CLOSED))
+ {
+ if (tree->closedButtonImage != NULL)
+ {
+ Tk_SizeOfImage(tree->closedButtonImage,
+ &tree->closedButtonWidth, &tree->closedButtonHeight);
+ }
+ else if (tree->closedButtonBitmap != None)
+ {
+ Tk_SizeOfBitmap(tree->display, tree->closedButtonBitmap,
+ &tree->closedButtonWidth, &tree->closedButtonHeight);
+ }
+ else
+ {
+ tree->closedButtonWidth = tree->buttonSize;
+ tree->closedButtonHeight = tree->buttonSize;
+ }
+ }
+
+ if (mask & (TREE_CONF_BUTIMG_OPEN | TREE_CONF_BUTBMP_OPEN))
+ {
+ if (tree->openButtonImage != NULL)
+ {
+ Tk_SizeOfImage(tree->openButtonImage,
+ &tree->openButtonWidth, &tree->openButtonHeight);
+ }
+ else if (tree->openButtonBitmap != None)
+ {
+ Tk_SizeOfBitmap(tree->display, tree->openButtonBitmap,
+ &tree->openButtonWidth, &tree->openButtonHeight);
+ }
+ else
+ {
+ tree->openButtonWidth = tree->buttonSize;
+ tree->openButtonHeight = tree->buttonSize;
+ }
+ }
+
+ tree->useIndent = MAX(tree->closedButtonWidth, tree->openButtonWidth);
+ tree->useIndent = MAX(tree->indent, tree->useIndent);
+
+ if (tree->highlightWidth < 0)
+ tree->highlightWidth = 0;
+ tree->inset = tree->highlightWidth + tree->borderWidth;
+
+ if ((tree->columnTree < 0) || (tree->columnTree >= tree->columnCount))
+ tree->columnTree = 0;
+
+ if (oldShowRoot != tree->showRoot)
+ {
+ TreeItem_InvalidateHeight(tree, tree->root);
+ tree->updateIndex = 1;
+ }
+
+ TreeStyle_TreeChanged(tree, mask);
+ TreeColumn_TreeChanged(tree, mask);
+
+ if (mask & TREE_CONF_RELAYOUT)
+ {
+ TreeComputeGeometry(tree);
+ Tree_InvalidateColumnWidth(tree, -1);
+ Tree_RelayoutWindow(tree);
+ }
+
+ if (mask & TREE_CONF_REDISPLAY)
+ Tree_RelayoutWindow(tree);
+
+ return TCL_OK;
+}
+
+static void TreeWorldChanged(ClientData instanceData)
+{
+ 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);
+
+ TreeComputeGeometry(tree);
+ Tree_InvalidateColumnWidth(tree, -1);
+ Tree_RelayoutWindow(tree);
+}
+
+static void TreeEventProc(ClientData clientData, XEvent *eventPtr)
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+
+ if (eventPtr->type == Expose)
+ {
+ int x = eventPtr->xexpose.x;
+ int y = eventPtr->xexpose.y;
+ Tree_RedrawArea(tree, x, y,
+ x + eventPtr->xexpose.width,
+ y + eventPtr->xexpose.height);
+ }
+ else if (eventPtr->type == ConfigureNotify)
+ {
+ if ((tree->prevWidth != Tk_Width(tree->tkwin)) ||
+ (tree->prevHeight != Tk_Height(tree->tkwin)))
+ {
+ tree->widthOfColumns = -1;
+ Tree_RelayoutWindow(tree);
+ tree->prevWidth = Tk_Width(tree->tkwin);
+ tree->prevHeight = Tk_Height(tree->tkwin);
+ }
+ }
+ else if (eventPtr->type == FocusIn)
+ {
+ if (eventPtr->xfocus.detail != NotifyInferior)
+ Tree_FocusChanged(tree, 1);
+ }
+ else if (eventPtr->type == FocusOut)
+ {
+ if (eventPtr->xfocus.detail != NotifyInferior)
+ Tree_FocusChanged(tree, 0);
+ }
+ else if (eventPtr->type == DestroyNotify)
+ {
+ if (!tree->deleted)
+ {
+ tree->deleted = 1;
+ Tcl_DeleteCommandFromToken(tree->interp, tree->widgetCmd);
+ Tcl_EventuallyFree((ClientData) tree, TreeDestroy);
+ }
+ }
+}
+
+static void TreeCmdDeletedProc(ClientData clientData)
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+
+ if (!tree->deleted)
+ {
+ Tk_DestroyWindow(tree->tkwin);
+ }
+}
+
+static void TreeDestroy(char *memPtr)
+{
+ TreeCtrl *tree = (TreeCtrl *) memPtr;
+ TreeItem item;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ Tk_Image image;
+ int i;
+
+ 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);
+
+ hPtr = Tcl_FirstHashEntry(&tree->imageHash, &search);
+ while (hPtr != NULL)
+ {
+ image = (Tk_Image) Tcl_GetHashValue(hPtr);
+ Tk_FreeImage(image);
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ Tcl_DeleteHashTable(&tree->imageHash);
+
+ TreeStyle_Free(tree);
+
+ TreeDragImage_Free(tree->dragImage);
+ TreeMarquee_Free(tree->marquee);
+ TreeDInfo_Free(tree);
+
+ if (tree->copyGC != None)
+ Tk_FreeGC(tree->display, tree->copyGC);
+ if (tree->textGC != None)
+ Tk_FreeGC(tree->display, tree->textGC);
+ if (tree->buttonGC != None)
+ Tk_FreeGC(tree->display, tree->buttonGC);
+ if (tree->lineGC != None)
+ Tk_FreeGC(tree->display, tree->lineGC);
+ if (tree->buttonClosedGC != None)
+ Tk_FreeGC(tree->display, tree->buttonClosedGC);
+ if (tree->buttonOpenGC != None)
+ Tk_FreeGC(tree->display, tree->buttonOpenGC);
+
+ Tree_FreeColumns(tree);
+
+ QE_DeleteBindingTable(tree->bindingTable);
+
+ for (i = STATE_USER - 1; i < 32; i++)
+ if (tree->stateNames[i] != NULL)
+ ckfree(tree->stateNames[i]);
+
+ Tk_FreeConfigOptions((char *) tree, tree->debug.optionTable,
+ tree->tkwin);
+
+ Tk_FreeConfigOptions((char *) tree, tree->optionTable, tree->tkwin);
+
+ WFREE(tree, TreeCtrl);
+}
+
+void Tree_UpdateScrollbarX(TreeCtrl *tree)
+{
+ Tcl_Interp *interp = tree->interp;
+ int result;
+ double fractions[2];
+ char buffer[TCL_DOUBLE_SPACE * 2];
+ 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);
+ sprintf(buffer, "%g %g", fractions[0], fractions[1]);
+ result = Tcl_VarEval(interp, xScrollCmd, " ", buffer, (char *) NULL);
+ if (result != TCL_OK)
+ Tcl_BackgroundError(interp);
+ Tcl_ResetResult(interp);
+ Tcl_Release((ClientData) xScrollCmd);
+
+ Tcl_Release((ClientData) tree);
+ Tcl_Release((ClientData) interp);
+}
+
+void Tree_UpdateScrollbarY(TreeCtrl *tree)
+{
+ Tcl_Interp *interp = tree->interp;
+ int result;
+ double fractions[2];
+ char buffer[TCL_DOUBLE_SPACE * 2];
+ 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);
+ sprintf(buffer, "%g %g", fractions[0], fractions[1]);
+ result = Tcl_VarEval(interp, yScrollCmd, " ", buffer, (char *) NULL);
+ if (result != TCL_OK)
+ Tcl_BackgroundError(interp);
+ Tcl_ResetResult(interp);
+ Tcl_Release((ClientData) yScrollCmd);
+
+ Tcl_Release((ClientData) tree);
+ Tcl_Release((ClientData) interp);
+}
+
+static void TreeComputeGeometry(TreeCtrl *tree)
+{
+ Tk_SetInternalBorder(tree->tkwin, tree->inset);
+ Tk_GeometryRequest(tree->tkwin, tree->width + tree->inset * 2,
+ tree->height + tree->inset * 2);
+}
+
+void Tree_AddItem(TreeCtrl *tree, TreeItem item)
+{
+ Tcl_HashEntry *hPtr;
+ int id, isNew;
+
+ id = TreeItem_SetID(tree, item, tree->nextItemId++);
+ hPtr = Tcl_CreateHashEntry(&tree->itemHash, (char *) id, &isNew);
+ Tcl_SetHashValue(hPtr, item);
+ tree->itemCount++;
+}
+
+void Tree_RemoveItem(TreeCtrl *tree, TreeItem item)
+{
+ Tcl_HashEntry *hPtr;
+
+ if (TreeItem_GetSelected(tree, item))
+ Tree_RemoveFromSelection(tree, item);
+
+ hPtr = Tcl_FindHashEntry(&tree->itemHash,
+ (char *) TreeItem_GetID(tree, item));
+ Tcl_DeleteHashEntry(hPtr);
+ tree->itemCount--;
+ if (tree->itemCount == 1)
+ tree->nextItemId = TreeItem_GetID(tree, tree->root) + 1;
+}
+
+/* Called when Tk_Image is deleted or modified */
+static void ImageChangedProc(
+ ClientData clientData,
+ int x, int y,
+ int width, int height,
+ int imageWidth, int imageHeight)
+{
+ /* I would like to know the image was deleted... */
+}
+
+Tk_Image Tree_GetImage(TreeCtrl *tree, char *imageName)
+{
+ Tcl_HashEntry *hPtr;
+ Tk_Image image;
+ int isNew;
+
+ hPtr = Tcl_CreateHashEntry(&tree->imageHash, imageName, &isNew);
+ if (isNew)
+ {
+ image = Tk_GetImage(tree->interp, tree->tkwin, imageName,
+ ImageChangedProc, (ClientData) tree);
+ if (image == NULL)
+ {
+ Tcl_DeleteHashEntry(hPtr);
+ return NULL;
+ }
+ Tcl_SetHashValue(hPtr, image);
+ }
+ return (Tk_Image) Tcl_GetHashValue(hPtr);
+}
+
+static int TreeStateCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[])
+{
+ Tcl_Interp *interp = tree->interp;
+ static CONST char *commandName[] = { "define", "undefine", "names",
+ (char *) NULL };
+ enum {
+ COMMAND_DEFINE, COMMAND_UNDEFINE, COMMAND_NAMES
+ };
+ 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);
+ for (i = 0; i < 32; i++)
+ {
+ if (tree->stateNames[i] == NULL)
+ {
+ if (slot == -1)
+ slot = i;
+ continue;
+ }
+ if (strcmp(tree->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;
+ }
+ tree->stateNames[slot] = ckalloc(length + 1);
+ strcpy(tree->stateNames[slot], string);
+ break;
+ }
+
+ case COMMAND_NAMES:
+ {
+ Tcl_Obj *listObj;
+ int i;
+
+ if (tree->stateNames == NULL)
+ break;
+ listObj = Tcl_NewListObj(0, NULL);
+ for (i = STATE_USER - 1; i < 32; i++)
+ {
+ if (tree->stateNames[i] != NULL)
+ Tcl_ListObjAppendElement(interp, listObj,
+ Tcl_NewStringObj(tree->stateNames[i], -1));
+ }
+ Tcl_SetObjResult(interp, listObj);
+ break;
+ }
+
+ case COMMAND_UNDEFINE:
+ {
+ char *string;
+ int i, length;
+
+ if (objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "stateName");
+ return TCL_ERROR;
+ }
+ string = Tcl_GetStringFromObj(objv[3], &length);
+ for (i = 0; i < 32; i++)
+ {
+ if (tree->stateNames[i] == NULL)
+ continue;
+ if (strcmp(tree->stateNames[i], string) == 0)
+ break;
+ }
+ if (i < STATE_USER - 1)
+ {
+ FormatResult(interp, "state \"%s\" cannot be undefined",
+ string);
+ return TCL_ERROR;
+ }
+ if (i == 32)
+ {
+ FormatResult(interp, "unknown state \"%s\"", string);
+ return TCL_ERROR;
+ }
+ TreeStyle_UndefineState(tree, 1L << i);
+ ckfree(tree->stateNames[i]);
+ tree->stateNames[i] = NULL;
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
+
+void Tree_AddToSelection(TreeCtrl *tree, TreeItem item)
+{
+ if (TreeItem_GetSelected(tree, item))
+ panic("Tree_AddToSelection: item %d already selected",
+ TreeItem_GetID(tree, item));
+ TreeItem_ChangeState(tree, item, 0, STATE_SELECTED);
+ tree->selectCount++;
+}
+
+void Tree_RemoveFromSelection(TreeCtrl *tree, TreeItem item)
+{
+ if (!TreeItem_GetSelected(tree, item))
+ panic("Tree_RemoveFromSelection: item %d isn't selected",
+ TreeItem_GetID(tree, item));
+ TreeItem_ChangeState(tree, item, STATE_SELECTED, 0);
+ tree->selectCount--;
+}
+
+static int TreeSelectionCmd(Tcl_Interp *interp, TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[])
+{
+ 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;
+ 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 indexFirst, indexLast, count;
+ TreeItem staticItems[20], *items = staticItems;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+
+ if (objc < 4 || objc > 5)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "first ?last?");
+ return TCL_ERROR;
+ }
+ if (TreeItem_FromObj(tree, objv[3], &itemFirst, IFO_ALLOK) != TCL_OK)
+ return TCL_ERROR;
+ itemLast = NULL;
+ if (objc == 5)
+ {
+ if (TreeItem_FromObj(tree, objv[4], &itemLast, IFO_ALLOK) != TCL_OK)
+ return TCL_ERROR;
+ if (TreeItem_RootAncestor(tree, itemFirst) !=
+ TreeItem_RootAncestor(tree, itemLast))
+ {
+ FormatResult(interp,
+ "item %d and item %d don't share a common ancestor",
+ TreeItem_GetID(tree, itemFirst),
+ TreeItem_GetID(tree, itemLast));
+ return TCL_ERROR;
+ }
+ }
+ if ((itemFirst == ITEM_ALL) || (itemLast == ITEM_ALL))
+ {
+ count = tree->itemCount - tree->selectCount;
+ if (count + 1 > sizeof(staticItems) / sizeof(staticItems[0]))
+ items = (TreeItem *) ckalloc(sizeof(TreeItem) * (count + 1));
+ count = 0;
+
+ /* Include detached items */
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ if (!TreeItem_GetSelected(tree, item))
+ {
+ Tree_AddToSelection(tree, item);
+ items[count++] = item;
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ goto doneADD;
+ }
+ if (objc == 4)
+ {
+ itemLast = itemFirst;
+ count = 1;
+ }
+ else
+ {
+ TreeItem_ToIndex(tree, itemFirst, &indexFirst, NULL);
+ TreeItem_ToIndex(tree, itemLast, &indexLast, NULL);
+ if (indexFirst > indexLast)
+ {
+ item = itemFirst;
+ itemFirst = itemLast;
+ itemLast = item;
+
+ index = indexFirst;
+ indexFirst = indexLast;
+ indexLast = index;
+ }
+ count = indexLast - indexFirst + 1;
+ }
+ if (count + 1 > sizeof(staticItems) / sizeof(staticItems[0]))
+ items = (TreeItem *) ckalloc(sizeof(TreeItem) * (count + 1));
+ count = 0;
+ item = itemFirst;
+ while (item != NULL)
+ {
+ if (!TreeItem_GetSelected(tree, item))
+ {
+ Tree_AddToSelection(tree, item);
+ items[count++] = item;
+ }
+ if (item == itemLast)
+ break;
+ item = TreeItem_Next(tree, item);
+ }
+doneADD:
+ if (count)
+ {
+ items[count] = NULL;
+ TreeNotify_Selection(tree, items, NULL);
+ }
+ if (items != staticItems)
+ ckfree((char *) items);
+ break;
+ }
+
+ case COMMAND_ANCHOR:
+ {
+ if (objc != 3 && objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "?index?");
+ return TCL_ERROR;
+ }
+ if (objc == 4)
+ {
+ if (TreeItem_FromObj(tree, objv[3], &item, 0) != TCL_OK)
+ {
+ return TCL_ERROR;
+ }
+ tree->anchorItem = item;
+ }
+ Tcl_SetObjResult(interp, TreeItem_ToObj(tree, tree->anchorItem));
+ break;
+ }
+
+ case COMMAND_CLEAR:
+ {
+ int indexFirst, indexLast, count;
+ TreeItem staticItems[20], *items = staticItems;
+ 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 (TreeItem_FromObj(tree, objv[3], &itemFirst, IFO_ALLOK) != TCL_OK)
+ return TCL_ERROR;
+ }
+ if (objc == 5)
+ {
+ if (TreeItem_FromObj(tree, objv[4], &itemLast, IFO_ALLOK) != TCL_OK)
+ return TCL_ERROR;
+ if (TreeItem_RootAncestor(tree, itemFirst) !=
+ TreeItem_RootAncestor(tree, itemLast))
+ {
+ FormatResult(interp,
+ "item %d and item %d don't share a common ancestor",
+ TreeItem_GetID(tree, itemFirst),
+ TreeItem_GetID(tree, itemLast));
+ return TCL_ERROR;
+ }
+ }
+ if ((objc == 3) || (itemFirst == ITEM_ALL) || (itemLast == ITEM_ALL))
+ {
+ count = tree->selectCount;
+ if (count + 1 > sizeof(staticItems) / sizeof(staticItems[0]))
+ items = (TreeItem *) ckalloc(sizeof(TreeItem) * (count + 1));
+ count = 0;
+
+ /* Include detached items */
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ if (TreeItem_GetSelected(tree, item))
+ {
+ Tree_RemoveFromSelection(tree, item);
+ items[count++] = item;
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ goto doneCLEAR;
+ }
+ if (objc == 4)
+ {
+ itemLast = itemFirst;
+ count = 1;
+ }
+ else
+ {
+ TreeItem_ToIndex(tree, itemFirst, &indexFirst, NULL);
+ TreeItem_ToIndex(tree, itemLast, &indexLast, NULL);
+ if (indexFirst > indexLast)
+ {
+ item = itemFirst;
+ itemFirst = itemLast;
+ itemLast = item;
+
+ index = indexFirst;
+ indexFirst = indexLast;
+ indexLast = index;
+ }
+ count = indexLast - indexFirst + 1;
+ }
+ if (count + 1 > sizeof(staticItems) / sizeof(staticItems[0]))
+ items = (TreeItem *) ckalloc(sizeof(TreeItem) * (count + 1));
+ count = 0;
+ item = itemFirst;
+ while (item != NULL)
+ {
+ if (TreeItem_GetSelected(tree, item))
+ {
+ Tree_RemoveFromSelection(tree, item);
+ items[count++] = item;
+ }
+ if (item == itemLast)
+ break;
+ item = TreeItem_Next(tree, item);
+ }
+doneCLEAR:
+ if (count)
+ {
+ items[count] = NULL;
+ TreeNotify_Selection(tree, NULL, items);
+ }
+ if (items != staticItems)
+ ckfree((char *) 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;
+
+ if (objc != 3)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (tree->selectCount < 1)
+ break;
+ listObj = Tcl_NewListObj(0, NULL);
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ if (TreeItem_GetSelected(tree, item))
+ {
+ 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, "index");
+ return TCL_ERROR;
+ }
+ if (TreeItem_FromObj(tree, objv[3], &item, 0) != TCL_OK)
+ return TCL_ERROR;
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
+ TreeItem_GetSelected(tree, item)));
+ break;
+ }
+
+ case COMMAND_MODIFY:
+ {
+ int i, j, count, objcS, objcD;
+ Tcl_Obj **objvS, **objvD;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ TreeItem item;
+#define STATIC_SIZE 20
+ TreeItem staticItemS[STATIC_SIZE], *itemS = staticItemS;
+ TreeItem staticItemD[STATIC_SIZE], *itemD = staticItemD;
+ TreeItem staticNewS[STATIC_SIZE], *newS = staticNewS;
+ TreeItem staticNewD[STATIC_SIZE], *newD = staticNewD;
+ int allS = FALSE, allD = FALSE;
+ int countS, countD;
+
+ 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;
+
+ /* List of items to select */
+ if (objcS > 0)
+ {
+ if (objcS > STATIC_SIZE)
+ itemS = (TreeItem *) ckalloc(sizeof(TreeItem) * objcS);
+ for (i = 0; i < objcS; i++)
+ {
+ if (TreeItem_FromObj(tree, objvS[i], &itemS[i], IFO_ALLOK) != TCL_OK)
+ {
+ if (itemS != staticItemS)
+ ckfree((char *) itemS);
+ return TCL_ERROR;
+ }
+ if (itemS[i] == ITEM_ALL)
+ {
+ if (itemS != staticItemS)
+ ckfree((char *) itemS);
+ allS = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Select all */
+ if (allS)
+ {
+ count = tree->itemCount - tree->selectCount;
+ if (count + 1 > STATIC_SIZE)
+ newS = (TreeItem *) ckalloc(sizeof(TreeItem) * (count + 1));
+ count = 0;
+
+ /* Include detached items */
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ if (!TreeItem_GetSelected(tree, item))
+ {
+ Tree_AddToSelection(tree, item);
+ newS[count++] = item;
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ if (count)
+ {
+ newS[count] = NULL;
+ TreeNotify_Selection(tree, newS, NULL);
+ }
+ if (newS != staticNewS)
+ ckfree((char *) newS);
+ break;
+ }
+
+ /* Select some, deselect none */
+ if ((objcS > 0) && (objcD == 0))
+ {
+ if (objcS + 1 > STATIC_SIZE)
+ newS = (TreeItem *) ckalloc(sizeof(TreeItem) * (objcS + 1));
+ count = 0;
+ for (i = 0; i < objcS; i++)
+ {
+ item = itemS[i];
+ if (TreeItem_GetSelected(tree, item))
+ continue;
+ /* Add unique item to newly-selected list */
+ for (j = 0; j < count; j++)
+ if (newS[j] == item)
+ break;
+ if (j == count)
+ {
+ Tree_AddToSelection(tree, item);
+ newS[count++] = item;
+ }
+ }
+ if (count)
+ {
+ newS[count] = NULL;
+ TreeNotify_Selection(tree, newS, NULL);
+ }
+ if (newS != staticNewS)
+ ckfree((char *) newS);
+ if (itemS != staticItemS)
+ ckfree((char *) itemS);
+ break;
+ }
+
+ /* Nothing to deselect */
+ if (objcD == 0)
+ break;
+
+ /* List of items to deselect */
+ if (objcD > STATIC_SIZE)
+ itemD = (TreeItem *) ckalloc(sizeof(TreeItem) * objcD);
+ for (i = 0; i < objcD; i++)
+ {
+ if (TreeItem_FromObj(tree, objvD[i], &itemD[i], IFO_ALLOK) != TCL_OK)
+ {
+ if (itemS != staticItemS)
+ ckfree((char *) itemS);
+ if (itemD != staticItemD)
+ ckfree((char *) itemD);
+ return TCL_ERROR;
+ }
+ if (itemD[i] == ITEM_ALL)
+ {
+ allD = TRUE;
+ break;
+ }
+ }
+
+ /* Select none, Deselect all */
+ if ((objcS == 0) && allD)
+ {
+ count = tree->selectCount;
+ if (count + 1 > STATIC_SIZE)
+ newD = (TreeItem *) ckalloc(sizeof(TreeItem) * (count + 1));
+ count = 0;
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ if (TreeItem_GetSelected(tree, item))
+ {
+ Tree_RemoveFromSelection(tree, item);
+ newD[count++] = item;
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ if (count)
+ {
+ newD[count] = NULL;
+ TreeNotify_Selection(tree, NULL, newD);
+ }
+ if (newD != staticNewD)
+ ckfree((char *) newD);
+ break;
+ }
+
+ /* Select none, deselect some */
+ if ((objcS == 0) && !allD)
+ {
+ if (objcD + 1 > STATIC_SIZE)
+ newD = (TreeItem *) ckalloc(sizeof(TreeItem) * (objcD + 1));
+ count = 0;
+ for (i = 0; i < objcD; i++)
+ {
+ item = itemD[i];
+ if (!TreeItem_GetSelected(tree, item))
+ continue;
+ /* Add unique item to newly-deselected list */
+ for (j = 0; j < count; j++)
+ if (newD[j] == item)
+ break;
+ if (j == count)
+ {
+ Tree_RemoveFromSelection(tree, item);
+ newD[count++] = item;
+ }
+ }
+ if (count)
+ {
+ newD[count] = NULL;
+ TreeNotify_Selection(tree, NULL, newD);
+ }
+ if (newD != staticNewD)
+ ckfree((char *) newD);
+ if (itemD != staticItemD)
+ ckfree((char *) itemD);
+ break;
+ }
+
+ /* Select some, deselect some */
+ if ((objcS > 0) && !allD)
+ {
+ if (objcS + 1 > STATIC_SIZE)
+ newS = (TreeItem *) ckalloc(sizeof(TreeItem) * (objcS + 1));
+ if (objcD + 1 > STATIC_SIZE)
+ newD = (TreeItem *) ckalloc(sizeof(TreeItem) * (objcD + 1));
+ countS = 0;
+ for (i = 0; i < objcS; i++)
+ {
+ item = itemS[i];
+ if (TreeItem_GetSelected(tree, item))
+ continue;
+ /* Add unique item to newly-selected list */
+ for (j = 0; j < countS; j++)
+ if (newS[j] == item)
+ break;
+ if (j == countS)
+ {
+ Tree_AddToSelection(tree, item);
+ newS[countS++] = item;
+ }
+ }
+ countD = 0;
+ for (i = 0; i < objcD; i++)
+ {
+ item = itemD[i];
+ if (!TreeItem_GetSelected(tree, item))
+ continue;
+ /* Don't deselect an item in the selected list */
+ for (j = 0; j < objcS; j++)
+ if (item == itemS[j])
+ break;
+ if (j != objcS)
+ continue;
+ /* Add unique item to newly-deselected list */
+ for (j = 0; j < countD; j++)
+ if (newD[j] == item)
+ break;
+ if (j == countD)
+ {
+ Tree_RemoveFromSelection(tree, item);
+ newD[countD++] = item;
+ }
+ }
+ if (countS || countD)
+ {
+ newS[countS] = NULL;
+ newD[countD] = NULL;
+ TreeNotify_Selection(tree, newS, newD);
+ }
+ if (newS != staticNewS)
+ ckfree((char *) newS);
+ if (itemS != staticItemS)
+ ckfree((char *) itemS);
+ if (newD != staticNewD)
+ ckfree((char *) newD);
+ if (itemD != staticItemD)
+ ckfree((char *) itemD);
+ break;
+ }
+
+ /* Select some, deselect all */
+ countD = tree->selectCount;
+ if (countD + 1 > STATIC_SIZE)
+ newD = (TreeItem *) ckalloc(sizeof(TreeItem) * (countD + 1));
+ countD = 0;
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ if (TreeItem_GetSelected(tree, item))
+ {
+ /* Don't deselect an item in the selected list */
+ for (j = 0; j < objcS; j++)
+ if (item == itemS[j])
+ break;
+ if (j == objcS)
+ {
+ Tree_RemoveFromSelection(tree, item);
+ newD[countD++] = item;
+ }
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ if (objcS + 1 > STATIC_SIZE)
+ newS = (TreeItem *) ckalloc(sizeof(TreeItem) * (objcS + 1));
+ countS = 0;
+ for (i = 0; i < objcS; i++)
+ {
+ item = itemS[i];
+ if (TreeItem_GetSelected(tree, item))
+ continue;
+ /* Add unique item to newly-selected list */
+ for (j = 0; j < countS; j++)
+ if (newS[j] == item)
+ break;
+ if (j == countS)
+ {
+ Tree_AddToSelection(tree, item);
+ newS[countS++] = item;
+ }
+ }
+ if (countS || countD)
+ {
+ newS[countS] = NULL;
+ newD[countD] = NULL;
+ TreeNotify_Selection(tree, newS, newD);
+ }
+ if (newS != staticNewS)
+ ckfree((char *) newS);
+ if (itemS != staticItemS)
+ ckfree((char *) itemS);
+ if (newD != staticNewD)
+ ckfree((char *) newD);
+ if (itemD != staticItemD)
+ ckfree((char *) itemD);
+
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
+
+static int A_XviewCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[])
+{
+ Tcl_Interp *interp = tree->interp;
+
+ if (objc == 2)
+ {
+ double fractions[2];
+ char buf[TCL_DOUBLE_SPACE * 2];
+
+ Tree_GetScrollFractionsX(tree, fractions);
+ sprintf(buf, "%g %g", fractions[0], fractions[1]);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ }
+ else
+ {
+ int count, index = 0, indexMax, offset, type;
+ double fraction;
+ int visWidth = Tk_Width(tree->tkwin) - 2 * tree->inset;
+ int totWidth = Tree_TotalWidth(tree);
+ int xIncr = tree->xScrollIncrement;
+
+ if (totWidth <= visWidth)
+ return TCL_OK;
+
+ if (visWidth > 1)
+ {
+ /* Find incrementLeft when scrolled to extreme right */
+ indexMax = Increment_FindX(tree, totWidth - visWidth);
+ offset = Increment_ToOffsetX(tree, indexMax);
+ if (offset < totWidth - visWidth)
+ {
+ indexMax++;
+ offset = Increment_ToOffsetX(tree, indexMax);
+ }
+
+ /* Add some fake content to right */
+ if (offset + visWidth > totWidth)
+ totWidth = offset + visWidth;
+ }
+ else
+ {
+ indexMax = Increment_FindX(tree, totWidth);
+ visWidth = 1;
+ }
+
+ type = Tk_GetScrollInfoObj(interp, objc, objv, &fraction, &count);
+ 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 = tree->inset + tree->xOrigin;
+ offset += (int) (count * visWidth * 0.9);
+ index = Increment_FindX(tree, offset);
+ break;
+ case TK_SCROLL_UNITS:
+ offset = tree->inset + tree->xOrigin;
+ index = offset / xIncr;
+ 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 (offset - tree->inset != tree->xOrigin)
+ {
+ tree->xOrigin = offset - tree->inset;
+ Tree_EventuallyRedraw(tree);
+ }
+ }
+ return TCL_OK;
+}
+
+static int A_YviewCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[])
+{
+ Tcl_Interp *interp = tree->interp;
+
+ if (objc == 2)
+ {
+ double fractions[2];
+ char buf[TCL_DOUBLE_SPACE * 2];
+
+ Tree_GetScrollFractionsY(tree, fractions);
+ sprintf(buf, "%g %g", fractions[0], fractions[1]);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ }
+ else
+ {
+ int count, index = 0, indexMax, offset, type;
+ double fraction;
+ int topInset = tree->inset + Tree_HeaderHeight(tree);
+ int visHeight = Tk_Height(tree->tkwin) - topInset - tree->inset;
+ int totHeight = Tree_TotalHeight(tree);
+ int yIncr = tree->yScrollIncrement;
+
+ if (totHeight <= visHeight)
+ return TCL_OK;
+
+ if (visHeight > 1)
+ {
+ /* Find incrementTop when scrolled to bottom */
+ indexMax = Increment_FindY(tree, totHeight - visHeight);
+ offset = Increment_ToOffsetY(tree, indexMax);
+ if (offset < totHeight - visHeight)
+ {
+ indexMax++;
+ offset = Increment_ToOffsetY(tree, indexMax);
+ }
+
+ /* Add some fake content to bottom */
+ if (offset + visHeight > totHeight)
+ totHeight = offset + visHeight;
+ }
+ else
+ {
+ indexMax = Increment_FindY(tree, totHeight);
+ visHeight = 1;
+ }
+
+ type = Tk_GetScrollInfoObj(interp, objc, objv, &fraction, &count);
+ 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 = topInset + tree->yOrigin;
+ offset += (int) (count * visHeight * 0.9);
+ index = Increment_FindY(tree, offset);
+ break;
+ case TK_SCROLL_UNITS:
+ offset = topInset + tree->yOrigin;
+ index = offset / yIncr;
+ 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_ToOffsetY(tree, index);
+ if (offset - topInset != tree->yOrigin)
+ {
+ tree->yOrigin = offset - topInset;
+ Tree_EventuallyRedraw(tree);
+ }
+ }
+ return TCL_OK;
+}
+
+static int TreeXviewCmd(Tcl_Interp *interp, TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[])
+{
+#ifdef INCREMENTS
+ if (tree->xScrollIncrement <= 0)
+ return B_XviewCmd(tree, objc, objv);
+#endif
+ return A_XviewCmd(tree, objc, objv);
+}
+
+static int TreeYviewCmd(Tcl_Interp *interp, TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[])
+{
+#ifdef INCREMENTS
+ if (tree->yScrollIncrement <= 0)
+ return B_YviewCmd(tree, objc, objv);
+#endif
+ return A_YviewCmd(tree, objc, objv);
+}
+
+void Tree_Debug(TreeCtrl *tree)
+{
+ if (TreeItem_Debug(tree, tree->root) != TCL_OK)
+ {
+ dbwin("Tree_Debug: %s\n", Tcl_GetStringResult(tree->interp));
+ Tcl_BackgroundError(tree->interp);
+ }
+}
+
+static int TreeDebugCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ static CONST char *commandNames[] = { "cget", "configure", "dinfo",
+ "scroll", (char *) NULL };
+ enum { COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DINFO, COMMAND_SCROLL };
+ 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 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));
+ }
+ break;
+ }
+
+ case COMMAND_DINFO:
+ {
+ extern void DumpDInfo(TreeCtrl *tree);
+ DumpDInfo(tree);
+ break;
+ }
+
+ case COMMAND_SCROLL:
+ {
+ int topInset = Tree_HeaderHeight(tree) + tree->inset;
+ int visHeight = Tk_Height(tree->tkwin) - topInset - tree->inset;
+ int totHeight = Tree_TotalHeight(tree);
+ int yIncr = tree->yScrollIncrement;
+ if (yIncr <= 0)
+ yIncr = tree->itemHeight;
+ if (yIncr <= 0)
+ yIncr = 1;
+ FormatResult(interp, "visHeight %d totHeight %d visHeight %% yIncr %d totHeight %% yIncr %d",
+ visHeight,
+ totHeight,
+ visHeight % yIncr,
+ totHeight % yIncr
+ );
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
+
+/*
+textlayout $font $text
+ -width pixels
+ -wrap word|char
+ -justify left|center|right
+ -ignoretabs boolean
+ -ignorenewlines boolean
+*/
+int TextLayoutCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ Tk_Font tkfont;
+ Tk_Window tkwin = Tk_MainWindow(interp);
+ char *text;
+ int textLen;
+ 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_GetStringFromObj(objv[2], &textLen);
+
+ 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, textLen, width, justify, flags,
+ &width, &height);
+ FormatResult(interp, "%d %d", width, height);
+ Tk_FreeTextLayout(layout);
+
+done:
+ Tk_FreeFont(tkfont);
+ return result;
+}
+
+int ImageTintCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
+{
+ 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 = 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] = ((double) xColor->red / USHRT_MAX) * 255;
+ pixelPtr[x * 4 + 1] = ((double) xColor->green / USHRT_MAX) * 255;
+ pixelPtr[x * 4 + 2] = ((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(photoH, &photoBlock, 0, y,
+ imgW, 1, TK_PHOTO_COMPOSITE_OVERLAY);
+#if 1
+ photoPix += pitch;
+#else
+ {
+ Tk_PhotoImageBlock photoBlock;
+ Tk_PhotoGetImage(photoH, &photoBlock);
+ photoPix = photoBlock.pixelPtr;
+ photoPix += photoBlock.pitch * (y + 1);
+ }
+#endif
+ }
+ Tcl_Free((char *) photoBlock.pixelPtr);
+
+ return TCL_OK;
+}
+
+#ifndef WIN32
+
+int LoupeCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
+{
+ Tk_Window tkwin = Tk_MainWindow(interp);
+ Display *display = Tk_Display(tkwin);
+ int screenNum = Tk_ScreenNumber(tkwin);
+ Visual *visual = Tk_Visual(tkwin);
+ Window rootWindow = RootWindow(display, screenNum);
+ 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;
+ XImage *ximage;
+ int i, ncolors;
+ XColor *xcolors;
+ unsigned long red_shift, green_shift, blue_shift;
+
+ if (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)
+ return TCL_ERROR;
+ if (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)
+ return TCL_ERROR;
+ if (Tcl_GetIntFromObj(interp, objv[4], &w) != TCL_OK)
+ return TCL_ERROR;
+ if (Tcl_GetIntFromObj(interp, objv[5], &h) != TCL_OK)
+ return TCL_ERROR;
+ if (Tcl_GetIntFromObj(interp, objv[6], &zoom) != TCL_OK)
+ return TCL_ERROR;
+
+ grabX = x - w / zoom / 2;
+ grabY = y - h / zoom / 2;
+ grabW = w / zoom;
+ grabH = h / zoom;
+ if (grabW > displayW)
+ grabW = displayW;
+ if (grabH > displayH)
+ grabH = displayH;
+ if (grabX < 0)
+ grabX = 0;
+ if (grabY < 0)
+ grabY = 0;
+ if (grabX + grabW > displayW)
+ grabX = displayW - grabW;
+ if (grabY + grabH > displayH)
+ grabY = displayH - grabH;
+ ximage = XGetImage(display, rootWindow,
+ grabX, grabY, grabW, grabH, AllPlanes, ZPixmap);
+ if (ximage == NULL)
+ {
+ FormatResult(interp, "XGetImage() failed");
+ return TCL_ERROR;
+ }
+
+ /* See TkPoscriptImage */
+
+ ncolors = visual->map_entries;
+ xcolors = (XColor *) ckalloc(sizeof(XColor) * ncolors);
+
+ 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++;
+
+ if ((visual->class == DirectColor) || (visual->class == TrueColor))
+ {
+ 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;
+ }
+
+ XQueryColors(display, Tk_Colormap(tkwin), xcolors, ncolors);
+
+ /* XImage -> Tk_Image */
+ pixelPtr = 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);
+ 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;
+ 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;
+ }
+ }
+
+ Tk_PhotoPutZoomedBlock(photoH, &photoBlock, 0, 0, w, h,
+ zoom, zoom, 1, 1, TK_PHOTO_COMPOSITE_SET);
+
+ Tcl_Free((char *) pixelPtr);
+ ckfree((char *) xcolors);
+ XDestroyImage(ximage);
+
+ return TCL_OK;
+}
+
+#endif /* not WIN32 */
+
+DLLEXPORT int Treectrl_Init(Tcl_Interp *interp)
+{
+#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
+ if (TreeStyle_Init(interp) != TCL_OK)
+ {
+ return TCL_ERROR;
+ }
+
+ /* Hack for editing a text Element */
+ Tcl_CreateObjCommand(interp, "textlayout", TextLayoutCmd, NULL, NULL);
+
+ /* Hack for colorizing a image (like Win98 explorer) */
+ Tcl_CreateObjCommand(interp, "imagetint", ImageTintCmd, NULL, NULL);
+#ifndef WIN32
+ /* Screen magnifier to check those dotted lines */
+ Tcl_CreateObjCommand(interp, "loupe", LoupeCmd, NULL, NULL);
+#endif
+ Tcl_CreateObjCommand(interp, "treectrl", TreeObjCmd, NULL, NULL);
+ return Tcl_PkgProvide(interp, "treectrl", "1.0");
+}
+
diff --git a/generic/tkTreeCtrl.h b/generic/tkTreeCtrl.h
new file mode 100644
index 0000000..10dbc3a
--- /dev/null
+++ b/generic/tkTreeCtrl.h
@@ -0,0 +1,488 @@
+#include "tkPort.h"
+#include "default.h"
+#include "tkInt.h"
+#include "qebind.h"
+#include "dbwin.h"
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define INCREMENTS
+
+typedef struct TreeCtrl TreeCtrl;
+typedef struct TreeColumn_ *TreeColumn;
+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;
+
+enum { LEFT, TOP, RIGHT, BOTTOM };
+
+struct TreeCtrlDebug
+{
+ Tk_OptionTable optionTable;
+ int enable; /* Turn all debugging on/off */
+ int data; /* Debug data structures */
+ int display; /* Debug display routines */
+ int displayDelay; /* Delay between copy/draw operations */
+ XColor *eraseColor; /* Erase "invalidated" areas */
+ GC gcErase; /* for eraseColor */
+};
+
+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 */
+ int borderWidth; /* -borderwidth */
+ Tk_3DBorder border; /* -background */
+ Tk_Cursor cursor; /* Current cursor for window, or None. */
+ int relief; /* -relief */
+ 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 */
+ Tcl_Obj *scrollMargin; /* -scrollmargin: used by scripts */
+ char *takeFocus; /* -takfocus */
+ Tcl_Obj *fontObj; /* -font */
+ Tk_Font tkfont; /* -font */
+ int showButtons; /* boolean: Draw expand/collapse buttons */
+ int showLines; /* boolean: Draw lines connecting parent to child */
+ int showRoot; /* boolean: Draw the unique root item */
+ int showRootButton; /* boolean: Draw expand/collapse button for root item */
+ int showHeader; /* boolean: show column titles */
+ int indent; /* pixels: offset of child relative to parent */
+ char *selectMode; /* -selectmode: used by scripts only */
+ int itemHeight; /* -itemheight: Fixed height for all items (unless overridden) */
+ int width; /* -width */
+ int height; /* -height */
+ int 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 */
+ 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 */
+ char *openButtonString; /* -openbuttonimage */
+ char *closedButtonString; /* -closedbuttonimage */
+ Pixmap openButtonBitmap; /* -openbuttonbitmap */
+ Pixmap closedButtonBitmap; /* -closedbuttonbitmap */
+ int useIndent; /* MAX of open/closed button width and indent */
+#define BG_MODE_COLUMN 0
+#define BG_MODE_INDEX 1
+#define BG_MODE_ROW 2
+#define BG_MODE_VISINDEX 3
+ int backgroundMode; /* -backgroundmode */
+ int itemPad[4]; /* -itempad w/n/e/s */
+ Tcl_Obj *itemPadObj[4]; /* -itempad w/n/e/s */
+
+ struct TreeCtrlDebug debug;
+
+ /* Other stuff */
+ int gotFocus; /* flag */
+ int deleted; /* flag */
+ int updateIndex; /* flag */
+ int 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 buttonGC;
+ GC lineGC;
+ Tk_Image openButtonImage; /* -openbuttonimage */
+ Tk_Image closedButtonImage; /* -closedbuttonimage */
+ GC buttonOpenGC;
+ GC buttonClosedGC;
+ int closedButtonWidth;
+ int closedButtonHeight;
+ int openButtonWidth;
+ int openButtonHeight;
+ int prevWidth;
+ int prevHeight;
+ int drawableXOrigin;
+ int drawableYOrigin;
+
+ TreeColumn columns; /* List of columns */
+ TreeColumn columnTail; /* Last infinitely-wide column */
+ TreeColumn columnVis; /* First visible column */
+ int columnCount; /* Number of columns */
+ int columnCountVis; /* Number of visible columns */
+ int headerHeight; /* 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 */
+
+ TreeItem root;
+ TreeItem activeItem;
+ TreeItem anchorItem;
+ int nextItemId;
+ Tcl_HashTable itemHash; /* TreeItem.id -> TreeItem */
+ Tcl_HashTable elementHash; /* Element.name -> Element */
+ Tcl_HashTable styleHash; /* Style.name -> Style */
+ Tcl_HashTable imageHash; /* image name -> Tk_Image */
+ int depth; /* max depth of items under root */
+ int itemCount; /* Total number of items */
+ int itemVisCount; /* Total number of ReallyVisible() items */
+ QE_BindingTable bindingTable;
+ TreeDragImage dragImage;
+ TreeMarquee marquee;
+ TreeDInfo dInfo;
+ int selectCount; /* Number of 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;
+
+ char *stateNames[32]; /* Names of static and dynamic item states */
+};
+
+#define TREE_CONF_FONT 0x0001
+#define TREE_CONF_ITEMHEIGHT 0x0002
+#define TREE_CONF_INDENT 0x0004
+#define TREE_CONF_WRAP 0x0008
+#define TREE_CONF_BUTIMG_CLOSED 0x0010
+#define TREE_CONF_BUTIMG_OPEN 0x0020
+#define TREE_CONF_BUTBMP_CLOSED 0x0040
+#define TREE_CONF_BUTBMP_OPEN 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
+
+extern void Tree_AddItem(TreeCtrl *tree, TreeItem item);
+extern void Tree_RemoveItem(TreeCtrl *tree, TreeItem item);
+extern Tk_Image Tree_GetImage(TreeCtrl *tree, char *imageName);
+extern void Tree_UpdateScrollbarX(TreeCtrl *tree);
+extern void Tree_UpdateScrollbarY(TreeCtrl *tree);
+extern void Tree_AddToSelection(TreeCtrl *tree, TreeItem item);
+extern void Tree_RemoveFromSelection(TreeCtrl *tree, TreeItem item);
+
+/* tkTreeItem.c */
+
+#define ITEM_ALL ((TreeItem) -1)
+#define IFO_ALLOK 0x0001 /* ItemFromObj flag: "all" is acceptable */
+#define IFO_NULLOK 0x0002 /* ItemFromObj flag: can be NULL */
+#define IFO_NOTROOT 0x0004 /* ItemFromObj flag: "root" is forbidden */
+extern int TreeItem_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeItem *itemPtr, int flags);
+
+extern void FormatResult(Tcl_Interp *interp, char *fmt, ...);
+extern void Tree_Debug(TreeCtrl *tree);
+
+extern TreeItem TreeItem_Alloc(TreeCtrl *tree);
+extern TreeItem TreeItem_AllocRoot(TreeCtrl *tree);
+extern int TreeItem_Debug(TreeCtrl *tree, TreeItem item);
+extern void TreeItem_OpenClose(TreeCtrl *tree, TreeItem item, int mode, int recurse);
+
+#define STATE_OPEN 0x0001
+#define STATE_SELECTED 0x0002
+#define STATE_ENABLED 0x0004
+#define STATE_ACTIVE 0x0008
+#define STATE_FOCUS 0x0010
+#define STATE_USER 6 /* first user bit */
+extern int TreeItem_GetState(TreeCtrl *tree, TreeItem item_);
+
+#define CS_DISPLAY 0x01
+#define CS_LAYOUT 0x02
+extern int TreeItem_ChangeState(TreeCtrl *tree, TreeItem item_, int stateOff, int stateOn);
+
+extern void TreeItem_Undefine(TreeCtrl *tree, TreeItem item_, int state);
+
+extern int TreeItem_GetButton(TreeCtrl *tree, TreeItem item_);
+extern int TreeItem_SetButton(TreeCtrl *tree, TreeItem item, int hasButton);
+extern int TreeItem_GetDepth(TreeCtrl *tree, TreeItem item_);
+extern int TreeItem_SetDepth(TreeCtrl *tree, TreeItem item, int depth);
+extern int TreeItem_GetID(TreeCtrl *tree, TreeItem item_);
+extern int TreeItem_SetID(TreeCtrl *tree, TreeItem item_, int id);
+extern int TreeItem_GetOpen(TreeCtrl *tree, TreeItem item_);
+extern int TreeItem_SetOpen(TreeCtrl *tree, TreeItem item, int isOpen);
+extern int TreeItem_GetSelected(TreeCtrl *tree, TreeItem item_);
+extern int TreeItem_SetSelected(TreeCtrl *tree, TreeItem item, int isSelected);
+extern TreeItem TreeItem_SetFirstChild(TreeCtrl *tree, TreeItem item, TreeItem firstChild);
+extern TreeItem TreeItem_GetFirstChild(TreeCtrl *tree, TreeItem item);
+extern TreeItem TreeItem_SetLastChild(TreeCtrl *tree, TreeItem item, TreeItem lastChild);
+extern TreeItem TreeItem_GetLastChild(TreeCtrl *tree, TreeItem item);
+extern TreeItem TreeItem_SetParent(TreeCtrl *tree, TreeItem item, TreeItem parent);
+extern TreeItem TreeItem_GetParent(TreeCtrl *tree, TreeItem item);
+extern TreeItem TreeItem_SetNextSibling(TreeCtrl *tree, TreeItem item, TreeItem nextSibling);
+extern TreeItem TreeItem_GetNextSibling(TreeCtrl *tree, TreeItem item);
+extern TreeItem TreeItem_SetPrevSibling(TreeCtrl *tree, TreeItem item, TreeItem prevSibling);
+extern TreeItem TreeItem_GetPrevSibling(TreeCtrl *tree, TreeItem item);
+extern void TreeItem_SetDInfo(TreeCtrl *tree, TreeItem item, TreeItemDInfo dInfo);
+extern TreeItemDInfo TreeItem_GetDInfo(TreeCtrl *tree, TreeItem item);
+extern void TreeItem_SetRInfo(TreeCtrl *tree, TreeItem item, TreeItemRInfo rInfo);
+extern TreeItemRInfo TreeItem_GetRInfo(TreeCtrl *tree, TreeItem item);
+
+extern void TreeItem_AppendChild(TreeCtrl *tree, TreeItem self, TreeItem child);
+extern void TreeItem_RemoveFromParent(TreeCtrl *tree, TreeItem self);
+extern int TreeItem_Height(TreeCtrl *tree, TreeItem self);
+extern int TreeItem_TotalHeight(TreeCtrl *tree, TreeItem self);
+extern void TreeItem_InvalidateHeight(TreeCtrl *tree, TreeItem self);
+extern void TreeItem_Draw(TreeCtrl *tree, TreeItem self, int x, int y, int width, int height, Drawable drawable, int minX, int maxX, int index);
+extern void TreeItem_DrawLines(TreeCtrl *tree, TreeItem self, int x, int y, int width, int height, Drawable drawable);
+extern void TreeItem_DrawButton(TreeCtrl *tree, TreeItem self, int x, int y, int width, int height, Drawable drawable);
+extern int TreeItem_ReallyVisible(TreeCtrl *tree, TreeItem self);
+extern void TreeItem_FreeResources(TreeCtrl *tree, TreeItem self);
+extern TreeItem TreeItem_RootAncestor(TreeCtrl *tree, TreeItem item_);
+extern int TreeItem_IsAncestor(TreeCtrl *tree, TreeItem item1, TreeItem item2);
+extern Tcl_Obj *TreeItem_ToObj(TreeCtrl *tree, TreeItem item);
+extern void TreeItem_ToIndex(TreeCtrl *tree, TreeItem item, int *absolute, int *visible);
+extern TreeItem TreeItem_Next(TreeCtrl *tree, TreeItem item);
+extern TreeItem TreeItem_NextVisible(TreeCtrl *tree, TreeItem item);
+extern TreeItem TreeItem_Prev(TreeCtrl *tree, TreeItem item);
+extern TreeItem TreeItem_PrevVisible(TreeCtrl *tree, TreeItem item);
+extern char *TreeItem_Identify(TreeCtrl *tree, TreeItem item_, int x, int y);
+extern void TreeItem_Identify2(TreeCtrl *tree, TreeItem item_,
+ int x1, int y1, int x2, int y2, Tcl_Obj *listObj);
+extern int TreeItem_Indent(TreeCtrl *tree, TreeItem item_);
+extern void Tree_UpdateItemIndex(TreeCtrl *tree);
+extern int TreeItemCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
+
+extern TreeItemColumn TreeItem_GetFirstColumn(TreeCtrl *tree, TreeItem item);
+extern TreeItemColumn TreeItemColumn_GetNext(TreeCtrl *tree, TreeItemColumn column);
+extern void TreeItemColumn_InvalidateSize(TreeCtrl *tree, TreeItemColumn column);
+extern TreeStyle TreeItemColumn_GetStyle(TreeCtrl *tree, TreeItemColumn column);
+extern void TreeItemColumn_ForgetStyle(TreeCtrl *tree, TreeItemColumn column_);
+extern int TreeItemColumn_NeededWidth(TreeCtrl *tree, TreeItem item_, TreeItemColumn column_);
+extern TreeItemColumn TreeItem_FindColumn(TreeCtrl *tree, TreeItem item, int columnIndex);
+extern int TreeItem_ColumnFromObj(TreeCtrl *tree, TreeItem item, Tcl_Obj *obj, TreeItemColumn *columnPtr, int *indexPtr);
+extern void TreeItem_RemoveColumn(TreeCtrl *tree, TreeItem item_, TreeItemColumn column_);
+
+typedef struct StyleDrawArgs StyleDrawArgs;
+struct StyleDrawArgs
+{
+ TreeCtrl *tree;
+ TreeStyle style;
+ int x;
+ int y;
+ int width;
+ int height;
+ Drawable drawable;
+ int state; /* STATE_xxx */
+ Tk_Justify justify;
+};
+
+/* tkTreeStyle.c */
+extern int TreeStyle_Init(Tcl_Interp *interp);
+extern int TreeStyle_NeededWidth(TreeCtrl *tree, TreeStyle style_, int state);
+extern int TreeStyle_NeededHeight(TreeCtrl *tree, TreeStyle style_, int state);
+extern int TreeStyle_UseHeight(StyleDrawArgs *drawArgs);
+extern void TreeStyle_Draw(StyleDrawArgs *args);
+extern void TreeStyle_FreeResources(TreeCtrl *tree, TreeStyle style_);
+extern void TreeStyle_Free(TreeCtrl *tree);
+extern int TreeStyle_FromObj(TreeCtrl *tree, Tcl_Obj *obj, TreeStyle *style_);
+extern Tcl_Obj *TreeStyle_ToObj(TreeStyle style_);
+extern Tcl_Obj *TreeStyle_GetText(TreeCtrl *tree, TreeStyle style_);
+extern void TreeStyle_SetText(TreeCtrl *tree, TreeStyle style_, Tcl_Obj *textObj);
+extern TreeStyle TreeStyle_NewInstance(TreeCtrl *tree, TreeStyle master);
+extern int TreeStyle_ElementActual(TreeCtrl *tree, TreeStyle style_, int state, Tcl_Obj *elemObj, Tcl_Obj *obj);
+extern int TreeStyle_ElementCget(TreeCtrl *tree, TreeStyle style_, Tcl_Obj *elemObj, Tcl_Obj *obj);
+extern int TreeStyle_ElementConfigure(TreeCtrl *tree, TreeStyle style_, Tcl_Obj *elemObj, int objc, Tcl_Obj **objv);
+extern void TreeStyle_ListElements(TreeCtrl *tree, TreeStyle style_);
+extern TreeStyle TreeStyle_GetMaster(TreeCtrl *tree, TreeStyle style_);
+extern char *TreeStyle_Identify(StyleDrawArgs *drawArgs, int x, int y);
+extern void TreeStyle_Identify2(StyleDrawArgs *drawArgs,
+ int x1, int y1, int x2, int y2, Tcl_Obj *listObj);
+extern int TreeStyle_Remap(TreeCtrl *tree, TreeStyle styleFrom_, TreeStyle styleTo_, int objc, Tcl_Obj *CONST objv[]);
+extern 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
+extern int TreeStyle_GetSortData(TreeCtrl *tree, TreeStyle style_, int type, long *lv, double *dv, char **sv);
+extern int TreeStyle_GetElemRects(StyleDrawArgs *drawArgs, int objc, Tcl_Obj *CONST objv[], XRectangle rects[20]);
+extern int TreeElementCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
+extern int TreeStyleCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
+extern int TreeStyle_ChangeState(TreeCtrl *tree, TreeStyle style_, int state1, int state2);
+extern void TreeStyle_UndefineState(TreeCtrl *tree, int state);
+
+/* tkTreeNotify.c */
+extern int TreeNotify_Init(TreeCtrl *tree);
+extern void TreeNotify_OpenClose(TreeCtrl *tree, TreeItem item, int isOpen, int before);
+extern void TreeNotify_Selection(TreeCtrl *tree, TreeItem select[], TreeItem deselect[]);
+extern int TreeNotifyCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
+extern void TreeNotify_ActiveItem(TreeCtrl *tree, TreeItem itemOld, TreeItem itemNew);
+extern void TreeNotify_Scroll(TreeCtrl *tree, double fractions[2], int vertical);
+
+/* tkTreeColumn.c */
+extern void Tree_InitColumns(TreeCtrl *tree);
+extern TreeColumn Tree_CreateColumn(TreeCtrl *tree, int columnIndex, int *isNew);
+extern TreeColumn Tree_FindColumn(TreeCtrl *tree, int columnIndex);
+#define CFO_NOT_TAIL 0x01
+extern int Tree_FindColumnByTag(TreeCtrl *tree, Tcl_Obj *obj, TreeColumn *columnPtr, int flags);
+extern int TreeColumn_FromObj(TreeCtrl *tree, Tcl_Obj *obj, TreeColumn *columnPtr, int flags);
+extern int TreeColumnCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
+extern int TreeColumn_Index(TreeColumn column_);
+extern TreeColumn TreeColumn_Next(TreeColumn column_);
+extern int TreeColumn_FixedWidth(TreeColumn column_);
+extern int TreeColumn_MinWidth(TreeColumn column_);
+extern int TreeColumn_StepWidth(TreeColumn column_);
+extern int TreeColumn_NeededWidth(TreeColumn column_);
+extern int TreeColumn_UseWidth(TreeColumn column_);
+extern void TreeColumn_SetUseWidth(TreeColumn column_, int width);
+extern Tk_Justify TreeColumn_Justify(TreeColumn column_);
+extern int TreeColumn_WidthHack(TreeColumn column_);
+extern int TreeColumn_Visible(TreeColumn column_);
+extern GC TreeColumn_BackgroundGC(TreeColumn column_, int which);
+extern void TreeColumn_Draw(TreeColumn column_, Drawable drawable, int x, int y);
+extern void Tree_DrawHeader(TreeCtrl *tree, Drawable drawable, int x, int y);
+extern int TreeColumn_WidthOfItems(TreeColumn column_);
+extern void TreeColumn_InvalidateWidth(TreeColumn column_);
+extern void TreeColumn_Init(TreeCtrl *tree);
+extern void Tree_FreeColumns(TreeCtrl *tree);
+extern void Tree_InvalidateColumnWidth(TreeCtrl *tree, int columnIndex);
+extern int Tree_HeaderHeight(TreeCtrl *tree);
+extern int Tree_WidthOfColumns(TreeCtrl *tree);
+extern void TreeColumn_TreeChanged(TreeCtrl *tree, int flagT);
+
+/* tkTreeDrag.c */
+extern int TreeDragImage_Init(TreeCtrl *tree);
+extern void TreeDragImage_Free(TreeDragImage dragImage_);
+extern void TreeDragImage_Display(TreeDragImage dragImage_);
+extern void TreeDragImage_Undisplay(TreeDragImage dragImage_);
+extern void TreeDragImage_Draw(TreeDragImage dragImage_, Drawable drawable, int x, int y);
+extern int DragImageCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
+
+/* tkTreeMarquee.c */
+extern int TreeMarquee_Init(TreeCtrl *tree);
+extern void TreeMarquee_Free(TreeMarquee marquee_);
+extern void TreeMarquee_Draw(TreeMarquee marquee_, Drawable drawable, int x, int y);
+extern void TreeMarquee_Display(TreeMarquee marquee_);
+extern void TreeMarquee_Undisplay(TreeMarquee marquee_);
+extern int TreeMarqueeCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
+
+/* tkTreeDisplay.c */
+extern int Tree_TotalWidth(TreeCtrl *tree);
+extern int Tree_TotalHeight(TreeCtrl *tree);
+extern TreeItem Tree_ItemUnderPoint(TreeCtrl *tree, int *x, int *y, int nearest);
+extern void Tree_FreeItemRInfo(TreeCtrl *tree, TreeItem item);
+extern void Tree_ItemBbox(TreeCtrl *tree, TreeItem item, int *x, int *y, int *w, int *h);
+extern TreeItem Tree_ItemAbove(TreeCtrl *tree, TreeItem item);
+extern TreeItem Tree_ItemBelow(TreeCtrl *tree, TreeItem item);
+extern TreeItem Tree_ItemLeft(TreeCtrl *tree, TreeItem item);
+extern TreeItem Tree_ItemRight(TreeCtrl *tree, TreeItem item);
+extern TreeItem Tree_ItemTop(TreeCtrl *tree, TreeItem item);
+extern TreeItem Tree_ItemBottom(TreeCtrl *tree, TreeItem item);
+extern TreeItem Tree_ItemLeftMost(TreeCtrl *tree, TreeItem item);
+extern TreeItem Tree_ItemRightMost(TreeCtrl *tree, TreeItem item);
+extern int Tree_ItemToRNC(TreeCtrl *tree, TreeItem item, int *row, int *col);
+extern TreeItem Tree_RNCToItem(TreeCtrl *tree, int row, int col);
+
+extern void TreeDInfo_Init(TreeCtrl *tree);
+extern void TreeDInfo_Free(TreeCtrl *tree);
+extern void Tree_EventuallyRedraw(TreeCtrl *tree);
+extern void Tree_GetScrollFractionsX(TreeCtrl *tree, double fractions[2]);
+extern void Tree_GetScrollFractionsY(TreeCtrl *tree, double fractions[2]);
+extern int Increment_FindX(TreeCtrl *tree, int offset);
+extern int Increment_FindY(TreeCtrl *tree, int offset);
+extern int Increment_ToOffsetX(TreeCtrl *tree, int index);
+extern int Increment_ToOffsetY(TreeCtrl *tree, int index);
+extern int B_XviewCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]);
+extern int B_YviewCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[]);
+extern void Tree_SetOriginX(TreeCtrl *tree, int xOrigin);
+extern void Tree_SetOriginY(TreeCtrl *tree, int yOrigin);
+extern void Tree_RelayoutWindow(TreeCtrl *tree);
+extern void Tree_FreeItemDInfo(TreeCtrl *tree, TreeItem item1, TreeItem item2);
+extern void Tree_InvalidateItemDInfo(TreeCtrl *tree, TreeItem item1, TreeItem item2);
+extern void Tree_InvalidateArea(TreeCtrl *tree, int x1, int y1, int x2, int y2);
+extern void Tree_InvalidateItemArea(TreeCtrl *tree, int x1, int y1, int x2, int y2);
+extern void Tree_InvalidateRegion(TreeCtrl *tree, TkRegion region);
+extern void Tree_InvalidateWindow(TreeCtrl *tree);
+extern void Tree_RedrawArea(TreeCtrl *tree, int x1, int y1, int x2, int y2);
+extern void Tree_RedrawItemArea(TreeCtrl *tree, int x1, int y1, int x2, int y2);
+extern void Tree_FocusChanged(TreeCtrl *tree, int gotFocus);
+extern TreeItem *Tree_ItemsInArea(TreeCtrl *tree, int minX, int minY, int maxX, int maxY);
+extern void TreeColumnProxy_Undisplay(TreeCtrl *tree);
+extern void TreeColumnProxy_Display(TreeCtrl *tree);
+
+#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
+extern void Tree_DInfoChanged(TreeCtrl *tree, int flags);
+
+/* tkTreeUtils.c */
+extern void wipefree(char *memPtr, int size);
+#define WFREE(p,t) \
+ wipefree((char *) p, sizeof(t))
+extern int Ellipsis(Tk_Font tkfont, char *string, int numBytes, int *maxPixels, char *ellipsis);
+extern void HDotLine(TreeCtrl *tree, Drawable drawable, GC gc, int x1, int y1, int x2);
+extern void VDotLine(TreeCtrl *tree, Drawable drawable, GC gc, int x1, int y1, int y2);
+extern void DotRect(TreeCtrl *tree, Drawable drawable, int x, int y, int width, int height);
+extern void DrawActiveOutline(TreeCtrl *tree, Drawable drawable, int x, int y, int width, int height, int open);
+typedef struct DotState
+{
+ int stuff[10];
+} DotState;
+extern void DotRect_Setup(TreeCtrl *tree, Drawable drawable, DotState *dotState);
+extern void DotRect_Draw(DotState *dotState, int x, int y, int width, int height);
+extern void DotRect_Restore(DotState *dotState);
+typedef struct TextLayout_ *TextLayout;
+extern TextLayout TextLayout_Compute(Tk_Font tkfont, CONST char *string,
+ int numChars, int wrapLength, Tk_Justify justify, int maxLines, int flags);
+extern void TextLayout_Free(TextLayout textLayout);
+extern void TextLayout_Size(TextLayout textLayout, int *widthPtr, int *heightPtr);
+extern void TextLayout_Draw(Display *display, Drawable drawable, GC gc,
+ TextLayout layout, int x, int y, int firstChar, int lastChar);
+
diff --git a/generic/tkTreeDisplay.c b/generic/tkTreeDisplay.c
new file mode 100644
index 0000000..8056cbf
--- /dev/null
+++ b/generic/tkTreeDisplay.c
@@ -0,0 +1,3618 @@
+#include "tkTreeCtrl.h"
+
+typedef struct RItem RItem;
+typedef struct Range Range;
+typedef struct DItem DItem;
+typedef struct DInfo DInfo;
+
+void Range_RedoIfNeeded(TreeCtrl *tree);
+int Range_TotalWidth(TreeCtrl *tree, Range *range_);
+int Range_TotalHeight(TreeCtrl *tree, Range *range_);
+void Range_Redo(TreeCtrl *tree);
+Range *Range_UnderPoint(TreeCtrl *tree, int *x_, int *y_, int nearest);
+RItem *Range_ItemUnderPoint(TreeCtrl *tree, Range *range, int *x_, int *y_);
+
+/* One of these per TreeItem */
+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 */
+ 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 */
+ int offset; /* vertical/horizontal offset from canvas top/left */
+ Range *prev;
+ Range *next;
+};
+
+/* Display information for a TreeItem */
+struct DItem
+{
+ char magic[4]; /* debug */
+ TreeItem item;
+ int x, y; /* Where it should be drawn, window coords */
+ int oldX, oldY; /* Where it was last drawn, window coords */
+ int width, height; /* Current width and height */
+ int dirty[4]; /* Dirty area in item coords */
+ Range *range; /* Range the TreeItem is in */
+ int index; /* Used for alternating background colors */
+#define DITEM_DIRTY 0x0001
+#define DITEM_ALL_DIRTY 0x0002
+ int flags;
+ DItem *next;
+};
+
+/* Display information for a TreeCtrl */
+struct DInfo
+{
+ GC scrollGC;
+ int xOrigin; /* Last seen TreeCtrl.xOrigin */
+ int yOrigin; /* Last seen TreeCtrl.yOrigin */
+ int totalWidth; /* Last seen Tree_TotalWidth() */
+ int totalHeight; /* Last seen Tree_TotalHeight() */
+ int columnWidth[20]; /* Last seen column widths */
+ int headerHeight; /* Last seen TreeCtrl.headerHeight */
+ DItem *dItem; /* Head of list for each visible item */
+ DItem *dItemLast; /* Temp for UpdateDInfo() */
+ Range *rangeFirst; /* Head of Ranges */
+ Range *rangeLast; /* Tail of Ranges */
+ RItem *rItem; /* Block of RItems for all Ranges */
+ int rItemMax; /* size of rItem */
+ Range *rangeFirstD; /* First range with valid display info */
+ Range *rangeLastD; /* Last range with valid display info */
+ int itemHeight; /* Observed max TreeItem height */
+ int itemWidth; /* Observed max TreeItem width */
+ Pixmap pixmap; /* DOUBLEBUFFER_WINDOW */
+ int dirty[4]; /* DOUBLEBUFFER_WINDOW */
+ int flags; /* DINFO_XXX */
+#ifdef INCREMENTS
+ int xScrollIncrement; /* Last seen TreeCtr.xScrollIncrement */
+ int yScrollIncrement; /* Last seen TreeCtr.yScrollIncrement */
+ int *xScrollIncrements; /* When tree->xScrollIncrement is zero */
+ int *yScrollIncrements; /* When tree->yScrollIncrement is zero */
+ int xScrollIncrementCount;
+ int yScrollIncrementCount;
+ int incrementTop; /* yScrollIncrement[] index of item at top */
+ int incrementLeft; /* xScrollIncrement[] index of item at left */
+#endif
+};
+
+/*========*/
+
+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;
+}
+
+/*
+ * This routine puts all ReallyVisible() TreeItems into a list of Ranges.
+ * If tree->wrapMode is TREE_WRAP_NONE there will only be a single Range.
+ */
+void Range_Redo(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ Range *rangeList = dInfo->rangeFirst;
+ Range *range, *rangePrev = NULL;
+ RItem *rItem;
+ TreeItem item = tree->root;
+ int fixedWidth = -1, minWidth = -1, stepWidth = -1;
+ int wrapCount = 0, wrapPixels = 0;
+ int count, pixels, rItemCount = 0;
+ int rangeIndex = 0, itemIndex;
+
+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 ?
+ Tk_Height(tree->tkwin) - tree->inset * 2 - Tree_HeaderHeight(tree) :
+ Tk_Width(tree->tkwin) - tree->inset * 2;
+ if (wrapPixels < 0)
+ wrapPixels = 0;
+ break;
+ }
+
+ if ((wrapPixels > 0) && !tree->vertical)
+ {
+ /* 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 ranges */
+ else if (TreeColumn_FixedWidth(tree->columnVis) != -1)
+ fixedWidth = TreeColumn_FixedWidth(tree->columns);
+
+ /* Single item column, possible minimum width */
+ else if (TreeColumn_MinWidth(tree->columnVis) != -1)
+ minWidth = TreeColumn_MinWidth(tree->columns);
+
+ /* Single item column, each item is a multiple of this width */
+ else
+ stepWidth = TreeColumn_StepWidth(tree->columnVis);
+ }
+
+ /* Speed up ReallyVisible() and get itemVisCount */
+ if (tree->updateIndex)
+ 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;
+ pixels = 0;
+ itemIndex = 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 = itemIndex;
+
+ /* Range must be <= this number of pixels */
+ /* Ensure at least one item is in this Range */
+ 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_GetFirstColumn(tree, item);
+ if (itemColumn != NULL)
+ {
+ int columnWidth =
+ TreeItemColumn_NeededWidth(tree, item, itemColumn);
+ if (0 == tree->columnTree)
+ columnWidth += TreeItem_Indent(tree, item);
+ rItem->size = MAX(columnWidth, minWidth);
+ }
+ else
+ rItem->size = MAX(0, minWidth);
+ }
+ }
+ if ((stepWidth != -1) && (rItem->size % stepWidth))
+ rItem->size += stepWidth - rItem->size % stepWidth;
+ /* Too big */
+ if (pixels + rItem->size > wrapPixels)
+ break;
+ pixels += rItem->size;
+ }
+ range->last = rItem;
+ itemIndex++;
+ rItemCount++;
+ if (++count == wrapCount)
+ break;
+ item = TreeItem_NextVisible(tree, item);
+ if (item == NULL)
+ break;
+ }
+ /* Since 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)
+ range->totalHeight = pixels;
+ else
+ range->totalWidth = pixels;
+ }
+
+ if (rangePrev == NULL)
+ dInfo->rangeFirst = range;
+ else
+ {
+ range->prev = rangePrev;
+ rangePrev->next = range;
+ }
+ dInfo->rangeLast = range;
+ rangePrev = range;
+ item = TreeItem_NextVisible(tree, range->last->item);
+ }
+
+freeRanges:
+ while (rangeList != NULL)
+ rangeList = Range_Free(tree, rangeList);
+}
+
+int Range_TotalWidth(TreeCtrl *tree, Range *range)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ TreeItem item;
+ TreeItemColumn itemColumn;
+ RItem *rItem;
+ int columnWidth, fixedWidth = -1, minWidth = -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);
+
+ /* Single item column, fixed width for all ranges */
+ if (TreeColumn_FixedWidth(tree->columnVis) != -1)
+ return range->totalWidth = TreeColumn_FixedWidth(tree->columnVis);
+
+ /* If there is only a single range, then use the column width,
+ * since it may expand to fill the window */
+ if (dInfo->rangeFirst == dInfo->rangeLast)
+ return range->totalWidth = TreeColumn_UseWidth(tree->columnVis);
+
+ /* Single item column, want all ranges same width */
+ if (TreeColumn_WidthHack(tree->columnVis))
+ return range->totalWidth = TreeColumn_UseWidth(tree->columnVis);
+
+ /* Possible minimum column width */
+ minWidth = TreeColumn_MinWidth(tree->columnVis);
+ range->totalWidth = MAX(0, minWidth);
+
+ /* Max needed width of items in this range */
+ rItem = range->first;
+ while (1)
+ {
+ item = rItem->item;
+ itemColumn = TreeItem_GetFirstColumn(tree, item);
+ if (itemColumn != NULL)
+ {
+ columnWidth = TreeItemColumn_NeededWidth(tree, item, itemColumn);
+ if (0 == tree->columnTree)
+ columnWidth += TreeItem_Indent(tree, item);
+ if (columnWidth > range->totalWidth)
+ range->totalWidth = columnWidth;
+ }
+ if (rItem == range->last)
+ break;
+ rItem++;
+ }
+ return range->totalWidth;
+ }
+ else
+ {
+ /* More than one item column, so all items/ranges have the same width */
+ if (tree->columnCountVis > 1)
+ fixedWidth = Tree_WidthOfColumns(tree);
+
+ /* Single item column, fixed width for all items/ranges */
+ else if (TreeColumn_FixedWidth(tree->columnVis) != -1)
+ fixedWidth = TreeColumn_FixedWidth(tree->columnVis);
+
+ else if (TreeColumn_MinWidth(tree->columnVis) != -1)
+ minWidth = TreeColumn_MinWidth(tree->columnVis);
+
+ else
+ stepWidth = TreeColumn_StepWidth(tree->columnVis);
+
+ /* 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_GetFirstColumn(tree, item);
+ if (itemColumn != NULL)
+ {
+ columnWidth = TreeItemColumn_NeededWidth(tree, item, itemColumn);
+ if (0 == tree->columnTree)
+ columnWidth += TreeItem_Indent(tree, item);
+ itemWidth = MAX(columnWidth, minWidth);
+ }
+ else
+ itemWidth = MAX(0, minWidth);
+
+ if ((stepWidth != -1) && (itemWidth % stepWidth))
+ itemWidth += stepWidth - rItem->size % stepWidth;
+ }
+
+ rItem = (RItem *) TreeItem_GetRInfo(tree, item);
+ rItem->offset = range->totalWidth;
+ rItem->size = itemWidth;
+
+ range->totalWidth += itemWidth;
+ if (rItem == range->last)
+ break;
+ rItem++;
+ }
+ return range->totalWidth;
+ }
+}
+
+int Range_TotalHeight(TreeCtrl *tree, Range *range)
+{
+ 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;
+ range->totalHeight += itemHeight;
+ }
+ else
+ {
+ if (itemHeight > range->totalHeight)
+ range->totalHeight = itemHeight;
+ }
+ if (rItem == range->last)
+ break;
+ rItem++;
+ }
+ return range->totalHeight;
+}
+
+int Tree_TotalWidth(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ Range *range = dInfo->rangeFirst;
+ int rangeWidth;
+
+ Range_RedoIfNeeded(tree);
+
+ if (tree->totalWidth >= 0)
+ return tree->totalWidth;
+
+ tree->totalWidth = 0;
+ while (range != NULL)
+ {
+ rangeWidth = Range_TotalWidth(tree, range);
+ if (tree->vertical)
+ {
+ range->offset = tree->totalWidth;
+ tree->totalWidth += rangeWidth;
+ }
+ else
+ {
+ if (rangeWidth > tree->totalWidth)
+ tree->totalWidth = rangeWidth;
+ }
+ range = range->next;
+ }
+ return tree->totalWidth;
+}
+
+int Tree_TotalHeight(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ Range *range = dInfo->rangeFirst;
+ int rangeHeight;
+
+ Range_RedoIfNeeded(tree);
+
+ if (tree->totalHeight >= 0)
+ return tree->totalHeight;
+
+ tree->totalHeight = 0;
+ while (range != NULL)
+ {
+ rangeHeight = Range_TotalHeight(tree, range);
+ if (tree->vertical)
+ {
+ if (rangeHeight > tree->totalHeight)
+ tree->totalHeight = rangeHeight;
+ }
+ else
+ {
+ range->offset = tree->totalHeight;
+ tree->totalHeight += rangeHeight;
+ }
+ range = range->next;
+ }
+ return tree->totalHeight;
+}
+
+Range *Range_UnderPoint(TreeCtrl *tree, int *x_, int *y_, int nearest)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ Range *range;
+ int x = *x_, y = *y_;
+
+ Range_RedoIfNeeded(tree);
+
+ range = dInfo->rangeFirst;
+
+ if (nearest)
+ {
+ int visWidth = Tk_Width(tree->tkwin) - tree->inset * 2;
+ int topInset = tree->inset + Tree_HeaderHeight(tree);
+ int visHeight = Tk_Height(tree->tkwin) - topInset - tree->inset;
+
+ if ((visWidth <= 0) || (visHeight <= 0))
+ return NULL;
+
+ /* Keep inside borders and header. Perhaps another flag needed. */
+ if (x < tree->inset)
+ x = tree->inset;
+ if (x >= Tk_Width(tree->tkwin) - tree->inset)
+ x = Tk_Width(tree->tkwin) - tree->inset - 1;
+ if (y < topInset)
+ y = topInset;
+ if (y >= Tk_Height(tree->tkwin) - tree->inset)
+ y = Tk_Height(tree->tkwin) - tree->inset - 1;
+ }
+
+ /* Window -> canvas */
+ x += tree->xOrigin;
+ y += tree->yOrigin;
+
+ if (nearest)
+ {
+ if (x < 0)
+ x = 0;
+ if (x >= Tree_TotalWidth(tree))
+ x = Tree_TotalWidth(tree) - 1;
+ if (y < 0)
+ y = 0;
+ if (y >= Tree_TotalHeight(tree))
+ y = Tree_TotalHeight(tree) - 1;
+ }
+ else
+ {
+ if (x < 0)
+ return NULL;
+ if (x >= Tree_TotalWidth(tree))
+ return NULL;
+ if (y < 0)
+ return NULL;
+ if (y >= Tree_TotalHeight(tree))
+ return NULL;
+ }
+
+ if (tree->vertical)
+ {
+ while (range != NULL)
+ {
+ if ((x >= range->offset) && (x < range->offset + range->totalWidth))
+ {
+ if (nearest || (y < range->totalHeight))
+ {
+ (*x_) = x - range->offset;
+ (*y_) = MIN(y, range->totalHeight - 1);
+ return range;
+ }
+ return NULL;
+ }
+ range = range->next;
+ }
+ return NULL;
+ }
+ else
+ {
+ while (range != NULL)
+ {
+ if ((y >= range->offset) && (y < range->offset + range->totalHeight))
+ {
+ if (nearest || (x < range->totalWidth))
+ {
+ (*x_) = MIN(x, range->totalWidth - 1);
+ (*y_) = y - range->offset;
+ return range;
+ }
+ return NULL;
+ }
+ range = range->next;
+ }
+ return NULL;
+ }
+}
+
+RItem *Range_ItemUnderPoint(TreeCtrl *tree, Range *range, int *x_, int *y_)
+{
+ RItem *rItem;
+ int x = (*x_), y = (*y_);
+ int i, l, u;
+
+ /* x and y must be in Range */
+ if (x < 0 || x >= range->totalWidth || y < 0 || y >= range->totalHeight)
+ goto panicNow;
+
+#if 1
+ if (tree->vertical)
+ {
+ /* Binary search */
+ l = 0;
+ u = range->last->index;
+ while (l <= u)
+ {
+ i = (l + u) / 2;
+ rItem = range->first + i;
+ if ((y >= rItem->offset) && (y < rItem->offset + rItem->size))
+ {
+ /* Range -> item coords */
+ (*x_) = x;
+ (*y_) = y - rItem->offset;
+ return rItem;
+ }
+ if (y < rItem->offset)
+ u = i - 1;
+ else
+ l = i + 1;
+ }
+ }
+ else
+ {
+ /* Binary search */
+ l = 0;
+ u = range->last->index;
+ while (l <= u)
+ {
+ i = (l + u) / 2;
+ rItem = range->first + i;
+ if ((x >= rItem->offset) && (x < rItem->offset + rItem->size))
+ {
+ /* Range -> item coords */
+ (*x_) = x - rItem->offset;
+ (*y_) = y;
+ return rItem;
+ }
+ if (x < rItem->offset)
+ u = i - 1;
+ else
+ l = i + 1;
+ }
+ }
+#else
+ if (tree->vertical)
+ {
+ rItem = range->first;
+ while (1)
+ {
+ if ((y >= rItem->offset) && (y < rItem->offset + rItem->size))
+ {
+ /* Range -> item coords */
+ (*x_) = x;
+ (*y_) = y - rItem->offset;
+ return rItem->item;
+ }
+ if (rItem == range->last)
+ break;
+ rItem++;
+ }
+ }
+ else
+ {
+ rItem = range->first;
+ while (1)
+ {
+ if ((x >= rItem->offset) && (x < rItem->offset + rItem->size))
+ {
+ /* Range -> item coords */
+ (*x_) = x - rItem->offset;
+ (*y_) = y;
+ return rItem->item;
+ }
+ if (rItem == range->last)
+ break;
+ rItem++;
+ }
+ }
+#endif
+panicNow:
+ panic("Range_ItemUnderPoint: can't find TreeItem in Range: x %d y %d W %d H %d",
+ x, y, range->totalWidth, range->totalHeight);
+ return NULL;
+}
+
+#ifdef INCREMENTS
+
+static int Increment_AddX(TreeCtrl *tree, int offset, int size)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ int visWidth = Tk_Width(tree->tkwin) - tree->inset * 2;
+
+ while ((visWidth > 1) &&
+ (offset - dInfo->xScrollIncrements[dInfo->xScrollIncrementCount - 1]
+ > visWidth))
+ {
+ size = Increment_AddX(tree,
+ dInfo->xScrollIncrements[dInfo->xScrollIncrementCount - 1] + visWidth,
+ size);
+ }
+ if (dInfo->xScrollIncrementCount + 1 > size)
+ {
+ size *= 2;
+ dInfo->xScrollIncrements = (int *) ckrealloc(
+ (char *) dInfo->xScrollIncrements, size * sizeof(int));
+ }
+ dInfo->xScrollIncrements[dInfo->xScrollIncrementCount++] = offset;
+ return size;
+}
+
+static int Increment_AddY(TreeCtrl *tree, int offset, int size)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ int topInset = tree->inset + Tree_HeaderHeight(tree);
+ int visHeight = Tk_Height(tree->tkwin) - topInset - tree->inset;
+
+ while ((visHeight > 1) &&
+ (offset - dInfo->yScrollIncrements[dInfo->yScrollIncrementCount - 1]
+ > visHeight))
+ {
+ size = Increment_AddY(tree,
+ dInfo->yScrollIncrements[dInfo->yScrollIncrementCount - 1] + visHeight,
+ size);
+ }
+ if (dInfo->yScrollIncrementCount + 1 > size)
+ {
+ size *= 2;
+ dInfo->yScrollIncrements = (int *) ckrealloc(
+ (char *) dInfo->yScrollIncrements, size * sizeof(int));
+ }
+ dInfo->yScrollIncrements[dInfo->yScrollIncrementCount++] = offset;
+ return size;
+}
+
+static void Increment_RedoX(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ Range *range;
+ RItem *rItem;
+ int visWidth = Tk_Width(tree->tkwin) - tree->inset * 2;
+ int totalWidth = Tree_TotalWidth(tree);
+ int x1, x2, x, y;
+ int size;
+
+ if (dInfo->rangeFirst == NULL)
+ return;
+
+ /* First increment is zero */
+ size = 10;
+ dInfo->xScrollIncrements = (int *) ckalloc(size * sizeof(int));
+ dInfo->xScrollIncrements[dInfo->xScrollIncrementCount++] = 0;
+
+ x1 = 0;
+ while (1)
+ {
+ x2 = totalWidth;
+ for (range = dInfo->rangeFirst;
+ range != NULL;
+ range = range->next)
+ {
+ if (x1 >= range->totalWidth)
+ continue;
+
+ /* Find RItem whose right side is >= x1 by smallest amount */
+ x = x1;
+ y = 0;
+ rItem = Range_ItemUnderPoint(tree, range, &x, &y);
+ if (rItem->offset + rItem->size < x2)
+ x2 = rItem->offset + rItem->size;
+ }
+ if (x2 == totalWidth)
+ break;
+ size = Increment_AddX(tree, x2, size);
+ x1 = x2;
+ }
+ if ((visWidth > 1) && (totalWidth -
+ dInfo->xScrollIncrements[dInfo->xScrollIncrementCount - 1] > visWidth))
+ {
+ Increment_AddX(tree, totalWidth, size);
+ dInfo->xScrollIncrementCount--;
+ dInfo->xScrollIncrements[dInfo->xScrollIncrementCount - 1] = totalWidth - visWidth;
+ }
+}
+
+static void Increment_RedoY(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ Range *range;
+ RItem *rItem;
+ int topInset = tree->inset + Tree_HeaderHeight(tree);
+ int visHeight = Tk_Height(tree->tkwin) - topInset - tree->inset;
+ int totalHeight = Tree_TotalHeight(tree);
+ int y1, y2, x, y;
+ int size;
+
+ if (dInfo->rangeFirst == NULL)
+ return;
+
+ /* First increment is zero */
+ size = 10;
+ dInfo->yScrollIncrements = (int *) ckalloc(size * sizeof(int));
+ dInfo->yScrollIncrements[dInfo->yScrollIncrementCount++] = 0;
+
+ y1 = 0;
+ while (1)
+ {
+ y2 = totalHeight;
+ for (range = dInfo->rangeFirst;
+ range != NULL;
+ range = range->next)
+ {
+ if (y1 >= range->totalHeight)
+ continue;
+
+ /* Find RItem whose bottom edge is >= y1 by smallest amount */
+ x = 0;
+ y = y1;
+ rItem = Range_ItemUnderPoint(tree, range, &x, &y);
+ if (rItem->offset + rItem->size < y2)
+ y2 = rItem->offset + rItem->size;
+ }
+ if (y2 == totalHeight)
+ break;
+ size = Increment_AddY(tree, y2, size);
+ y1 = y2;
+ }
+ if ((visHeight > 1) && (totalHeight -
+ dInfo->yScrollIncrements[dInfo->yScrollIncrementCount - 1] > visHeight))
+ {
+ size = Increment_AddY(tree, totalHeight, size);
+ dInfo->yScrollIncrementCount--;
+ dInfo->yScrollIncrements[dInfo->yScrollIncrementCount - 1] = totalHeight - visHeight;
+ }
+}
+
+static void RangesToIncrementsX(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ Range *range = dInfo->rangeFirst;
+ int visWidth = Tk_Width(tree->tkwin) - tree->inset * 2;
+ int totalWidth = Tree_TotalWidth(tree);
+ int size;
+
+ if (dInfo->rangeFirst == NULL)
+ return;
+
+ /* First increment is zero */
+ size = 10;
+ dInfo->xScrollIncrements = (int *) ckalloc(size * sizeof(int));
+ dInfo->xScrollIncrements[dInfo->xScrollIncrementCount++] = 0;
+
+ range = dInfo->rangeFirst->next;
+ while (range != NULL)
+ {
+ size = Increment_AddX(tree, range->offset, size);
+ range = range->next;
+ }
+ if ((visWidth > 1) && (totalWidth -
+ dInfo->xScrollIncrements[dInfo->xScrollIncrementCount - 1] > visWidth))
+ {
+ size = Increment_AddX(tree, totalWidth, size);
+ dInfo->xScrollIncrementCount--;
+ dInfo->xScrollIncrements[dInfo->xScrollIncrementCount - 1] = totalWidth - visWidth;
+ }
+}
+
+static void RangesToIncrementsY(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ Range *range = dInfo->rangeFirst;
+ int topInset = tree->inset + Tree_HeaderHeight(tree);
+ int visHeight = Tk_Height(tree->tkwin) - topInset - tree->inset;
+ int totalHeight = Tree_TotalHeight(tree);
+ int size;
+
+ if (dInfo->rangeFirst == NULL)
+ return;
+
+ /* First increment is zero */
+ size = 10;
+ dInfo->yScrollIncrements = (int *) ckalloc(size * sizeof(int));
+ dInfo->yScrollIncrements[dInfo->yScrollIncrementCount++] = 0;
+
+ range = dInfo->rangeFirst->next;
+ while (range != NULL)
+ {
+ size = Increment_AddY(tree, range->offset, size);
+ range = range->next;
+ }
+ if ((visHeight > 1) && (totalHeight -
+ dInfo->yScrollIncrements[dInfo->yScrollIncrementCount - 1] > visHeight))
+ {
+ size = Increment_AddY(tree, totalHeight, size);
+ dInfo->yScrollIncrementCount--;
+ dInfo->yScrollIncrements[dInfo->yScrollIncrementCount - 1] = totalHeight - visHeight;
+ }
+}
+
+static void Increment_Redo(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ /* Free x */
+ if (dInfo->xScrollIncrements != NULL)
+ ckfree((char *) dInfo->xScrollIncrements);
+ dInfo->xScrollIncrements = NULL;
+ dInfo->xScrollIncrementCount = 0;
+
+ /* Free y */
+ if (dInfo->yScrollIncrements != NULL)
+ ckfree((char *) dInfo->yScrollIncrements);
+ dInfo->yScrollIncrements = NULL;
+ dInfo->yScrollIncrementCount = 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)
+ Increment_RedoY(tree);
+ }
+ else
+ {
+ /* No xScrollIncrement is given. Snap to left edge of a TreeItem */
+ if (tree->xScrollIncrement <= 0)
+ Increment_RedoX(tree);
+
+ /* No yScrollIncrement is given. Snap to top edge of a Range */
+ if (tree->yScrollIncrement <= 0)
+ RangesToIncrementsY(tree);
+ }
+}
+
+static void Increment_RedoIfNeeded(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ Range_RedoIfNeeded(tree);
+
+ /* Check for x|yScrollIncrement >0 changing to <=0 */
+ if (((dInfo->yScrollIncrement > 0) != (tree->yScrollIncrement > 0)) ||
+ ((dInfo->xScrollIncrement > 0) != (tree->xScrollIncrement > 0)))
+ {
+ dInfo->yScrollIncrement = tree->yScrollIncrement;
+ dInfo->xScrollIncrement = tree->xScrollIncrement;
+ dInfo->flags |= DINFO_REDO_INCREMENTS;
+ }
+ if (dInfo->flags & DINFO_REDO_INCREMENTS)
+ {
+ Increment_Redo(tree);
+ dInfo->flags &= ~DINFO_REDO_INCREMENTS;
+ }
+}
+
+static int B_IncrementFind(int *increments, int count, int offset)
+{
+ 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;
+}
+
+int B_IncrementFindX(TreeCtrl *tree, int offset)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ return B_IncrementFind(
+ dInfo->xScrollIncrements,
+ dInfo->xScrollIncrementCount,
+ offset);
+}
+
+int B_IncrementFindY(TreeCtrl *tree, int offset)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ return B_IncrementFind(
+ dInfo->yScrollIncrements,
+ dInfo->yScrollIncrementCount,
+ offset);
+}
+
+int B_XviewCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[])
+{
+ Tcl_Interp *interp = tree->interp;
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ if (objc == 2)
+ {
+ double fractions[2];
+ char buf[TCL_DOUBLE_SPACE * 2];
+
+ Tree_GetScrollFractionsX(tree, fractions);
+ sprintf(buf, "%g %g", fractions[0], fractions[1]);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ }
+ else
+ {
+ int count, index = 0, indexMax, offset, type;
+ double fraction;
+ int visWidth = Tk_Width(tree->tkwin) - tree->inset * 2;
+ int totWidth = Tree_TotalWidth(tree);
+
+ if (totWidth <= visWidth)
+ return TCL_OK;
+
+ if (visWidth > 1)
+ {
+ /* Find incrementLeft when scrolled to right */
+ indexMax = Increment_FindX(tree, totWidth - visWidth);
+ offset = Increment_ToOffsetX(tree, indexMax);
+ if (offset < totWidth - visWidth)
+ {
+ indexMax++;
+ offset = Increment_ToOffsetX(tree, indexMax);
+ }
+
+ /* Add some fake content to bottom */
+ if (offset + visWidth > totWidth)
+ totWidth = offset + visWidth;
+ }
+ else
+ {
+ indexMax = Increment_FindX(tree, totWidth);
+ visWidth = 1;
+ }
+
+ type = Tk_GetScrollInfoObj(interp, objc, objv, &fraction, &count);
+ 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 = tree->inset + tree->xOrigin;
+ offset += (int) (count * visWidth * 0.9);
+ index = Increment_FindX(tree, offset);
+ if (index == Increment_FindX(tree, tree->inset + tree->xOrigin))
+ index++;
+ break;
+ case TK_SCROLL_UNITS:
+ index = dInfo->incrementLeft + 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 ((index != dInfo->incrementLeft) || (tree->xOrigin != offset - tree->inset))
+ {
+ dInfo->incrementLeft = index;
+ tree->xOrigin = offset - tree->inset;
+ Tree_EventuallyRedraw(tree);
+ }
+ }
+ return TCL_OK;
+}
+
+int B_YviewCmd(TreeCtrl *tree, int objc, Tcl_Obj *CONST objv[])
+{
+ Tcl_Interp *interp = tree->interp;
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ if (objc == 2)
+ {
+ double fractions[2];
+ char buf[TCL_DOUBLE_SPACE * 2];
+
+ Tree_GetScrollFractionsY(tree, fractions);
+ sprintf(buf, "%g %g", fractions[0], fractions[1]);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ }
+ else
+ {
+ int count, index = 0, indexMax, offset, type;
+ double fraction;
+ int topInset = tree->inset + Tree_HeaderHeight(tree);
+ int visHeight = Tk_Height(tree->tkwin) - topInset - tree->inset;
+ int totHeight = Tree_TotalHeight(tree);
+
+ if (totHeight <= visHeight)
+ return TCL_OK;
+
+ if (visHeight > 1)
+ {
+ /* Find incrementTop when scrolled to bottom */
+ indexMax = Increment_FindY(tree, totHeight - visHeight);
+ offset = Increment_ToOffsetY(tree, indexMax);
+ if (offset < totHeight - visHeight)
+ {
+ indexMax++;
+ offset = Increment_ToOffsetY(tree, indexMax);
+ }
+
+ /* Add some fake content to bottom */
+ if (offset + visHeight > totHeight)
+ totHeight = offset + visHeight;
+ }
+ else
+ {
+ indexMax = Increment_FindY(tree, totHeight);
+ visHeight = 1;
+ }
+
+ type = Tk_GetScrollInfoObj(interp, objc, objv, &fraction, &count);
+ 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 = topInset + tree->yOrigin;
+ offset += (int) (count * visHeight * 0.9);
+ index = Increment_FindY(tree, offset);
+ if (index == Increment_FindY(tree, topInset + tree->yOrigin))
+ index++;
+ break;
+ case TK_SCROLL_UNITS:
+ index = dInfo->incrementTop + 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 ((index != dInfo->incrementTop) || (tree->yOrigin != offset - topInset))
+ {
+ dInfo->incrementTop = index;
+ tree->yOrigin = offset - topInset;
+ Tree_EventuallyRedraw(tree);
+ }
+ }
+ return TCL_OK;
+}
+
+#endif /* INCREMENTS */
+
+TreeItem Tree_ItemUnderPoint(TreeCtrl *tree, int *x_, int *y_, int nearest)
+{
+ Range *range;
+ RItem *rItem;
+
+ range = Range_UnderPoint(tree, x_, y_, nearest);
+ if (range == NULL)
+ return NULL;
+ rItem = Range_ItemUnderPoint(tree, range, x_, y_);
+ if (rItem != NULL)
+ return rItem->item;
+ return NULL;
+}
+
+void Tree_ItemBbox(TreeCtrl *tree, TreeItem item, int *x, int *y, int *w, int *h)
+{
+ Range *range;
+ RItem *rItem;
+
+ if (!TreeItem_ReallyVisible(tree, item))
+ return;
+ Range_RedoIfNeeded(tree);
+ rItem = (RItem *) TreeItem_GetRInfo(tree, item);
+ range = rItem->range;
+ if (tree->vertical)
+ {
+ (*x) = range->offset;
+ (*w) = range->totalWidth;
+ (*y) = rItem->offset;
+ (*h) = rItem->size;
+ }
+ else
+ {
+ (*x) = rItem->offset;
+ (*w) = rItem->size;
+ (*y) = range->offset;
+ (*h) = range->totalHeight;
+ }
+}
+
+TreeItem Tree_ItemLARB(TreeCtrl *tree, TreeItem item, int vertical, int prev)
+{
+ RItem *rItem, *rItem2;
+ Range *range;
+ int i, l, u;
+
+ if (!TreeItem_ReallyVisible(tree, item))
+ 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
+ {
+ /* Find the previous range */
+ range = prev ? rItem->range->prev : rItem->range->next;
+ if (range == NULL)
+ return NULL;
+
+ /* Find item with same index */
+ /* Binary search */
+ l = 0;
+ u = range->last->index;
+ while (l <= u)
+ {
+ i = (l + u) / 2;
+ rItem2 = range->first + i;
+ if (rItem2->index == rItem->index)
+ return rItem2->item;
+ if (rItem->index < rItem2->index)
+ u = i - 1;
+ else
+ l = i + 1;
+ }
+ }
+ 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);
+}
+
+TreeItem Tree_ItemFL(TreeCtrl *tree, TreeItem item, int vertical, int first)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ RItem *rItem, *rItem2;
+ Range *range;
+ int i, l, u;
+
+ if (!TreeItem_ReallyVisible(tree, item))
+ 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;
+
+ /* Find item with same index */
+ /* Binary search */
+ l = 0;
+ u = range->last->index;
+ while (l <= u)
+ {
+ i = (l + u) / 2;
+ rItem2 = range->first + i;
+ if (rItem2->index == rItem->index)
+ return rItem2->item;
+ if (rItem->index < rItem2->index)
+ u = i - 1;
+ else
+ l = i + 1;
+ }
+
+ 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);
+}
+
+int Tree_ItemToRNC(TreeCtrl *tree, TreeItem item, int *row, int *col)
+{
+ RItem *rItem;
+
+ if (!TreeItem_ReallyVisible(tree, item))
+ 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;
+}
+
+TreeItem Tree_RNCToItem(TreeCtrl *tree, int row, int col)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ Range *range;
+ RItem *rItem;
+ int i, l, u;
+
+ 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;
+ /* Binary search */
+ l = 0;
+ u = range->last->index;
+ while (l <= u)
+ {
+ i = (l + u) / 2;
+ rItem = range->first + i;
+ if (rItem->index == row)
+ break;
+ if (row < rItem->index)
+ u = i - 1;
+ else
+ l = i + 1;
+ }
+ }
+ 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;
+ /* Binary search */
+ l = 0;
+ u = range->last->index;
+ while (l <= u)
+ {
+ i = (l + u) / 2;
+ rItem = range->first + i;
+ if (rItem->index == col)
+ break;
+ if (col < rItem->index)
+ u = i - 1;
+ else
+ l = i + 1;
+ }
+ }
+ return rItem->item;
+}
+
+/*=============*/
+
+static void DisplayDelay(TreeCtrl *tree)
+{
+ if (tree->debug.enable &&
+ tree->debug.display &&
+ tree->debug.displayDelay > 0)
+ Tcl_Sleep(tree->debug.displayDelay);
+}
+
+static DItem *DItem_Alloc(TreeCtrl *tree, RItem *rItem)
+{
+ DItem *dItem;
+
+ dItem = (DItem *) TreeItem_GetDInfo(tree, rItem->item);
+ if (dItem != NULL)
+ panic("tried to allocate duplicate DItem");
+
+ dItem = (DItem *) ckalloc(sizeof(DItem));
+ memset(dItem, '\0', sizeof(DItem));
+ strncpy(dItem->magic, "MAGC", 4);
+ dItem->item = rItem->item;
+ dItem->flags = DITEM_DIRTY | DITEM_ALL_DIRTY;
+ TreeItem_SetDInfo(tree, rItem->item, (TreeItemDInfo) dItem);
+ return dItem;
+}
+
+static DItem *DItem_Unlink(DItem *head, DItem *dItem)
+{
+ 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;
+}
+
+static DItem *DItem_Free(TreeCtrl *tree, DItem *dItem)
+{
+ DItem *next = dItem->next;
+ if (strncmp(dItem->magic, "MAGC", 4) != 0)
+ panic("DItem_Free: dItem.magic != MAGC");
+ if (dItem->item != NULL)
+ TreeItem_SetDInfo(tree, dItem->item, (TreeItemDInfo) NULL);
+ WFREE(dItem, DItem);
+ return next;
+}
+
+static void FreeDItems(TreeCtrl *tree, DItem *first, DItem *last, int unlink)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ DItem *prev;
+
+ if (unlink)
+ {
+ if (dInfo->dItem == first)
+ dInfo->dItem = last;
+ else
+ {
+ for (prev = dInfo->dItem;
+ prev->next != first;
+ prev = prev->next)
+ {
+ /* nothing */
+ }
+ prev->next = last;
+ }
+ }
+ while (first != last)
+ first = DItem_Free(tree, first);
+}
+
+TreeItem *Tree_ItemsInArea(TreeCtrl *tree, int minX, int minY, int maxX, int maxY)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ int x, y, rx = 0, ry = 0, ix, iy, dx, dy;
+ Range *range;
+ RItem *rItem;
+ TreeItem *items;
+ int count = 0, size = 25;
+
+ 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 < maxX) &&
+ (range->offset + range->totalWidth >= minX))
+ {
+ rx = range->offset;
+ ry = 0;
+ break;
+ }
+ range = range->next;
+ }
+ }
+ else
+ {
+ /* Find the first range which could be in the area vertically */
+ while (range != NULL)
+ {
+ if ((range->offset < maxY) &&
+ (range->offset + range->totalHeight >= minY))
+ {
+ rx = 0;
+ ry = range->offset;
+ break;
+ }
+ range = range->next;
+ }
+ }
+
+ if (range == NULL)
+ return NULL;
+
+ items = (TreeItem *) ckalloc(sizeof(TreeItem) * size);
+
+ while (range != NULL)
+ {
+ if ((rx + range->totalWidth > minX) &&
+ (ry + range->totalHeight > minY))
+ {
+ if (tree->vertical)
+ {
+ /* Range coords */
+ dx = MAX(minX - rx, 0);
+ dy = minY;
+ }
+ else
+ {
+ dx = minX;
+ dy = MAX(minY - ry, 0);
+ }
+ ix = dx;
+ iy = dy;
+ rItem = Range_ItemUnderPoint(tree, range, &ix, &iy);
+
+ /* Canvas coords of top-left of item */
+ x = rx + dx - ix;
+ y = ry + dy - iy;
+
+ while (1)
+ {
+ if (count + 1 > size)
+ {
+ size *= 2;
+ items = (TreeItem *) ckrealloc((char *) items, sizeof(TreeItem) * size);
+ }
+ items[count++] = rItem->item;
+ if (tree->vertical)
+ {
+ y += rItem->size;
+ if (y >= maxY)
+ break;
+ }
+ else
+ {
+ x += rItem->size;
+ if (x >= maxX)
+ break;
+ }
+ 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;
+ }
+
+ /* NULL terminator */
+ if (count + 1 > size)
+ {
+ size += 1;
+ items = (TreeItem *) ckrealloc((char *) items, sizeof(TreeItem) * size);
+ }
+ items[count++] = NULL;
+
+ return items;
+}
+
+static DItem *UpdateDInfoForRange(TreeCtrl *tree, DItem *dItemHead, Range *range, RItem *rItem, int x, int y)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ DItem *dItem;
+ TreeItem item;
+ int maxX, maxY;
+ int index, indexVis;
+
+ maxX = Tk_Width(tree->tkwin) - tree->inset;
+ maxY = Tk_Height(tree->tkwin) - tree->inset;
+
+ /* 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)
+ {
+ case BG_MODE_INDEX: break;
+ case BG_MODE_VISINDEX: index = indexVis; break;
+ case BG_MODE_COLUMN: index = range->index; break;
+ case BG_MODE_ROW: index = rItem->index; break;
+ }
+
+ dItem = (DItem *) TreeItem_GetDInfo(tree, item);
+
+ /* Re-use a previously allocated DItem */
+ if (dItem != NULL)
+ {
+ dItemHead = DItem_Unlink(dItemHead, dItem);
+ if (dInfo->flags & DINFO_INVALIDATE)
+ dItem->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY;
+
+ /* Range height may have changed due to an item resizing */
+ else if (dItem->width != range->totalWidth)
+ dItem->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY;
+
+ /* Items may have alternating background colors. */
+ else if ((tree->columnBgCnt > 1) &&
+ ((index % tree->columnBgCnt) !=
+ (dItem->index % tree->columnBgCnt)))
+ dItem->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))
+ dItem->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 &&
+ ((dItem->oldY & 1) != (y & 1)))
+ dItem->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY;
+ }
+
+ /* Make a new DItem */
+ else
+ {
+ dItem = DItem_Alloc(tree, rItem);
+ }
+
+ dItem->x = x;
+ dItem->y = y;
+ dItem->width = Range_TotalWidth(tree, range);
+ dItem->height = rItem->size;
+ dItem->range = range;
+ dItem->index = index;
+
+ /* Keep track of the maximum item size */
+ if (dItem->width > dInfo->itemWidth)
+ dInfo->itemWidth = dItem->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;
+
+ /* Advance to next TreeItem */
+ rItem++;
+
+ /* Stop when out of bounds */
+ y += dItem->height;
+ if (y >= 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)
+ {
+ case BG_MODE_INDEX: break;
+ case BG_MODE_VISINDEX: index = indexVis; break;
+ case BG_MODE_COLUMN: index = rItem->index; break;
+ case BG_MODE_ROW: index = range->index; break;
+ }
+
+ dItem = (DItem *) TreeItem_GetDInfo(tree, item);
+
+ /* Re-use a previously allocated DItem */
+ if (dItem != NULL)
+ {
+ dItemHead = DItem_Unlink(dItemHead, dItem);
+ if (dInfo->flags & DINFO_INVALIDATE)
+ dItem->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY;
+
+ /* If another item changed size, it may affect the
+ * height/width of this range */
+ else if (dItem->height != range->totalHeight)
+ dItem->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY;
+
+ /* Items may have alternating background colors. */
+ else if ((tree->columnBgCnt > 1) && ((index % tree->columnBgCnt) !=
+ (dItem->index % tree->columnBgCnt)))
+ dItem->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))
+ dItem->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 &&
+ ((dItem->oldY & 1) != (y & 1)))
+ dItem->flags |= DITEM_DIRTY | DITEM_ALL_DIRTY;
+ }
+
+ /* Make a new DItem */
+ else
+ {
+ dItem = DItem_Alloc(tree, rItem);
+ }
+
+ dItem->x = x;
+ dItem->y = y;
+ dItem->width = rItem->size;
+ dItem->height = Range_TotalHeight(tree, range);
+ dItem->range = range;
+ dItem->index = index;
+
+ /* Keep track of the maximum item size */
+ if (dItem->width > dInfo->itemWidth)
+ dInfo->itemWidth = dItem->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;
+
+ /* Advance to next TreeItem */
+ rItem++;
+
+ /* Stop when out of bounds */
+ x += dItem->width;
+ if (x >= maxX)
+ break;
+ }
+ }
+
+ return dItemHead;
+}
+
+void Tree_UpdateDInfo(TreeCtrl *tree)
+{
+ DInfo *dInfo = (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;
+
+if (tree->debug.enable && tree->debug.display)
+ dbwin("Tree_UpdateDInfo %s\n", Tk_PathName(tree->tkwin));
+
+ minX = tree->inset;
+ minY = tree->inset + Tree_HeaderHeight(tree);
+ maxX = Tk_Width(tree->tkwin) - tree->inset;
+ maxY = Tk_Height(tree->tkwin) - tree->inset;
+
+ if ((maxX - minX < 1) || (maxY - minY < 1))
+ goto done;
+
+ 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 < maxX + tree->xOrigin) &&
+ (range->offset + range->totalWidth >= minX + tree->xOrigin))
+ {
+ rx = range->offset;
+ ry = 0;
+ 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 < maxY + tree->yOrigin) &&
+ (range->offset + range->totalHeight >= minY + tree->yOrigin))
+ {
+ rx = 0;
+ ry = range->offset;
+ break;
+ }
+ range = range->next;
+ }
+ }
+
+ dInfo->dItem = dInfo->dItemLast = NULL;
+ dInfo->rangeFirstD = dInfo->rangeLastD = NULL;
+ dInfo->itemWidth = dInfo->itemHeight = 0;
+
+ while (range != NULL)
+ {
+ if ((rx + range->totalWidth > minX + tree->xOrigin) &&
+ (ry + range->totalHeight > minY + tree->yOrigin))
+ {
+ if (tree->vertical)
+ {
+ /* Range coords */
+ dx = MAX(minX + tree->xOrigin - rx, 0);
+ dy = minY + tree->yOrigin;
+ }
+ else
+ {
+ dx = minX + tree->xOrigin;
+ dy = MAX(minY + tree->yOrigin - ry, 0);
+ }
+ ix = dx;
+ iy = dy;
+ rItem = Range_ItemUnderPoint(tree, range, &ix, &iy);
+
+ /* Window coords of top-left of item */
+ x = (rx - tree->xOrigin) + dx - ix;
+ y = (ry - tree->yOrigin) + dy - iy;
+ dItemHead = UpdateDInfoForRange(tree, dItemHead, range, rItem, x, y);
+ }
+
+ /* Track this range even if it has no DItems, so we whitespace is
+ * erased */
+ if (dInfo->rangeFirstD == NULL)
+ dInfo->rangeFirstD = range;
+ dInfo->rangeLastD = range;
+
+ if (tree->vertical)
+ {
+ rx += range->totalWidth;
+ if (rx >= maxX + tree->xOrigin)
+ break;
+ }
+ else
+ {
+ ry += range->totalHeight;
+ if (ry >= maxY + tree->yOrigin)
+ break;
+ }
+ range = range->next;
+ }
+
+ if (dInfo->dItemLast != NULL)
+ dInfo->dItemLast->next = NULL;
+done:
+ while (dItemHead != NULL)
+ dItemHead = DItem_Free(tree, dItemHead);
+
+ dInfo->flags &= ~DINFO_INVALIDATE;
+}
+
+static void InvalidateDItemX(DItem *dItem, int itemX, int dirtyX, int dirtyWidth)
+{
+ int x1, x2;
+
+ if (dirtyX <= itemX)
+ dItem->dirty[LEFT] = 0;
+ else
+ {
+ x1 = dirtyX - itemX;
+ if (!(dItem->flags & DITEM_DIRTY) || (x1 < dItem->dirty[LEFT]))
+ dItem->dirty[LEFT] = x1;
+ }
+
+ if (dirtyX + dirtyWidth >= itemX + dItem->width)
+ dItem->dirty[RIGHT] = dItem->width;
+ else
+ {
+ x2 = dirtyX + dirtyWidth - itemX;
+ if (!(dItem->flags & DITEM_DIRTY) || (x2 > dItem->dirty[RIGHT]))
+ dItem->dirty[RIGHT] = x2;
+ }
+}
+
+static void InvalidateDItemY(DItem *dItem, int itemY, int dirtyY, int dirtyHeight)
+{
+ int y1, y2;
+
+ if (dirtyY <= itemY)
+ dItem->dirty[TOP] = 0;
+ else
+ {
+ y1 = dirtyY - itemY;
+ if (!(dItem->flags & DITEM_DIRTY) || (y1 < dItem->dirty[TOP]))
+ dItem->dirty[TOP] = y1;
+ }
+
+ if (dirtyY + dirtyHeight >= itemY + dItem->height)
+ dItem->dirty[BOTTOM] = dItem->height;
+ else
+ {
+ y2 = dirtyY + dirtyHeight - itemY;
+ if (!(dItem->flags & DITEM_DIRTY) || (y2 > dItem->dirty[BOTTOM]))
+ dItem->dirty[BOTTOM] = y2;
+ }
+}
+
+void Range_RedoIfNeeded(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ 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;
+
+ /* Do this after clearing REDO_RANGES to prevent infinite loop */
+ tree->totalWidth = tree->totalHeight = -1;
+ (void) Tree_TotalWidth(tree);
+ (void) Tree_TotalHeight(tree);
+#ifdef INCREMENTS
+ dInfo->flags |= DINFO_REDO_INCREMENTS;
+#endif
+ }
+}
+
+static int ScrollVerticalComplex(TreeCtrl *tree)
+{
+ DInfo *dInfo = (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;
+
+ minX = tree->inset;
+ maxX = Tk_Width(tree->tkwin) - tree->inset;
+ minY = tree->inset + Tree_HeaderHeight(tree);
+ maxY = Tk_Height(tree->tkwin) - tree->inset;
+
+ /* 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->flags & DITEM_ALL_DIRTY) ||
+ (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) ||
+ (dItem2->flags & DITEM_ALL_DIRTY) ||
+ (dItem2->oldY + offset != dItem2->y))
+ break;
+numCopy++;
+ height += dItem2->height;
+ }
+
+ 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);
+
+ oldX = dItem->oldX;
+ width = dItem->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))
+ {
+ InvalidateDItemX(dItem, oldX, oldX, width);
+ InvalidateDItemY(dItem, dItem->oldY, dItem->oldY, minY - dItem->oldY);
+ dItem->flags |= DITEM_DIRTY;
+ }
+ if ((dItem->oldY + dItem->height > maxY) && (offset < 0))
+ {
+ InvalidateDItemX(dItem, oldX, oldX, width);
+ InvalidateDItemY(dItem, dItem->oldY, maxY, maxY - dItem->oldY + dItem->height);
+ dItem->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 (!(dItem2->flags & DITEM_ALL_DIRTY) &&
+ (dItem2->oldY + dItem2->height > y) &&
+ (dItem2->oldY < y + height))
+ {
+ InvalidateDItemX(dItem2, oldX, oldX, width);
+ InvalidateDItemY(dItem2, dItem2->oldY, y, height);
+ dItem2->flags |= DITEM_DIRTY;
+ }
+ }
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ {
+ int dirtyMin, dirtyMax;
+ XCopyArea(tree->display, dInfo->pixmap, dInfo->pixmap,
+ tree->copyGC,
+ oldX, oldY, width, height,
+ oldX, oldY + offset);
+ dirtyMin = MAX(oldY, oldY + offset + height);
+ dirtyMax = MIN(oldY + height, oldY + offset);
+ Tree_InvalidateArea(tree, oldX, dirtyMin, width, dirtyMax - dirtyMin);
+ dInfo->dirty[LEFT] = MIN(dInfo->dirty[LEFT], oldX);
+ dInfo->dirty[TOP] = MIN(dInfo->dirty[TOP], oldY + offset);
+ dInfo->dirty[RIGHT] = MAX(dInfo->dirty[RIGHT], oldX + width);
+ dInfo->dirty[BOTTOM] = MAX(dInfo->dirty[BOTTOM], oldY + offset + height);
+ continue;
+ }
+
+ /* Copy */
+ damageRgn = TkCreateRegion();
+ if (TkScrollWindow(tree->tkwin, dInfo->scrollGC,
+ oldX, oldY, width, height, 0, offset, damageRgn))
+ {
+DisplayDelay(tree);
+ Tree_InvalidateRegion(tree, damageRgn);
+ }
+ TkDestroyRegion(damageRgn);
+ }
+ return numCopy;
+}
+
+static void ScrollHorizontalSimple(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ DItem *dItem;
+ TkRegion damageRgn;
+ int minX, minY, maxX, maxY;
+ int width, offset;
+ int x;
+
+ minX = tree->inset;
+ maxX = Tk_Width(tree->tkwin) - tree->inset;
+ minY = tree->inset + Tree_HeaderHeight(tree);
+ maxY = Tk_Height(tree->tkwin) - tree->inset;
+
+ /* Horizontal scrolling */
+ if (dInfo->xOrigin != tree->xOrigin)
+ {
+ int dirtyMin, dirtyMax;
+
+ offset = dInfo->xOrigin - tree->xOrigin;
+ width = maxX - minX - abs(offset);
+ if (width < 0)
+ width = maxX - minX;
+ /* Move pixels right */
+ if (offset > 0)
+ {
+ x = minX;
+ }
+ /* Move pixels left */
+ else
+ {
+ x = maxX - width;
+ }
+
+ dirtyMin = minX + width;
+ dirtyMax = maxX - width;
+
+ /* Update oldX */
+ for (dItem = dInfo->dItem;
+ dItem != NULL;
+ dItem = dItem->next)
+ {
+ dItem->oldX = dItem->x;
+ }
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ {
+ XCopyArea(tree->display, dInfo->pixmap, dInfo->pixmap,
+ tree->copyGC,
+ x, minY, width, maxY - minY,
+ x + offset, minY);
+ if (offset < 0)
+ dirtyMax = maxX;
+ else
+ dirtyMin = minX;
+ Tree_InvalidateArea(tree, dirtyMin, minY, dirtyMax, maxY);
+ return;
+ }
+ /* Copy */
+ damageRgn = TkCreateRegion();
+ if (TkScrollWindow(tree->tkwin, dInfo->scrollGC,
+ x, minY, width, maxY - minY, offset, 0, damageRgn))
+ {
+ DisplayDelay(tree);
+ Tree_InvalidateRegion(tree, damageRgn);
+ }
+ TkDestroyRegion(damageRgn);
+#ifndef WIN32
+ if (offset < 0)
+ dirtyMax = maxX;
+ else
+ dirtyMin = minX;
+#endif
+ if (dirtyMin < dirtyMax)
+ Tree_InvalidateArea(tree, dirtyMin, minY, dirtyMax, maxY);
+ }
+}
+
+static void ScrollVerticalSimple(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ DItem *dItem;
+ TkRegion damageRgn;
+ int minX, minY, maxX, maxY;
+ int height, offset;
+ int y;
+
+ minX = tree->inset;
+ maxX = Tk_Width(tree->tkwin) - tree->inset;
+ minY = tree->inset + Tree_HeaderHeight(tree);
+ maxY = Tk_Height(tree->tkwin) - tree->inset;
+
+ /* Vertical scrolling */
+ if (dInfo->yOrigin != tree->yOrigin)
+ {
+ int dirtyMin, dirtyMax;
+
+ offset = dInfo->yOrigin - tree->yOrigin;
+ height = maxY - minY - abs(offset);
+ if (height < 0)
+ height = maxY - minY;
+ /* Move pixels down */
+ if (offset > 0)
+ {
+ y = minY;
+ }
+ /* Move pixels up */
+ else
+ {
+ y = maxY - height;
+ }
+
+ dirtyMin = minY + height;
+ dirtyMax = maxY - height;
+
+ /* Update oldY */
+ for (dItem = dInfo->dItem;
+ dItem != NULL;
+ dItem = dItem->next)
+ {
+ dItem->oldY = dItem->y;
+ }
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ {
+ XCopyArea(tree->display, dInfo->pixmap, dInfo->pixmap,
+ tree->copyGC,
+ minX, y, maxX - minX, height,
+ minX, y + offset);
+ if (offset < 0)
+ dirtyMax = maxY;
+ else
+ dirtyMin = minY;
+ Tree_InvalidateArea(tree, minX, dirtyMin, maxX, dirtyMax);
+ return;
+ }
+
+ /* Copy */
+ damageRgn = TkCreateRegion();
+ if (TkScrollWindow(tree->tkwin, dInfo->scrollGC,
+ minX, y, maxX - minX, height, 0, offset, damageRgn))
+ {
+DisplayDelay(tree);
+ Tree_InvalidateRegion(tree, damageRgn);
+ }
+ TkDestroyRegion(damageRgn);
+#ifndef WIN32
+ if (offset < 0)
+ dirtyMax = maxY;
+ else
+ dirtyMin = minY;
+#endif
+ if (dirtyMin < dirtyMax)
+ Tree_InvalidateArea(tree, minX, dirtyMin, maxX, dirtyMax);
+ }
+}
+
+static int ScrollHorizontalComplex(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ DItem *dItem, *dItem2;
+ Range *range;
+ TkRegion damageRgn;
+ int minX, minY, maxX, maxY;
+ int oldX, oldY, width, height, offset;
+ int x;
+ int numCopy = 0;
+
+ minX = tree->inset;
+ maxX = Tk_Width(tree->tkwin) - tree->inset;
+ minY = tree->inset + Tree_HeaderHeight(tree);
+ maxY = Tk_Height(tree->tkwin) - tree->inset;
+
+ /* 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->flags & DITEM_ALL_DIRTY) ||
+ (dItem->oldX == dItem->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->x - dItem->oldX;
+ width = dItem->width;
+ for (dItem2 = dItem->next;
+ dItem2 != NULL;
+ dItem2 = dItem2->next)
+ {
+ if ((dItem2->range != range) ||
+ (dItem2->flags & DITEM_ALL_DIRTY) ||
+ (dItem2->oldX + offset != dItem2->x))
+ break;
+numCopy++;
+ width += dItem2->width;
+ }
+
+ x = dItem->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->oldX, dItem->oldX, minX - dItem->oldX);
+ InvalidateDItemY(dItem, oldY, oldY, height);
+ dItem->flags |= DITEM_DIRTY;
+ }
+ if ((dItem->oldX + dItem->width > maxX) && (offset < 0))
+ {
+ InvalidateDItemX(dItem, dItem->oldX, maxX, maxX - dItem->oldX + dItem->width);
+ InvalidateDItemY(dItem, oldY, oldY, height);
+ dItem->flags |= DITEM_DIRTY;
+ }
+
+ dItem->oldX = dItem->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->flags & DITEM_ALL_DIRTY) &&
+ (dItem2->oldX + dItem2->width > x) &&
+ (dItem2->oldX < x + width))
+ {
+ InvalidateDItemX(dItem2, dItem2->oldX, x, width);
+ InvalidateDItemY(dItem2, oldY, oldY, height);
+ dItem2->flags |= DITEM_DIRTY;
+ }
+ }
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ {
+ XCopyArea(tree->display, dInfo->pixmap, dInfo->pixmap,
+ tree->copyGC,
+ oldX, oldY, width, height,
+ oldX + offset, oldY);
+ Tree_InvalidateArea(tree, oldX, oldY, width, height);
+ dInfo->dirty[LEFT] = MIN(dInfo->dirty[LEFT], oldX + offset);
+ dInfo->dirty[TOP] = MIN(dInfo->dirty[TOP], oldY);
+ dInfo->dirty[RIGHT] = MAX(dInfo->dirty[RIGHT], oldX + offset + width);
+ dInfo->dirty[BOTTOM] = MAX(dInfo->dirty[BOTTOM], oldY + height);
+ continue;
+ }
+
+ /* Copy */
+ damageRgn = TkCreateRegion();
+ if (TkScrollWindow(tree->tkwin, dInfo->scrollGC,
+ oldX, oldY, width, height, offset, 0, damageRgn))
+ {
+DisplayDelay(tree);
+ Tree_InvalidateRegion(tree, damageRgn);
+ }
+ TkDestroyRegion(damageRgn);
+ }
+ return numCopy;
+}
+
+void TreeColumnProxy_Draw(TreeCtrl *tree)
+{
+ XGCValues gcValues;
+ unsigned long gcMask;
+ GC gc;
+
+ gcValues.function = GXinvert;
+ gcValues.graphics_exposures = False;
+ gcMask = GCFunction | GCGraphicsExposures;
+ gc = Tk_GetGC(tree->tkwin, gcMask, &gcValues);
+
+ /* GXinvert doesn't work with XFillRectangle() on Win32 */
+#ifdef WIN32
+ XDrawLine(tree->display, Tk_WindowId(tree->tkwin), gc,
+ tree->columnProxy.sx,
+ tree->inset,
+ tree->columnProxy.sx,
+ Tk_Height(tree->tkwin) - tree->inset);
+#else
+ XFillRectangle(tree->display, Tk_WindowId(tree->tkwin), gc,
+ tree->columnProxy.sx,
+ tree->inset,
+ 1,
+ Tk_Height(tree->tkwin) - tree->inset * 2);
+#endif
+
+ Tk_FreeGC(tree->display, gc);
+}
+
+void TreeColumnProxy_Undisplay(TreeCtrl *tree)
+{
+ if (tree->columnProxy.onScreen)
+ {
+ TreeColumnProxy_Draw(tree);
+ tree->columnProxy.onScreen = FALSE;
+ }
+}
+
+void TreeColumnProxy_Display(TreeCtrl *tree)
+{
+ if (!tree->columnProxy.onScreen && (tree->columnProxy.xObj != NULL))
+ {
+ tree->columnProxy.sx = tree->columnProxy.x;
+ TreeColumnProxy_Draw(tree);
+ tree->columnProxy.onScreen = TRUE;
+ }
+}
+
+void Tree_Display(ClientData clientData)
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ DItem *dItem;
+ Range *range;
+ Tk_Window tkwin = tree->tkwin;
+ Drawable drawable = Tk_WindowId(tkwin);
+ int x, y, minX, minY, maxX, maxY, height, width;
+ int left, right, top, bottom;
+ int count;
+ int numCopy = 0, numDraw = 0;
+
+if (tree->debug.enable && tree->debug.display && 0)
+ dbwin("Tree_Display %s\n", Tk_PathName(tree->tkwin));
+
+ if (tree->deleted)
+ {
+ dInfo->flags &= ~(DINFO_REDRAW_PENDING);
+ return;
+ }
+ /* The width of one or more columns *might* have changed */
+ if (dInfo->flags & DINFO_CHECK_COLUMN_WIDTH)
+ {
+ TreeColumn treeColumn = tree->columns;
+ int columnIndex = 0;
+
+ while (treeColumn != NULL)
+ {
+ if (dInfo->columnWidth[columnIndex] != TreeColumn_UseWidth(treeColumn))
+ {
+ dInfo->columnWidth[columnIndex] = TreeColumn_UseWidth(treeColumn);
+ dInfo->flags |=
+ DINFO_INVALIDATE |
+ DINFO_OUT_OF_DATE |
+ DINFO_REDO_RANGES |
+ DINFO_DRAW_HEADER;
+ }
+ columnIndex++;
+ treeColumn = TreeColumn_Next(treeColumn);
+ }
+ dInfo->flags &= ~DINFO_CHECK_COLUMN_WIDTH;
+ }
+ Range_RedoIfNeeded(tree);
+#ifdef INCREMENTS
+ Increment_RedoIfNeeded(tree);
+#endif
+ 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_TotalWidth(tree))
+ {
+ dInfo->totalWidth = Tree_TotalWidth(tree);
+ dInfo->flags |=
+ DINFO_SET_ORIGIN_X |
+ DINFO_UPDATE_SCROLLBAR_X |
+ DINFO_OUT_OF_DATE;
+ }
+ if (dInfo->totalHeight != Tree_TotalHeight(tree))
+ {
+ dInfo->totalHeight = Tree_TotalHeight(tree);
+ dInfo->flags |=
+ DINFO_SET_ORIGIN_Y |
+ DINFO_UPDATE_SCROLLBAR_Y |
+ DINFO_OUT_OF_DATE;
+ }
+ if (dInfo->headerHeight != Tree_HeaderHeight(tree))
+ {
+ dInfo->headerHeight = Tree_HeaderHeight(tree);
+ dInfo->flags |=
+ DINFO_OUT_OF_DATE |
+ DINFO_SET_ORIGIN_Y |
+ DINFO_UPDATE_SCROLLBAR_Y |
+ DINFO_DRAW_HEADER;
+ }
+ 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;
+ }
+ if (dInfo->flags & DINFO_UPDATE_SCROLLBAR_X)
+ {
+ Tree_UpdateScrollbarX(tree);
+ dInfo->flags &= ~DINFO_UPDATE_SCROLLBAR_X;
+ }
+ if (dInfo->flags & DINFO_UPDATE_SCROLLBAR_Y)
+ {
+ Tree_UpdateScrollbarY(tree);
+ dInfo->flags &= ~DINFO_UPDATE_SCROLLBAR_Y;
+ }
+ if (tree->deleted || !Tk_IsMapped(tkwin))
+ {
+ dInfo->flags &= ~(DINFO_REDRAW_PENDING);
+ return;
+ }
+ if (dInfo->flags & DINFO_OUT_OF_DATE)
+ {
+ Tree_UpdateDInfo(tree);
+ dInfo->flags &= ~DINFO_OUT_OF_DATE;
+ }
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ {
+ dInfo->dirty[LEFT] = dInfo->dirty[TOP] = 100000;
+ dInfo->dirty[RIGHT] = dInfo->dirty[BOTTOM] = -100000;
+ }
+
+ minX = tree->inset;
+ maxX = Tk_Width(tree->tkwin) - tree->inset;
+ minY = tree->inset + Tree_HeaderHeight(tree);
+ maxY = Tk_Height(tree->tkwin) - tree->inset;
+
+ /* XOR off */
+ TreeColumnProxy_Undisplay(tree);
+ TreeDragImage_Undisplay(tree->dragImage);
+ TreeMarquee_Undisplay(tree->marquee);
+
+ if (dInfo->flags & DINFO_DRAW_HEADER)
+ {
+ if (tree->showHeader)
+ {
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ {
+ Tree_DrawHeader(tree, dInfo->pixmap, 0 - tree->xOrigin,
+ tree->inset);
+ dInfo->dirty[LEFT] = minX;
+ dInfo->dirty[TOP] = tree->inset;
+ dInfo->dirty[RIGHT] = maxX;
+ dInfo->dirty[BOTTOM] = minY;
+ }
+ else
+ Tree_DrawHeader(tree, drawable, 0 - tree->xOrigin, tree->inset);
+ }
+ 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))
+ {
+ dInfo->dirty[LEFT] = minX;
+ /* might include header */
+ dInfo->dirty[TOP] = MIN(dInfo->dirty[TOP], minY);
+ dInfo->dirty[RIGHT] = maxX;
+ dInfo->dirty[BOTTOM] = maxY;
+ }
+ }
+
+ dInfo->xOrigin = tree->xOrigin;
+ dInfo->yOrigin = tree->yOrigin;
+
+ /* Does this need to be here? */
+ dInfo->flags &= ~(DINFO_REDRAW_PENDING);
+
+ /* See if there are any dirty items */
+ count = 0;
+ for (dItem = dInfo->dItem;
+ dItem != NULL;
+ dItem = dItem->next)
+ {
+ if (dItem->flags & DITEM_DIRTY)
+ {
+ count++;
+ break;
+ }
+ }
+
+ /* Display dirty items */
+ if (count > 0)
+ {
+ Drawable pixmap = drawable;
+ if (tree->doubleBuffer != DOUBLEBUFFER_NONE)
+ {
+ /* Allocate pixmap for largest item */
+ width = MIN(maxX - minX, dInfo->itemWidth);
+ height = MIN(maxY - minY, dInfo->itemHeight);
+ pixmap = Tk_GetPixmap(tree->display, Tk_WindowId(tkwin),
+ width, height, Tk_Depth(tkwin));
+ }
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ drawable = dInfo->pixmap;
+ for (dItem = dInfo->dItem;
+ dItem != NULL;
+ dItem = dItem->next)
+ {
+ if (!(dItem->flags & DITEM_DIRTY))
+ continue;
+
+ if (dItem->flags & DITEM_ALL_DIRTY)
+ {
+ left = dItem->x;
+ right = dItem->x + dItem->width;
+ top = dItem->y;
+ bottom = dItem->y + dItem->height;
+ }
+ else
+ {
+ left = dItem->x + dItem->dirty[LEFT];
+ right = dItem->x + dItem->dirty[RIGHT];
+ top = dItem->y + dItem->dirty[TOP];
+ bottom = dItem->y + dItem->dirty[BOTTOM];
+ }
+ if (left < minX)
+ left = minX;
+ if (right > maxX)
+ right = maxX;
+ if (top < minY)
+ top = minY;
+ if (bottom > maxY)
+ bottom = maxY;
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ {
+ dInfo->dirty[LEFT] = MIN(dInfo->dirty[LEFT], left);
+ dInfo->dirty[TOP] = MIN(dInfo->dirty[TOP], top);
+ dInfo->dirty[RIGHT] = MAX(dInfo->dirty[RIGHT], right);
+ dInfo->dirty[BOTTOM] = MAX(dInfo->dirty[BOTTOM], bottom);
+ }
+
+ if (tree->doubleBuffer != DOUBLEBUFFER_NONE)
+ {
+ /* The top-left corner of the drawable is at this
+ * point in the canvas */
+ tree->drawableXOrigin = left + tree->xOrigin;
+ tree->drawableYOrigin = top + tree->yOrigin;
+
+ TreeItem_Draw(tree, dItem->item,
+ dItem->x - left,
+ dItem->y - top,
+ dItem->width, dItem->height,
+ pixmap,
+ 0, right - left,
+ dItem->index);
+ if (tree->columnTreeVis && tree->showLines)
+ {
+ TreeItem_DrawLines(tree, dItem->item,
+ dItem->x - left,
+ dItem->y - top,
+ dItem->width, dItem->height,
+ pixmap);
+ }
+ if (tree->columnTreeVis && tree->showButtons)
+ {
+ TreeItem_DrawButton(tree, dItem->item,
+ dItem->x - left,
+ dItem->y - top,
+ dItem->width, dItem->height,
+ pixmap);
+ }
+ XCopyArea(tree->display, pixmap, drawable,
+ tree->copyGC,
+ 0, 0,
+ right - left, bottom - top,
+ left, top);
+ }
+ /* DOUBLEBUFFER_NONE */
+ 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,
+ dItem->x,
+ dItem->y,
+ dItem->width, dItem->height,
+ pixmap,
+ minX, maxX,
+ dItem->index);
+ if (tree->columnTreeVis && tree->showLines)
+ {
+ TreeItem_DrawLines(tree, dItem->item,
+ dItem->x,
+ dItem->y,
+ dItem->width, dItem->height,
+ pixmap);
+ }
+ if (tree->columnTreeVis && tree->showButtons)
+ {
+ TreeItem_DrawButton(tree, dItem->item,
+ dItem->x,
+ dItem->y,
+ dItem->width, dItem->height,
+ pixmap);
+ }
+ }
+DisplayDelay(tree);
+numDraw++;
+
+ dItem->oldX = dItem->x;
+ dItem->oldY = dItem->y;
+ dItem->flags &= ~(DITEM_DIRTY | DITEM_ALL_DIRTY);
+ }
+ if (tree->doubleBuffer != DOUBLEBUFFER_NONE)
+ Tk_FreePixmap(tree->display, pixmap);
+ }
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ drawable = dInfo->pixmap;
+
+if (tree->debug.enable && tree->debug.display)
+ dbwin("copy %d draw %d %s\n", numCopy, numDraw, Tk_PathName(tree->tkwin));
+
+ x = 0 - tree->xOrigin;
+ y = 0 - tree->yOrigin;
+
+ if (tree->vertical)
+ {
+ /* Erase area to right of last Range */
+ if (x + Tree_TotalWidth(tree) < maxX)
+ {
+ Tk_Fill3DRectangle(tkwin, drawable, tree->border,
+ x + Tree_TotalWidth(tree), minY,
+ maxX - (x + Tree_TotalWidth(tree)),
+ maxY - minY, 0, TK_RELIEF_FLAT);
+ }
+ }
+ else
+ {
+ /* Erase area below last Range */
+ if (y + Tree_TotalHeight(tree) < maxY)
+ {
+ Tk_Fill3DRectangle(tkwin, drawable, tree->border,
+ tree->inset,
+ y + Tree_TotalHeight(tree),
+ Tk_Width(tkwin) - tree->inset * 2,
+ maxY - (y + Tree_TotalHeight(tree)),
+ 0, TK_RELIEF_FLAT);
+ }
+ }
+
+ for (range = dInfo->rangeFirstD;
+ range != NULL;
+ range = range->next)
+ {
+ if (tree->vertical)
+ {
+ left = MAX(x + range->offset, minX);
+ right = MIN(x + range->offset + range->totalWidth, maxX);
+ top = MAX(y + range->totalHeight, minY);
+ bottom = maxY;
+
+ /* Erase area below Range */
+ if (top < bottom)
+ {
+ Tk_Fill3DRectangle(tkwin, drawable, tree->border,
+ left,
+ top,
+ right - left,
+ bottom - top,
+ 0, TK_RELIEF_FLAT);
+ }
+ }
+ else
+ {
+ left = MAX(x + range->totalWidth, minX);
+ right = maxX;
+ top = MAX(y + range->offset, minY);
+ bottom = MIN(y + range->offset + range->totalHeight, maxY);
+
+ /* Erase area to right of Range */
+ if (left < right)
+ {
+ Tk_Fill3DRectangle(tkwin, drawable, tree->border,
+ left, top,
+ right - left,
+ bottom - top, 0, TK_RELIEF_FLAT);
+ }
+ }
+ if (range == dInfo->rangeLastD)
+ break;
+ }
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ {
+ drawable = Tk_WindowId(tree->tkwin);
+ XCopyArea(tree->display, dInfo->pixmap, drawable,
+ tree->copyGC,
+ dInfo->dirty[LEFT], dInfo->dirty[TOP],
+ dInfo->dirty[RIGHT] - dInfo->dirty[LEFT],
+ dInfo->dirty[BOTTOM] - dInfo->dirty[TOP],
+ dInfo->dirty[LEFT],dInfo-> dirty[TOP]);
+ }
+
+ /* XOR on */
+ TreeMarquee_Display(tree->marquee);
+ TreeDragImage_Display(tree->dragImage);
+ TreeColumnProxy_Display(tree);
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_NONE)
+ dInfo->flags |= DINFO_DRAW_HIGHLIGHT | DINFO_DRAW_BORDER;
+
+ /* Draw focus rectangle (outside of 3D-border) */
+ if ((dInfo->flags & DINFO_DRAW_HIGHLIGHT) && (tree->highlightWidth > 0))
+ {
+ GC fgGC, bgGC;
+
+ 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))
+ {
+ 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;
+ }
+}
+
+static int A_IncrementFindX(TreeCtrl *tree, int offset)
+{
+ int totWidth = Tree_TotalWidth(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;
+}
+
+static int A_IncrementFindY(TreeCtrl *tree, int offset)
+{
+ int totHeight = Tree_TotalHeight(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 Increment_FindX(TreeCtrl *tree, int offset)
+{
+#ifdef INCREMENTS
+ if (tree->xScrollIncrement <= 0)
+ {
+ Increment_RedoIfNeeded(tree);
+ return B_IncrementFindX(tree, offset);
+ }
+#endif
+ return A_IncrementFindX(tree, offset);
+}
+
+int Increment_FindY(TreeCtrl *tree, int offset)
+{
+#ifdef INCREMENTS
+ if (tree->yScrollIncrement <= 0)
+ {
+ Increment_RedoIfNeeded(tree);
+ return B_IncrementFindY(tree, offset);
+ }
+#endif
+ return A_IncrementFindY(tree, offset);
+}
+
+int Increment_ToOffsetX(TreeCtrl *tree, int index)
+{
+#ifdef INCREMENTS
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ if (tree->xScrollIncrement <= 0)
+ {
+ if (index < 0 || index >= dInfo->xScrollIncrementCount)
+ panic("Increment_ToOffsetX: bad index %d (must be 0-%d)",
+ index, dInfo->xScrollIncrementCount-1);
+ return dInfo->xScrollIncrements[index];
+ }
+#endif
+ return index * tree->xScrollIncrement;
+}
+
+int Increment_ToOffsetY(TreeCtrl *tree, int index)
+{
+#ifdef INCREMENTS
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ if (tree->yScrollIncrement <= 0)
+ {
+ if (index < 0 || index >= dInfo->yScrollIncrementCount)
+ {
+ panic("Increment_ToOffsetY: bad index %d (must be 0-%d)\ntotHeight %d visHeight %d",
+ index, dInfo->yScrollIncrementCount - 1,
+ Tree_TotalHeight(tree), Tk_Height(tree->tkwin) - Tree_HeaderHeight(tree) - tree->inset);
+ }
+ return dInfo->yScrollIncrements[index];
+ }
+#endif
+ return index * tree->yScrollIncrement;
+}
+
+static void GetScrollFractions(int screen1, int screen2, int object1,
+ int object2, double fractions[2])
+{
+ 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;
+}
+
+void Tree_GetScrollFractionsX(TreeCtrl *tree, double fractions[2])
+{
+ int left = tree->xOrigin + tree->inset;
+ int visWidth = Tk_Width(tree->tkwin) - tree->inset * 2;
+ int totWidth = Tree_TotalWidth(tree);
+ int index, offset;
+
+ /* The tree is empty, or everything fits in the window */
+ if (totWidth <= visWidth)
+ {
+ fractions[0] = 0.0;
+ fractions[1] = 1.0;
+ return;
+ }
+
+ if (visWidth <= 1)
+ {
+ GetScrollFractions(left, left + 1, 0, totWidth, fractions);
+ return;
+ }
+
+ /* Find incrementLeft when scrolled to extreme right */
+ index = Increment_FindX(tree, totWidth - visWidth);
+ offset = Increment_ToOffsetX(tree, index);
+ if (offset < totWidth - visWidth)
+ {
+ index++;
+ offset = Increment_ToOffsetX(tree, index);
+ }
+
+ /* Add some fake content to right */
+ if (offset + visWidth > totWidth)
+ totWidth = offset + visWidth;
+
+ GetScrollFractions(left, left + visWidth, 0, totWidth, fractions);
+}
+
+void Tree_GetScrollFractionsY(TreeCtrl *tree, double fractions[2])
+{
+ int topInset = tree->inset + Tree_HeaderHeight(tree);
+ int top = topInset + tree->yOrigin; /* canvas coords */
+ int visHeight = Tk_Height(tree->tkwin) - topInset - tree->inset;
+ int totHeight = Tree_TotalHeight(tree);
+ int index, offset;
+
+ /* The tree is empty, or everything fits in the window */
+ if (totHeight <= visHeight)
+ {
+ fractions[0] = 0.0;
+ fractions[1] = 1.0;
+ return;
+ }
+
+ if (visHeight <= 1)
+ {
+ GetScrollFractions(top, top + 1, 0, totHeight, fractions);
+ return;
+ }
+
+ /* Find incrementTop when scrolled to bottom */
+ index = Increment_FindY(tree, totHeight - visHeight);
+ offset = Increment_ToOffsetY(tree, index);
+ if (offset < totHeight - visHeight)
+ {
+ index++;
+ offset = Increment_ToOffsetY(tree, index);
+ }
+
+ /* Add some fake content to bottom */
+ if (offset + visHeight > totHeight)
+ totHeight = offset + visHeight;
+
+ GetScrollFractions(top, top + visHeight, 0, totHeight, fractions);
+}
+
+void Tree_SetOriginX(TreeCtrl *tree, int xOrigin)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ int totWidth = Tree_TotalWidth(tree);
+ int visWidth = Tk_Width(tree->tkwin) - tree->inset * 2;
+ int index, indexMax, offset;
+
+ /* The tree is empty, or everything fits in the window */
+ if (totWidth <= visWidth)
+ {
+ xOrigin = 0 - tree->inset;
+ if (xOrigin != tree->xOrigin)
+ {
+ tree->xOrigin = xOrigin;
+#ifdef INCREMENTS
+ dInfo->incrementLeft = 0;
+#endif
+ Tree_EventuallyRedraw(tree);
+ }
+ return;
+ }
+
+ if (visWidth > 1)
+ {
+ /* Find incrementLeft when scrolled to extreme right */
+ indexMax = Increment_FindX(tree, totWidth - visWidth);
+ offset = Increment_ToOffsetX(tree, indexMax);
+ if (offset < totWidth - visWidth)
+ {
+ indexMax++;
+ offset = Increment_ToOffsetX(tree, indexMax);
+ }
+
+ /* Add some fake content to right */
+ if (offset + visWidth > totWidth)
+ totWidth = offset + visWidth;
+ }
+ else
+ indexMax = Increment_FindX(tree, totWidth);
+
+ xOrigin += tree->inset; /* 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->inset;
+
+ if (xOrigin == tree->xOrigin)
+ return;
+
+ tree->xOrigin = xOrigin;
+#ifdef INCREMENTS
+ dInfo->incrementLeft = index;
+#endif
+
+ Tree_EventuallyRedraw(tree);
+}
+
+void Tree_SetOriginY(TreeCtrl *tree, int yOrigin)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ int topInset = tree->inset + Tree_HeaderHeight(tree);
+ int visHeight = Tk_Height(tree->tkwin) - topInset - tree->inset;
+ int totHeight = Tree_TotalHeight(tree);
+ int index, indexMax, offset;
+
+ /* The tree is empty, or everything fits in the window */
+ if (totHeight <= visHeight)
+ {
+ yOrigin = 0 - topInset;
+ if (yOrigin != tree->yOrigin)
+ {
+ tree->yOrigin = yOrigin;
+#ifdef INCREMENTS
+ dInfo->incrementTop = 0;
+#endif
+ Tree_EventuallyRedraw(tree);
+ }
+ return;
+ }
+
+ if (visHeight > 1)
+ {
+ /* Find incrementTop when scrolled to bottom */
+ indexMax = Increment_FindY(tree, totHeight - visHeight);
+ offset = Increment_ToOffsetY(tree, indexMax);
+ if (offset < totHeight - visHeight)
+ {
+ indexMax++;
+ offset = Increment_ToOffsetY(tree, indexMax);
+ }
+
+ /* Add some fake content to bottom */
+ if (offset + visHeight > totHeight)
+ totHeight = offset + visHeight;
+ }
+ else
+ indexMax = Increment_FindY(tree, totHeight);
+
+ yOrigin += topInset; /* origin -> canvas */
+ index = Increment_FindY(tree, yOrigin);
+
+ /* Don't scroll too far left */
+ if (index < 0)
+ index = 0;
+
+ /* Don't scroll too far right */
+ if (index > indexMax)
+ index = indexMax;
+
+ offset = Increment_ToOffsetY(tree, index);
+ yOrigin = offset - topInset;
+ if (yOrigin == tree->yOrigin)
+ return;
+
+ tree->yOrigin = yOrigin;
+#ifdef INCREMENTS
+ dInfo->incrementTop = index;
+#endif
+
+ Tree_EventuallyRedraw(tree);
+}
+
+void Tree_EventuallyRedraw(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ if ((dInfo->flags & DINFO_REDRAW_PENDING) ||
+ tree->deleted ||
+ !Tk_IsMapped(tree->tkwin))
+ {
+ return;
+ }
+ dInfo->flags |= DINFO_REDRAW_PENDING;
+ Tcl_DoWhenIdle(Tree_Display, (ClientData) tree);
+}
+
+void Tree_RelayoutWindow(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ FreeDItems(tree, dInfo->dItem, NULL, 0);
+ dInfo->dItem = NULL;
+ dInfo->flags |=
+ DINFO_REDO_RANGES |
+ DINFO_OUT_OF_DATE |
+ DINFO_CHECK_COLUMN_WIDTH |
+ DINFO_SET_ORIGIN_X |
+ DINFO_SET_ORIGIN_Y |
+ DINFO_UPDATE_SCROLLBAR_X |
+ DINFO_UPDATE_SCROLLBAR_Y;
+ if (tree->highlightWidth > 0)
+ dInfo->flags |= DINFO_DRAW_HIGHLIGHT;
+ if (tree->borderWidth > 0)
+ dInfo->flags |= DINFO_DRAW_BORDER;
+ dInfo->xOrigin = tree->xOrigin;
+ dInfo->yOrigin = tree->yOrigin;
+
+ if (tree->doubleBuffer == DOUBLEBUFFER_WINDOW)
+ {
+ if (dInfo->pixmap == None)
+ {
+ dInfo->pixmap = Tk_GetPixmap(tree->display,
+ Tk_WindowId(tree->tkwin),
+ Tk_Width(tree->tkwin),
+ Tk_Height(tree->tkwin),
+ Tk_Depth(tree->tkwin));
+ }
+ else if ((tree->prevWidth != Tk_Width(tree->tkwin)) ||
+ (tree->prevHeight != Tk_Height(tree->tkwin)))
+ {
+ Tk_FreePixmap(tree->display, dInfo->pixmap);
+ dInfo->pixmap = Tk_GetPixmap(tree->display,
+ Tk_WindowId(tree->tkwin),
+ Tk_Width(tree->tkwin),
+ Tk_Height(tree->tkwin),
+ Tk_Depth(tree->tkwin));
+ }
+ }
+ else if (dInfo->pixmap != None)
+ {
+ Tk_FreePixmap(tree->display, dInfo->pixmap);
+ dInfo->pixmap = None;
+ }
+
+ Tree_EventuallyRedraw(tree);
+}
+
+void Tree_FocusChanged(TreeCtrl *tree, int gotFocus)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ int redraw = FALSE;
+ TreeItem item;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ int stateOn, stateOff;
+
+ tree->gotFocus = gotFocus;
+
+ if (gotFocus)
+ stateOff = 0, stateOn = STATE_FOCUS;
+ else
+ stateOff = STATE_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);
+ }
+
+ if (tree->highlightWidth > 0)
+ {
+ dInfo->flags |= DINFO_DRAW_HIGHLIGHT;
+ redraw = TRUE;
+ }
+ if (redraw)
+ Tree_EventuallyRedraw(tree);
+}
+
+void Tree_FreeItemDInfo(TreeCtrl *tree, TreeItem item1, TreeItem item2)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ DItem *dItem;
+ TreeItem item = item1;
+ int changed = 0;
+
+ while (item != NULL)
+ {
+ dItem = (DItem *) TreeItem_GetDInfo(tree, item);
+ if (dItem != NULL)
+ {
+ FreeDItems(tree, dItem, dItem->next, 1);
+ changed = 1;
+ }
+ if (item == item2 || item2 == NULL)
+ break;
+ item = TreeItem_Next(tree, item);
+ }
+changed = 1;
+ if (changed)
+ {
+ dInfo->flags |= DINFO_OUT_OF_DATE;
+ Tree_EventuallyRedraw(tree);
+ }
+}
+
+void Tree_InvalidateItemDInfo(TreeCtrl *tree, TreeItem item1, TreeItem item2)
+{
+/* DInfo *dInfo = (DInfo *) tree->dInfo; */
+ DItem *dItem;
+ TreeItem item = item1;
+ int changed = 0;
+
+ while (item != NULL)
+ {
+ dItem = (DItem *) TreeItem_GetDInfo(tree, item);
+ if (dItem != NULL)
+ {
+ dItem->flags |= (DITEM_DIRTY | DITEM_ALL_DIRTY);
+ changed = 1;
+ }
+ if (item == item2 || item2 == NULL)
+ break;
+ item = TreeItem_Next(tree, item);
+ }
+ if (changed)
+ {
+/* dInfo->flags |= DINFO_OUT_OF_DATE; */
+ Tree_EventuallyRedraw(tree);
+ }
+}
+
+void Tree_DInfoChanged(TreeCtrl *tree, int flags)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+
+ dInfo->flags |= flags;
+ Tree_EventuallyRedraw(tree);
+}
+
+void Tree_InvalidateArea(TreeCtrl *tree, int x1, int y1, int x2, int y2)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ DItem *dItem;
+
+ if (x1 >= x2 || y1 >= y2)
+ return;
+
+ if ((y2 > tree->inset) && (y1 < tree->inset + Tree_HeaderHeight(tree)))
+ dInfo->flags |= DINFO_DRAW_HEADER;
+
+ dItem = dInfo->dItem;
+ while (dItem != NULL)
+ {
+ if (!(dItem->flags & DITEM_ALL_DIRTY) &&
+ (x2 > dItem->x) && (x1 < dItem->x + dItem->width) &&
+ (y2 > dItem->y) && (y1 < dItem->y + dItem->height))
+ {
+ InvalidateDItemX(dItem, dItem->x, x1, x2 - x1);
+ InvalidateDItemY(dItem, dItem->y, y1, y2 - y1);
+ dItem->flags |= DITEM_DIRTY;
+ }
+ dItem = dItem->next;
+ }
+
+ /* Could check border and highlight separately */
+ if (tree->inset > 0)
+ {
+ if ((x1 < tree->inset) ||
+ (y1 < tree->inset) ||
+ (x2 > Tk_Width(tree->tkwin) - tree->inset) ||
+ (y2 > Tk_Height(tree->tkwin) - tree->inset))
+ {
+ if (tree->highlightWidth > 0)
+ dInfo->flags |= DINFO_DRAW_HIGHLIGHT;
+ if (tree->borderWidth > 0)
+ dInfo->flags |= DINFO_DRAW_BORDER;
+ }
+ }
+
+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);
+}
+}
+
+void Tree_InvalidateRegion(TreeCtrl *tree, TkRegion region)
+{
+ XRectangle rect;
+
+ TkClipBox(region, &rect);
+ Tree_InvalidateArea(tree, rect.x, rect.y, rect.x + rect.width,
+ rect.y + rect.height);
+}
+
+void Tree_InvalidateItemArea(TreeCtrl *tree, int x1, int y1, int x2, int y2)
+{
+ if (x1 < tree->inset)
+ x1 = tree->inset;
+ if (y1 < tree->inset + Tree_HeaderHeight(tree))
+ y1 = tree->inset + Tree_HeaderHeight(tree);
+ if (x2 > Tk_Width(tree->tkwin) - tree->inset)
+ x2 = Tk_Width(tree->tkwin) - tree->inset;
+ if (y2 > Tk_Height(tree->tkwin) - tree->inset)
+ y2 = Tk_Height(tree->tkwin) - tree->inset;
+ Tree_InvalidateArea(tree, x1, y1, x2, y2);
+}
+
+void Tree_InvalidateWindow(TreeCtrl *tree)
+{
+ Tree_InvalidateArea(tree, 0, 0,
+ Tk_Width(tree->tkwin),
+ Tk_Height(tree->tkwin));
+}
+
+void Tree_RedrawArea(TreeCtrl *tree, int x1, int y1, int x2, int y2)
+{
+ Tree_InvalidateArea(tree, x1, y1, x2, y2);
+ Tree_EventuallyRedraw(tree);
+}
+
+void Tree_RedrawItemArea(TreeCtrl *tree, int x1, int y1, int x2, int y2)
+{
+ Tree_InvalidateItemArea(tree, x1, y1, x2, y2);
+ Tree_EventuallyRedraw(tree);
+}
+
+void TreeDInfo_Init(TreeCtrl *tree)
+{
+ DInfo *dInfo;
+ XGCValues gcValues;
+
+ dInfo = (DInfo *) ckalloc(sizeof(DInfo));
+ memset(dInfo, '\0', sizeof(DInfo));
+ gcValues.graphics_exposures = True;
+ dInfo->scrollGC = Tk_GetGC(tree->tkwin, GCGraphicsExposures, &gcValues);
+ dInfo->flags = DINFO_OUT_OF_DATE;
+ tree->dInfo = (TreeDInfo) dInfo;
+}
+
+void TreeDInfo_Free(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ Range *range = dInfo->rangeFirst;
+
+ if (dInfo->rItem != NULL)
+ ckfree((char *) dInfo->rItem);
+ FreeDItems(tree, dInfo->dItem, NULL, 0);
+ 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->pixmap != None)
+ Tk_FreePixmap(tree->display, dInfo->pixmap);
+ if (dInfo->xScrollIncrements != NULL)
+ ckfree((char *) dInfo->xScrollIncrements);
+ if (dInfo->yScrollIncrements != NULL)
+ ckfree((char *) dInfo->yScrollIncrements);
+ WFREE(dInfo, DInfo);
+}
+
+void DumpDInfo(TreeCtrl *tree)
+{
+ DInfo *dInfo = (DInfo *) tree->dInfo;
+ DItem *dItem;
+ Range *range;
+
+ dbwin("DumpDInfo: itemW,H %d,%d totalW,H %d,%d flags %0x\n",
+ dInfo->itemWidth, dInfo->itemHeight,
+ dInfo->totalWidth, dInfo->totalHeight,
+ dInfo->flags);
+ dItem = dInfo->dItem;
+ while (dItem != NULL)
+ {
+ if (dItem->item == NULL)
+ dbwin(" item NULL\n");
+ else
+ dbwin(" item %d x,y,w,h %d,%d,%d,%d dirty %d,%d,%d,%d flags %0X\n",
+ TreeItem_GetID(tree, dItem->item),
+ dItem->x, dItem->y, dItem->width, dItem->height,
+ dItem->dirty[LEFT], dItem->dirty[TOP],
+ dItem->dirty[RIGHT], dItem->dirty[BOTTOM],
+ dItem->flags);
+ dItem = dItem->next;
+ }
+
+ dbwin(" dInfo.rangeFirstD %p dInfo.rangeLastD %p\n",
+ dInfo->rangeFirstD, dInfo->rangeLastD);
+ for (range = dInfo->rangeFirstD;
+ range != NULL;
+ range = range->next)
+ {
+ dbwin(" Range: totalW,H %d,%d offset %d\n", range->totalWidth,
+ range->totalHeight, range->offset);
+ if (range == dInfo->rangeLastD)
+ break;
+ }
+
+ dbwin(" dInfo.rangeFirst %p dInfo.rangeLast %p\n",
+ dInfo->rangeFirst, dInfo->rangeLast);
+ for (range = dInfo->rangeFirst;
+ range != NULL;
+ range = range->next)
+ {
+ dbwin(" Range: first %p last %p totalW,H %d,%d offset %d\n",
+ range->first, range->last,
+ range->totalWidth, range->totalHeight, range->offset);
+ }
+}
+
diff --git a/generic/tkTreeDrag.c b/generic/tkTreeDrag.c
new file mode 100644
index 0000000..f6cc1e9
--- /dev/null
+++ b/generic/tkTreeDrag.c
@@ -0,0 +1,436 @@
+#include "tkTreeCtrl.h"
+
+typedef struct DragElem DragElem;
+typedef struct DragImage DragImage;
+
+struct DragElem
+{
+ int x, y, width, height;
+ DragElem *next;
+};
+
+struct DragImage
+{
+ TreeCtrl *tree;
+ int visible;
+ int x, y; /* offset to draw at in canvas coords */
+ int bounds[4]; /* bounds of all DragElems */
+ DragElem *elem;
+ int onScreen; /* TRUE if is displayed */
+ int sx, sy; /* Window coords where displayed */
+};
+
+static Tk_OptionSpec optionSpecs[] = {
+ {TK_OPTION_BOOLEAN, "-visible", (char *) NULL, (char *) NULL,
+ "0", -1, Tk_Offset(DragImage, visible),
+ 0, (ClientData) NULL, 0},
+ {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, 0, 0}
+};
+
+static Tk_OptionTable optionTable = NULL;
+
+static DragElem *DragElem_Alloc(DragImage *dragImage)
+{
+ 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;
+}
+
+static DragElem *DragElem_Free(DragImage *dragImage, DragElem *elem)
+{
+ DragElem *next = elem->next;
+ WFREE(elem, DragElem);
+ return next;
+}
+
+int TreeDragImage_Init(TreeCtrl *tree)
+{
+ DragImage *dragImage;
+
+ if (optionTable == NULL)
+ optionTable = Tk_CreateOptionTable(tree->interp, optionSpecs);
+
+ dragImage = (DragImage *) ckalloc(sizeof(DragImage));
+ memset(dragImage, '\0', sizeof(DragImage));
+ dragImage->tree = tree;
+ if (Tk_InitOptions(tree->interp, (char *) dragImage, optionTable,
+ tree->tkwin) != TCL_OK)
+ {
+ WFREE(dragImage, DragImage);
+ return TCL_ERROR;
+ }
+ tree->dragImage = (TreeDragImage) dragImage;
+ return TCL_OK;
+}
+
+void TreeDragImage_Free(TreeDragImage dragImage_)
+{
+ DragImage *dragImage = (DragImage *) dragImage_;
+ DragElem *elem = dragImage->elem;
+
+ while (elem != NULL)
+ elem = DragElem_Free(dragImage, elem);
+ Tk_FreeConfigOptions((char *) dragImage, optionTable,
+ dragImage->tree->tkwin);
+ WFREE(dragImage, DragImage);
+}
+
+void TreeDragImage_Display(TreeDragImage dragImage_)
+{
+ DragImage *dragImage = (DragImage *) dragImage_;
+ TreeCtrl *tree = dragImage->tree;
+
+ if (!dragImage->onScreen && dragImage->visible)
+ {
+ dragImage->sx = 0 - tree->xOrigin;
+ dragImage->sy = 0 - tree->yOrigin;
+ TreeDragImage_Draw(dragImage_, Tk_WindowId(tree->tkwin), dragImage->sx, dragImage->sy);
+ dragImage->onScreen = TRUE;
+ }
+}
+
+void TreeDragImage_Undisplay(TreeDragImage dragImage_)
+{
+ DragImage *dragImage = (DragImage *) dragImage_;
+ TreeCtrl *tree = dragImage->tree;
+
+ if (dragImage->onScreen)
+ {
+ TreeDragImage_Draw(dragImage_, Tk_WindowId(tree->tkwin), dragImage->sx, dragImage->sy);
+ dragImage->onScreen = FALSE;
+ }
+}
+
+static int DragImage_Config(DragImage *dragImage, int objc, Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = dragImage->tree;
+ Tk_SavedOptions savedOptions;
+ int mask, result;
+
+ result = Tk_SetOptions(tree->interp, (char *) dragImage, optionTable,
+ objc, objv, tree->tkwin, &savedOptions, &mask);
+ if (result != TCL_OK)
+ {
+ Tk_RestoreSavedOptions(&savedOptions);
+ return TCL_ERROR;
+ }
+ Tk_FreeSavedOptions(&savedOptions);
+#if 0
+ if (mask & CONF_VISIBLE)
+ {
+ if (dragImage->visible)
+ TreeDragImage_Display();
+ else
+ TreeDragImage_Unisplay();
+ }
+#endif
+ return TCL_OK;
+}
+
+void TreeDragImage_Draw(TreeDragImage dragImage_, Drawable drawable, int x, int y)
+{
+ DragImage *dragImage = (DragImage *) dragImage_;
+ TreeCtrl *tree = dragImage->tree;
+ DragElem *elem = dragImage->elem;
+ DotState dotState;
+
+/* if (!dragImage->visible)
+ return; */
+ if (elem == NULL)
+ return;
+
+ DotRect_Setup(tree, drawable, &dotState);
+
+ while (elem != NULL)
+ {
+ DotRect_Draw(&dotState,
+ x + dragImage->x + elem->x,
+ y + dragImage->y + elem->y,
+ elem->width, elem->height);
+ elem = elem->next;
+ }
+
+ DotRect_Restore(&dotState);
+}
+
+int DragImageCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ DragImage *dragImage = (DragImage *) tree->dragImage;
+ static CONST char *commandNames[] = { "add", "cget", "clear", "configure",
+ "offset", "visible", (char *) NULL };
+ enum { COMMAND_ADD, COMMAND_CGET, COMMAND_CLEAR, COMMAND_CONFIGURE,
+ COMMAND_OFFSET, COMMAND_VISIBLE };
+ 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:
+ {
+ XRectangle rects[20];
+ TreeItem item;
+ TreeItemColumn itemColumn;
+ TreeColumn treeColumn;
+ int i, count, columnIndex;
+ int indent, width, totalWidth;
+ int x, y, w, h;
+ DragElem *elem;
+ StyleDrawArgs drawArgs;
+
+ if (objc < 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "item ?column? ?element ...?");
+ return TCL_ERROR;
+ }
+ if (TreeItem_FromObj(tree, objv[3], &item, 0) != TCL_OK)
+ return TCL_ERROR;
+
+ Tree_ItemBbox(tree, item, &x, &y, &w, &h);
+
+ drawArgs.tree = tree;
+ drawArgs.drawable = None;
+ drawArgs.state = TreeItem_GetState(tree, item);
+ drawArgs.y = y;
+ drawArgs.height = h;
+
+ TreeDragImage_Undisplay(tree->dragImage);
+
+ if (objc > 4)
+ {
+ if (TreeItem_ColumnFromObj(tree, item, objv[4], &itemColumn, &columnIndex) != TCL_OK)
+ {
+ TreeDragImage_Display(tree->dragImage);
+ return TCL_ERROR;
+ }
+ drawArgs.style = TreeItemColumn_GetStyle(tree, itemColumn);
+ if (drawArgs.style == NULL)
+ {
+ TreeDragImage_Display(tree->dragImage);
+ break;
+ }
+ totalWidth = 0;
+ treeColumn = tree->columns;
+ for (i = 0; i < columnIndex; i++)
+ {
+ totalWidth += TreeColumn_UseWidth(treeColumn);
+ treeColumn = TreeColumn_Next(treeColumn);
+ }
+ if (TreeColumn_Index(treeColumn) == tree->columnTree)
+ indent = TreeItem_Indent(tree, item);
+ else
+ indent = 0;
+ drawArgs.x = x + indent + totalWidth;
+ drawArgs.width = TreeColumn_UseWidth(treeColumn) - indent;
+ drawArgs.justify = TreeColumn_Justify(treeColumn);
+ count = TreeStyle_GetElemRects(&drawArgs, objc - 5, objv + 5, rects);
+ if (count == -1)
+ {
+ TreeDragImage_Display(tree->dragImage);
+ return TCL_ERROR;
+ }
+ 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;
+ }
+ }
+ else
+ {
+ totalWidth = 0;
+ treeColumn = tree->columns;
+ itemColumn = TreeItem_GetFirstColumn(tree, item);
+ while (itemColumn != NULL)
+ {
+ width = TreeColumn_UseWidth(treeColumn);
+ if (TreeColumn_Index(treeColumn) == tree->columnTree)
+ indent = TreeItem_Indent(tree, item);
+ else
+ indent = 0;
+ drawArgs.style = TreeItemColumn_GetStyle(tree, itemColumn);
+ if (drawArgs.style != NULL)
+ {
+ drawArgs.x = x + indent + totalWidth;
+ drawArgs.width = width - indent;
+ drawArgs.justify = TreeColumn_Justify(treeColumn);
+ count = TreeStyle_GetElemRects(&drawArgs, 0, NULL, rects);
+ if (count == -1)
+ {
+ TreeDragImage_Display(tree->dragImage);
+ return TCL_ERROR;
+ }
+ 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;
+ }
+ }
+ totalWidth += width;
+ treeColumn = TreeColumn_Next(treeColumn);
+ itemColumn = TreeItemColumn_GetNext(tree, itemColumn);
+ }
+ }
+ dragImage->bounds[0] = 100000;
+ dragImage->bounds[1] = 100000;
+ dragImage->bounds[2] = -100000;
+ dragImage->bounds[3] = -100000;
+ for (elem = dragImage->elem;
+ elem != NULL;
+ elem = elem->next)
+ {
+ if (elem->x < dragImage->bounds[0])
+ dragImage->bounds[0] = elem->x;
+ if (elem->y < dragImage->bounds[1])
+ dragImage->bounds[1] = elem->y;
+ if (elem->x + elem->width > dragImage->bounds[2])
+ dragImage->bounds[2] = elem->x + elem->width;
+ if (elem->y + elem->height > dragImage->bounds[3])
+ dragImage->bounds[3] = elem->y + elem->height;
+ }
+ TreeDragImage_Display(tree->dragImage);
+ break;
+ }
+
+ /* 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,
+ optionTable, objv[4], tree->tkwin);
+ if (resultObjPtr == NULL)
+ return TCL_ERROR;
+ Tcl_SetObjResult(interp, resultObjPtr);
+ break;
+ }
+
+ /* T dragimage clear */
+ case COMMAND_CLEAR:
+ {
+ 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,
+ 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;
+ }
+
+ /* T dragimage visible ?boolean? */
+ case COMMAND_VISIBLE:
+ {
+ int visible;
+
+ if (objc != 3 && objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "?boolean?");
+ return TCL_ERROR;
+ }
+ if (objc == 4)
+ {
+ if (Tcl_GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK)
+ return TCL_ERROR;
+ if (visible != dragImage->visible)
+ {
+ dragImage->visible = visible;
+ TreeDragImage_Undisplay(tree->dragImage);
+ TreeDragImage_Display(tree->dragImage);
+ }
+ }
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(dragImage->visible));
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
diff --git a/generic/tkTreeElem.c b/generic/tkTreeElem.c
new file mode 100644
index 0000000..2596eb7
--- /dev/null
+++ b/generic/tkTreeElem.c
@@ -0,0 +1,3436 @@
+#include "tkTreeCtrl.h"
+#include "tkTreeElem.h"
+
+static int ObjectIsEmpty(Tcl_Obj *obj)
+{
+ int length;
+
+ if (obj == NULL)
+ return 1;
+ if (obj->bytes != NULL)
+ return (obj->length == 0);
+ Tcl_GetStringFromObj(obj, &length);
+ return (length == 0);
+}
+
+/* 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;
+
+ objEmpty = 0;
+
+ 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) = *((int *) internalPtr);
+ *((int *) 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
+};
+
+/* 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 *info = (IntegerClientData *) clientData;
+ int objEmpty;
+ int new, *internalPtr;
+
+ objEmpty = 0;
+
+ 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 ((info->flags & 0x01) && (new < info->min))
+ {
+ FormatResult(interp,
+ "bad integer value \"%d\": must be >= %d",
+ new, info->min);
+ return TCL_ERROR;
+ }
+ if ((info->flags & 0x02) && (new > info->max))
+ {
+ FormatResult(interp,
+ "bad integer value \"%d\": must be <= %d",
+ new, info->max);
+ return TCL_ERROR;
+ }
+ }
+ if (internalPtr != NULL)
+ {
+ if ((*value) == NULL)
+ new = info->empty;
+ *((int *) saveInternalPtr) = *((int *) internalPtr);
+ *((int *) internalPtr) = new;
+ }
+
+ return TCL_OK;
+}
+
+static Tcl_Obj *IntegerGet(
+ ClientData clientData,
+ Tk_Window tkwin,
+ char *recordPtr,
+ int internalOffset)
+{
+ IntegerClientData *info = (IntegerClientData *) clientData;
+ int value = *(int *) (recordPtr + internalOffset);
+ if (value == info->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 *info = (StringTableClientData *) clientData;
+ int objEmpty;
+ int new, *internalPtr;
+
+ objEmpty = 0;
+
+ 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), info->tablePtr,
+ info->msg, 0, &new) != TCL_OK)
+ return TCL_ERROR;
+ }
+ if (internalPtr != NULL)
+ {
+ if ((*value) == NULL)
+ new = -1;
+ *((int *) saveInternalPtr) = *((int *) internalPtr);
+ *((int *) internalPtr) = new;
+ }
+
+ return TCL_OK;
+}
+
+static Tcl_Obj *StringTableGet(
+ ClientData clientData,
+ Tk_Window tkwin,
+ char *recordPtr,
+ int internalOffset)
+{
+ StringTableClientData *info = (StringTableClientData *) clientData;
+ int index = *(int *) (recordPtr + internalOffset);
+
+ if (index == -1)
+ return NULL;
+ return Tcl_NewStringObj(info->tablePtr[index], -1);
+}
+
+static void StringTableRestore(
+ ClientData clientData,
+ Tk_Window tkwin,
+ char *internalPtr,
+ char *saveInternalPtr)
+{
+ *(int *) internalPtr = *(int *) saveInternalPtr;
+}
+
+/* END custom "stringtable" option */
+
+/*****/
+
+typedef struct PerStateData PerStateData;
+typedef struct PerStateInfo PerStateInfo;
+typedef struct PerStateType PerStateType;
+
+/* There is one of these for each XColor, Tk_Font, Tk_Image etc */
+struct PerStateData
+{
+ int stateOff;
+ int stateOn;
+ /* Type-specific fields go here */
+};
+
+#define DEBUG_PSI
+
+struct PerStateInfo
+{
+#ifdef DEBUG_PSI
+ PerStateType *type;
+#endif
+ Tcl_Obj *obj;
+ int count;
+ PerStateData *data;
+};
+
+typedef int (*PerStateType_FromObjProc)(TreeCtrl *, Tcl_Obj *, PerStateData *);
+typedef void (*PerStateType_FreeProc)(TreeCtrl *, PerStateData *);
+
+struct PerStateType
+{
+ int size;
+ PerStateType_FromObjProc fromObjProc;
+ PerStateType_FreeProc freeProc;
+};
+
+#define MATCH_NONE 0
+#define MATCH_ANY 1
+#define MATCH_PARTIAL 2
+#define MATCH_EXACT 3
+
+static int StateFromObj(TreeCtrl *tree, Tcl_Obj *obj, int *stateOff, int *stateOn)
+{
+ Tcl_Interp *interp = tree->interp;
+ int i, negate = 0, length, state = 0;
+ char ch0, *string;
+
+ string = Tcl_GetStringFromObj(obj, &length);
+ if (length == 0)
+ goto unknown;
+ ch0 = string[0];
+ if (ch0 == '!')
+ {
+ negate = 1;
+ ++string;
+ ch0 = string[0];
+ }
+ for (i = 0; i < 32; i++)
+ {
+ if (tree->stateNames[i] == NULL)
+ continue;
+ if ((ch0 == tree->stateNames[i][0]) &&
+ (strcmp(string, tree->stateNames[i]) == 0))
+ {
+ state = 1L << i;
+ break;
+ }
+ }
+ if (state == 0)
+ goto unknown;
+
+ if (negate)
+ (*stateOff) |= state;
+ else
+ (*stateOn) |= state;
+ return TCL_OK;
+
+unknown:
+ FormatResult(interp, "unknown state \"%s\"", string);
+ return TCL_ERROR;
+}
+
+static void PerStateInfo_Free(
+ TreeCtrl *tree,
+ PerStateType *typePtr,
+ PerStateInfo *pInfo)
+{
+ PerStateData *pData = pInfo->data;
+ int i;
+
+ if (pInfo->data == NULL)
+ return;
+#ifdef DEBUG_PSI
+ if (pInfo->type != typePtr) panic("PerStateInfo_Free type mismatch");
+#endif
+ for (i = 0; i < pInfo->count; i++)
+ {
+ (*typePtr->freeProc)(tree, pData);
+ pData = (PerStateData *) (((char *) pData) + typePtr->size);
+ }
+ wipefree((char *) pInfo->data, typePtr->size * pInfo->count);
+ pInfo->data = NULL;
+ pInfo->count = 0;
+}
+
+static int PerStateInfo_FromObj(
+ TreeCtrl *tree,
+ PerStateType *typePtr,
+ PerStateInfo *pInfo)
+{
+ int i, j;
+ int objc, objc2;
+ Tcl_Obj **objv, **objv2;
+ PerStateData *pData;
+
+#ifdef DEBUG_PSI
+ 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)
+ {
+ pData = (PerStateData *) ckalloc(typePtr->size);
+ pData->stateOff = pData->stateOn = 0; /* all states */
+ if ((*typePtr->fromObjProc)(tree, objv[0], pData) != TCL_OK)
+ {
+ wipefree((char *) pData, typePtr->size);
+ return TCL_ERROR;
+ }
+ pInfo->data = pData;
+ pInfo->count = 1;
+ return TCL_OK;
+ }
+
+ if ((objc & 1))
+ {
+ FormatResult(tree->interp, "list must have event number of elements");
+ return TCL_ERROR;
+ }
+
+ pData = (PerStateData *) ckalloc(typePtr->size * (objc / 2));
+ pInfo->data = pData;
+ for (i = 0; i < objc; i += 2)
+ {
+ if ((*typePtr->fromObjProc)(tree, objv[i], pData) != TCL_OK)
+ {
+ PerStateInfo_Free(tree, typePtr, pInfo);
+ return TCL_ERROR;
+ }
+ pInfo->count++;
+ if (Tcl_ListObjGetElements(tree->interp, objv[i + 1], &objc2, &objv2) != TCL_OK)
+ {
+ PerStateInfo_Free(tree, typePtr, pInfo);
+ return TCL_ERROR;
+ }
+ pData->stateOff = pData->stateOn = 0; /* all states */
+ for (j = 0; j < objc2; j++)
+ {
+ if (StateFromObj(tree, objv2[j], &pData->stateOff, &pData->stateOn) != TCL_OK)
+ {
+ PerStateInfo_Free(tree, typePtr, pInfo);
+ return TCL_ERROR;
+ }
+ }
+ pData = (PerStateData *) (((char *) pData) + typePtr->size);
+ }
+ return TCL_OK;
+}
+
+static PerStateData *PerStateInfo_ForState(
+ TreeCtrl *tree,
+ PerStateType *typePtr,
+ PerStateInfo *pInfo,
+ int state,
+ int *match)
+{
+ PerStateData *pData = pInfo->data;
+ int stateOff = ~state, stateOn = state;
+ int i;
+
+#ifdef DEBUG_PSI
+ if ((pInfo->data != NULL) && (pInfo->type != typePtr)) panic("PerStateInfo_ForState type mismatch");
+#endif
+
+ for (i = 0; i < pInfo->count; i++)
+ {
+ /* Any state */
+ if ((pData->stateOff == 0) &&
+ (pData->stateOn == 0))
+ {
+ (*match) = MATCH_ANY;
+ return pData;
+ }
+
+ /* Exact match */
+ if ((pData->stateOff == stateOff) &&
+ (pData->stateOn == stateOn))
+ {
+ (*match) = MATCH_EXACT;
+ return pData;
+ }
+
+ /* Partial match */
+ if (((pData->stateOff & stateOff) == pData->stateOff) &&
+ ((pData->stateOn & stateOn) == pData->stateOn))
+ {
+ (*match) = MATCH_PARTIAL;
+ return pData;
+ }
+
+ pData = (PerStateData *) (((char *) pData) + typePtr->size);
+ }
+
+ (*match) = MATCH_NONE;
+ return NULL;
+}
+
+static Tcl_Obj *PerStateInfo_ObjForState(
+ TreeCtrl *tree,
+ PerStateType *typePtr,
+ PerStateInfo *pInfo,
+ int state,
+ int *match)
+{
+ PerStateData *pData;
+ Tcl_Obj *obj;
+ int i;
+
+#ifdef DEBUG_PSI
+ if ((pInfo->data != NULL) && (pInfo->type != typePtr)) panic("PerStateInfo_ForStateObj type mismatch");
+#endif
+
+ pData = PerStateInfo_ForState(tree, typePtr, pInfo, state, match);
+ if (pData != NULL)
+ {
+ i = ((char *) pData - (char *) pInfo->data) / typePtr->size;
+ Tcl_ListObjIndex(tree->interp, pInfo->obj, i * 2, &obj);
+ return obj;
+ }
+
+ return NULL;
+}
+
+static void PerStateInfo_Undefine(
+ TreeCtrl *tree,
+ PerStateType *typePtr,
+ PerStateInfo *pInfo,
+ int state)
+{
+ PerStateData *pData = pInfo->data;
+ int i, j, numStates, stateOff, stateOn;
+ Tcl_Obj *configObj = pInfo->obj, *listObj, *stateObj;
+
+#ifdef DEBUG_PSI
+ if ((pInfo->data != NULL) && (pInfo->type != typePtr)) panic("PerStateInfo_ForState type mismatch");
+#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 = Tcl_DuplicateObj(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 = Tcl_DuplicateObj(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;
+ StateFromObj(tree, stateObj, &stateOff, &stateOn);
+ 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 ...}, but not
+ * the parent list */
+ Tcl_InvalidateStringRep(configObj);
+ }
+ pData = (PerStateData *) (((char *) pData) + typePtr->size);
+ }
+}
+
+/*****/
+
+struct PerStateGC
+{
+ unsigned long mask;
+ XGCValues gcValues;
+ GC gc;
+ struct PerStateGC *next;
+};
+
+void PerStateGC_Free(TreeCtrl *tree, struct PerStateGC **pGCPtr)
+{
+ struct PerStateGC *pGC = (*pGCPtr), *next;
+
+ while (pGC != NULL)
+ {
+ next = pGC->next;
+ Tk_FreeGC(tree->display, pGC->gc);
+ WFREE(pGC, struct PerStateGC);
+ pGC = next;
+ }
+ (*pGCPtr) = NULL;
+}
+
+GC PerStateGC_Get(TreeCtrl *tree, struct PerStateGC **pGCPtr, unsigned long mask, XGCValues *gcValues)
+{
+ struct PerStateGC *pGC;
+
+ if ((mask | (GCFont | GCForeground | GCBackground | GCGraphicsExposures)) !=
+ (GCFont | GCForeground | GCBackground | GCGraphicsExposures))
+ panic("PerStateGC_Get: unsupported mask");
+
+ for (pGC = (*pGCPtr); pGC != NULL; pGC = pGC->next)
+ {
+ if (mask != pGC->mask)
+ continue;
+ if ((mask & GCFont) &&
+ (pGC->gcValues.font != gcValues->font))
+ continue;
+ if ((mask & GCForeground) &&
+ (pGC->gcValues.foreground != gcValues->foreground))
+ continue;
+ if ((mask & GCBackground) &&
+ (pGC->gcValues.background != gcValues->background))
+ continue;
+ if ((mask & GCGraphicsExposures) &&
+ (pGC->gcValues.graphics_exposures != gcValues->graphics_exposures))
+ continue;
+ return pGC->gc;
+ }
+
+ pGC = (struct PerStateGC *) ckalloc(sizeof(*pGC));
+ pGC->gcValues = (*gcValues);
+ pGC->mask = mask;
+ pGC->gc = Tk_GetGC(tree->tkwin, mask, gcValues);
+ pGC->next = (*pGCPtr);
+ (*pGCPtr) = pGC;
+
+ return pGC->gc;
+}
+
+/*****/
+
+typedef struct PerStateDataBitmap PerStateDataBitmap;
+struct PerStateDataBitmap
+{
+ PerStateData header;
+ Pixmap bitmap;
+};
+
+static int BitmapFromObj(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 BitmapFree(TreeCtrl *tree, PerStateDataBitmap *pBitmap)
+{
+ if (pBitmap->bitmap != None)
+ Tk_FreeBitmap(tree->display, pBitmap->bitmap);
+}
+
+PerStateType pstBitmap =
+{
+ sizeof(PerStateDataBitmap),
+ (PerStateType_FromObjProc) BitmapFromObj,
+ (PerStateType_FreeProc) BitmapFree
+};
+
+static 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;
+}
+
+/*****/
+
+typedef struct PerStateDataBorder PerStateDataBorder;
+struct PerStateDataBorder
+{
+ PerStateData header;
+ Tk_3DBorder border;
+};
+
+static int BorderFromObj(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 BorderFree(TreeCtrl *tree, PerStateDataBorder *pBorder)
+{
+ if (pBorder->border != NULL)
+ Tk_Free3DBorder(pBorder->border);
+}
+
+PerStateType pstBorder =
+{
+ sizeof(PerStateDataBorder),
+ (PerStateType_FromObjProc) BorderFromObj,
+ (PerStateType_FreeProc) BorderFree
+};
+
+static 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;
+ XColor *color;
+};
+
+static int ColorFromObj(TreeCtrl *tree, Tcl_Obj *obj, PerStateDataColor *pColor)
+{
+ if (ObjectIsEmpty(obj))
+ {
+ /* Specify empty string to override masterX */
+ pColor->color = NULL;
+ }
+ else
+ {
+ pColor->color = Tk_AllocColorFromObj(tree->interp, tree->tkwin, obj);
+ if (pColor->color == NULL)
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+static void ColorFree(TreeCtrl *tree, PerStateDataColor *pColor)
+{
+ if (pColor->color != NULL)
+ Tk_FreeColor(pColor->color);
+}
+
+PerStateType pstColor =
+{
+ sizeof(PerStateDataColor),
+ (PerStateType_FromObjProc) ColorFromObj,
+ (PerStateType_FreeProc) ColorFree
+};
+
+static XColor *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 FontFromObj(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 FontFree(TreeCtrl *tree, PerStateDataFont *pFont)
+{
+ if (pFont->tkfont != NULL)
+ Tk_FreeFont(pFont->tkfont);
+}
+
+PerStateType pstFont =
+{
+ sizeof(PerStateDataFont),
+ (PerStateType_FromObjProc) FontFromObj,
+ (PerStateType_FreeProc) FontFree
+};
+
+static 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 ImageFromObj(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 ImageFree(TreeCtrl *tree, PerStateDataImage *pImage)
+{
+ if (pImage->string != NULL)
+ ckfree(pImage->string);
+ /* don't free image */
+}
+
+PerStateType pstImage =
+{
+ sizeof(PerStateDataImage),
+ (PerStateType_FromObjProc) ImageFromObj,
+ (PerStateType_FreeProc) ImageFree
+};
+
+static 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;
+}
+
+/*****/
+
+typedef struct PerStateDataRelief PerStateDataRelief;
+struct PerStateDataRelief
+{
+ PerStateData header;
+ int relief;
+};
+
+static int ReliefFromObj(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 ReliefFree(TreeCtrl *tree, PerStateDataRelief *pRelief)
+{
+}
+
+PerStateType pstRelief =
+{
+ sizeof(PerStateDataRelief),
+ (PerStateType_FromObjProc) ReliefFromObj,
+ (PerStateType_FreeProc) ReliefFree
+};
+
+static 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;
+}
+
+/*****/
+
+void PSTSave(
+ PerStateInfo *pInfo,
+ PerStateInfo *pSave)
+{
+#ifdef DEBUG_PSI
+ 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;
+}
+
+/*****/
+
+typedef struct ElementBitmap ElementBitmap;
+
+struct ElementBitmap
+{
+ Element header;
+ PerStateInfo bitmap;
+ PerStateInfo fg;
+ PerStateInfo bg;
+};
+
+#define BITMAP_CONF_BITMAP 0x0001
+#define BITMAP_CONF_FG 0x0002
+#define BITMAP_CONF_BG 0x0004
+
+static Tk_OptionSpec bitmapOptionSpecs[] = {
+ {TK_OPTION_STRING, "-background", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementBitmap, bg.obj), -1,
+ TK_OPTION_NULL_OK, (ClientData) NULL, BITMAP_CONF_BG},
+ {TK_OPTION_STRING, "-bitmap", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementBitmap, bitmap.obj), -1,
+ TK_OPTION_NULL_OK, (ClientData) NULL, BITMAP_CONF_BITMAP},
+ {TK_OPTION_STRING, "-foreground", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementBitmap, fg.obj), -1,
+ 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 DeleteBitmap(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementBitmap *elemX = (ElementBitmap *) elem;
+
+ PerStateInfo_Free(tree, &pstBitmap, &elemX->bitmap);
+ PerStateInfo_Free(tree, &pstColor, &elemX->fg);
+ PerStateInfo_Free(tree, &pstColor, &elemX->bg);
+}
+
+static int WorldChangedBitmap(ElementArgs *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) & (BITMAP_CONF_FG | BITMAP_CONF_BG))
+ mask |= CS_DISPLAY;
+
+ return mask;
+}
+
+static int ConfigBitmap(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementBitmap *elemX = (ElementBitmap *) elem;
+ ElementBitmap savedX;
+ 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;
+ }
+
+ if (args->config.flagSelf & BITMAP_CONF_BITMAP)
+ {
+ PSTSave(&elemX->bitmap, &savedX.bitmap);
+ if (PerStateInfo_FromObj(tree, &pstBitmap, &elemX->bitmap) != TCL_OK)
+ continue;
+ }
+
+ if (args->config.flagSelf & BITMAP_CONF_FG)
+ {
+ PSTSave(&elemX->fg, &savedX.fg);
+ if (PerStateInfo_FromObj(tree, &pstColor, &elemX->fg) != TCL_OK)
+ continue;
+ }
+
+ if (args->config.flagSelf & BITMAP_CONF_BG)
+ {
+ PSTSave(&elemX->bg, &savedX.bg);
+ if (PerStateInfo_FromObj(tree, &pstColor, &elemX->bg) != TCL_OK)
+ continue;
+ }
+
+ if (args->config.flagSelf & BITMAP_CONF_BITMAP)
+ PerStateInfo_Free(tree, &pstBitmap, &savedX.bitmap);
+ if (args->config.flagSelf & BITMAP_CONF_FG)
+ PerStateInfo_Free(tree, &pstColor, &savedX.fg);
+ if (args->config.flagSelf & BITMAP_CONF_BG)
+ PerStateInfo_Free(tree, &pstColor, &savedX.bg);
+ Tk_FreeSavedOptions(&savedOptions);
+ break;
+ }
+ else
+ {
+ errorResult = Tcl_GetObjResult(tree->interp);
+ Tcl_IncrRefCount(errorResult);
+ Tk_RestoreSavedOptions(&savedOptions);
+
+ if (args->config.flagSelf & BITMAP_CONF_BITMAP)
+ PSTRestore(tree, &pstBitmap, &elemX->bitmap, &savedX.bitmap);
+
+ if (args->config.flagSelf & BITMAP_CONF_FG)
+ PSTRestore(tree, &pstColor, &elemX->fg, &savedX.fg);
+
+ if (args->config.flagSelf & BITMAP_CONF_BG)
+ PSTRestore(tree, &pstColor, &elemX->bg, &savedX.bg);
+
+ Tcl_SetObjResult(tree->interp, errorResult);
+ Tcl_DecrRefCount(errorResult);
+ return TCL_ERROR;
+ }
+ }
+
+ return TCL_OK;
+}
+
+static int CreateBitmap(ElementArgs *args)
+{
+ return TCL_OK;
+}
+
+static void DisplayBitmap(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementBitmap *elemX = (ElementBitmap *) elem;
+ ElementBitmap *masterX = (ElementBitmap *) elem->master;
+ int state = args->state;
+ int match, match2;
+ Pixmap bitmap;
+ XColor *fg, *bg;
+ int imgW, imgH;
+
+ bitmap = PerStateBitmap_ForState(tree, &elemX->bitmap, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ Pixmap bitmap2 = PerStateBitmap_ForState(tree, &masterX->bitmap,
+ state, &match2);
+ if (match2 > match)
+ bitmap = bitmap2;
+ }
+
+ fg = PerStateColor_ForState(tree, &elemX->fg, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *fg2 = PerStateColor_ForState(tree, &masterX->fg,
+ state, &match2);
+ if (match2 > match)
+ fg = fg2;
+ }
+
+ bg = PerStateColor_ForState(tree, &elemX->bg, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *bg2 = PerStateColor_ForState(tree, &masterX->bg,
+ state, &match2);
+ if (match2 > match)
+ bg = bg2;
+ }
+
+ if (bitmap != None)
+ {
+ int bx = args->display.x /* + args->display.pad[LEFT] */;
+ int by = args->display.y /* + args->display.pad[TOP] */;
+ int dx = 0, dy = 0;
+ XGCValues gcValues;
+ GC gc;
+ unsigned long mask = 0;
+
+ Tk_SizeOfBitmap(tree->display, bitmap, &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;
+
+ bx += dx;
+ by += dy;
+
+ 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);
+ XSetClipOrigin(tree->display, gc, bx, by);
+ XCopyPlane(tree->display, bitmap, args->display.drawable, gc,
+ 0, 0, (unsigned int) imgW, (unsigned int) imgH,
+ bx, by, 1);
+ Tk_FreeGC(tree->display, gc);
+ }
+}
+
+static void LayoutBitmap(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementBitmap *elemX = (ElementBitmap *) elem;
+ ElementBitmap *masterX = (ElementBitmap *) elem->master;
+ int state = args->state;
+ int match, match2;
+ Pixmap bitmap;
+
+ bitmap = PerStateBitmap_ForState(tree, &elemX->bitmap, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ Pixmap bitmap2 = PerStateBitmap_ForState(tree, &masterX->bitmap,
+ state, &match2);
+ if (match2 > match)
+ bitmap = bitmap2;
+ }
+
+ if (bitmap != None)
+ Tk_SizeOfBitmap(tree->display, bitmap,
+ &args->layout.width, &args->layout.height);
+ else
+ args->layout.width = args->layout.height = 0;
+}
+
+static int StateProcBitmap(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementBitmap *elemX = (ElementBitmap *) elem;
+ ElementBitmap *masterX = (ElementBitmap *) elem->master;
+ int match, match2;
+ Pixmap bitmap1, bitmap2;
+ XColor *fg1, *fg2;
+ XColor *bg1, *bg2;
+ int mask = 0;
+
+ bitmap1 = PerStateBitmap_ForState(tree, &elemX->bitmap,
+ args->states.state1, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ Pixmap bitmap = PerStateBitmap_ForState(tree, &masterX->bitmap,
+ args->states.state1, &match2);
+ if (match2 > match)
+ bitmap1 = bitmap;
+ }
+
+ fg1 = PerStateColor_ForState(tree, &elemX->fg,
+ args->states.state1, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *fg = PerStateColor_ForState(tree, &masterX->fg,
+ args->states.state1, &match2);
+ if (match2 > match)
+ fg1 = fg;
+ }
+
+ bg1 = PerStateColor_ForState(tree, &elemX->bg,
+ args->states.state1, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *bg = PerStateColor_ForState(tree, &masterX->bg,
+ args->states.state1, &match2);
+ if (match2 > match)
+ bg1 = bg;
+ }
+
+ bitmap2 = PerStateBitmap_ForState(tree, &elemX->bitmap,
+ args->states.state2, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ Pixmap bitmap = PerStateBitmap_ForState(tree, &masterX->bitmap,
+ args->states.state2, &match2);
+ if (match2 > match)
+ bitmap2 = bitmap;
+ }
+
+ fg2 = PerStateColor_ForState(tree, &elemX->fg,
+ args->states.state2, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *fg = PerStateColor_ForState(tree, &masterX->fg,
+ args->states.state2, &match2);
+ if (match2 > match)
+ fg2 = fg;
+ }
+
+ bg2 = PerStateColor_ForState(tree, &elemX->bg,
+ args->states.state2, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *bg = PerStateColor_ForState(tree, &masterX->bg,
+ args->states.state2, &match2);
+ if (match2 > match)
+ bg2 = bg;
+ }
+
+ if ((fg1 != fg2) || (bg1 != bg2) || (bitmap1 != bitmap2))
+ mask |= CS_DISPLAY;
+
+ 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))
+ mask |= CS_LAYOUT;
+ }
+ else
+ mask |= CS_LAYOUT;
+ }
+
+ return mask;
+}
+
+static void UndefProcBitmap(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementBitmap *elemX = (ElementBitmap *) args->elem;
+
+ PerStateInfo_Undefine(tree, &pstBitmap, &elemX->fg, args->state);
+ PerStateInfo_Undefine(tree, &pstBitmap, &elemX->bg, args->state);
+ PerStateInfo_Undefine(tree, &pstBitmap, &elemX->bitmap, args->state);
+}
+
+static int ActualProcBitmap(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementBitmap *elemX = (ElementBitmap *) args->elem;
+ ElementBitmap *masterX = (ElementBitmap *) args->elem->master;
+ static CONST char *optionName[] = {
+ "-background", "-bitmap", "-foreground",
+ (char *) NULL };
+ int index, match, matchM;
+ Tcl_Obj *obj = NULL, *objM;
+
+ 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, &pstColor, &elemX->bg, args->state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ objM = PerStateInfo_ObjForState(tree, &pstColor, &masterX->bg, args->state, &matchM);
+ if (matchM > match)
+ obj = objM;
+ }
+ /* When -background isn't specified, GC default (white) is used */
+ if (ObjectIsEmpty(obj))
+ obj = Tcl_NewStringObj("white", -1);
+ break;
+ }
+ case 1:
+ {
+ obj = PerStateInfo_ObjForState(tree, &pstBitmap, &elemX->bitmap, args->state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ objM = PerStateInfo_ObjForState(tree, &pstBitmap, &masterX->bitmap, args->state, &matchM);
+ if (matchM > match)
+ obj = objM;
+ }
+ break;
+ }
+ case 2:
+ {
+ obj = PerStateInfo_ObjForState(tree, &pstColor, &elemX->fg, args->state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ objM = PerStateInfo_ObjForState(tree, &pstColor, &masterX->fg, args->state, &matchM);
+ if (matchM > match)
+ obj = objM;
+ }
+ /* When -foreground isn't specified, GC default (black) is used */
+ if (ObjectIsEmpty(obj))
+ obj = Tcl_NewStringObj("black", -1);
+ break;
+ }
+ }
+ if (obj != NULL)
+ Tcl_SetObjResult(tree->interp, obj);
+ return TCL_OK;
+}
+
+ElementType elemTypeBitmap = {
+ "bitmap",
+ sizeof(ElementBitmap),
+ bitmapOptionSpecs,
+ NULL,
+ CreateBitmap,
+ DeleteBitmap,
+ ConfigBitmap,
+ DisplayBitmap,
+ LayoutBitmap,
+ WorldChangedBitmap,
+ StateProcBitmap,
+ UndefProcBitmap,
+ ActualProcBitmap
+};
+
+/*****/
+
+typedef struct ElementBorder ElementBorder;
+
+struct ElementBorder
+{
+ Element header; /* Must be first */
+ 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
+
+static Tk_OptionSpec borderOptionSpecs[] = {
+ {TK_OPTION_STRING, "-background", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementBorder, border.obj), -1,
+ TK_OPTION_NULL_OK, (ClientData) NULL, BORDER_CONF_BG},
+ {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_STRING, "-relief", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementBorder, relief.obj), -1,
+ 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 DeleteBorder(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementBorder *elemX = (ElementBorder *) elem;
+
+ PerStateInfo_Free(tree, &pstBorder, &elemX->border);
+ PerStateInfo_Free(tree, &pstRelief, &elemX->relief);
+}
+
+static int WorldChangedBorder(ElementArgs *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) & (BORDER_CONF_BG | BORDER_CONF_RELIEF |
+ BORDER_CONF_THICKNESS | BORDER_CONF_FILLED))
+ mask |= CS_DISPLAY;
+
+ return mask;
+}
+
+static int ConfigBorder(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementBorder *elemX = (ElementBorder *) elem;
+ ElementBorder savedX;
+ 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;
+ }
+
+ if (args->config.flagSelf & BORDER_CONF_BG)
+ {
+ PSTSave(&elemX->border, &savedX.border);
+ if (PerStateInfo_FromObj(tree, &pstBorder, &elemX->border) != TCL_OK)
+ continue;
+ }
+
+ if (args->config.flagSelf & BORDER_CONF_RELIEF)
+ {
+ PSTSave(&elemX->relief, &savedX.relief);
+ if (PerStateInfo_FromObj(tree, &pstRelief, &elemX->relief) != TCL_OK)
+ continue;
+ }
+
+ if (args->config.flagSelf & BORDER_CONF_BG)
+ PerStateInfo_Free(tree, &pstBorder, &savedX.border);
+ if (args->config.flagSelf & BORDER_CONF_RELIEF)
+ PerStateInfo_Free(tree, &pstRelief, &savedX.relief);
+ Tk_FreeSavedOptions(&savedOptions);
+ break;
+ }
+ else
+ {
+ errorResult = Tcl_GetObjResult(tree->interp);
+ Tcl_IncrRefCount(errorResult);
+ Tk_RestoreSavedOptions(&savedOptions);
+
+ if (args->config.flagSelf & BORDER_CONF_BG)
+ PSTRestore(tree, &pstBorder, &elemX->border, &savedX.border);
+
+ if (args->config.flagSelf & BORDER_CONF_RELIEF)
+ PSTRestore(tree, &pstRelief, &elemX->relief, &savedX.relief);
+
+ Tcl_SetObjResult(tree->interp, errorResult);
+ Tcl_DecrRefCount(errorResult);
+ return TCL_ERROR;
+ }
+ }
+
+ return TCL_OK;
+}
+
+static int CreateBorder(ElementArgs *args)
+{
+ Element *elem = args->elem;
+ ElementBorder *elemX = (ElementBorder *) elem;
+
+ elemX->filled = -1;
+ return TCL_OK;
+}
+
+static void DisplayBorder(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementBorder *elemX = (ElementBorder *) elem;
+ ElementBorder *masterX = (ElementBorder *) elem->master;
+ int state = args->state;
+ int match, match2;
+ Tk_3DBorder border;
+ int relief, filled = FALSE;
+ int thickness = 0;
+
+ border = PerStateBorder_ForState(tree, &elemX->border, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ Tk_3DBorder border2 = PerStateBorder_ForState(tree, &masterX->border, state, &match2);
+ if (match2 > match)
+ border = border2;
+ }
+
+ relief = PerStateRelief_ForState(tree, &elemX->relief, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ int relief2 = PerStateRelief_ForState(tree, &masterX->relief, state, &match2);
+ if (match2 > match)
+ relief = relief2;
+ }
+
+ 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 (border != NULL)
+ {
+ if (relief == TK_RELIEF_NULL)
+ relief = TK_RELIEF_FLAT;
+ if (filled)
+ {
+ Tk_Fill3DRectangle(tree->tkwin, args->display.drawable, border,
+ args->display.x,
+ args->display.y,
+ args->display.width, args->display.height,
+ thickness, relief);
+ }
+ else if (thickness > 0)
+ {
+ Tk_Draw3DRectangle(tree->tkwin, args->display.drawable, border,
+ args->display.x,
+ args->display.y,
+ args->display.width, args->display.height,
+ thickness, relief);
+ }
+ }
+}
+
+static void LayoutBorder(ElementArgs *args)
+{
+ Element *elem = args->elem;
+ ElementBorder *elemX = (ElementBorder *) elem;
+ ElementBorder *masterX = (ElementBorder *) elem->master;
+ int width, height;
+
+ if (elemX->widthObj != NULL)
+ width = elemX->width;
+ else if ((masterX != NULL) && (masterX->widthObj != NULL))
+ width = masterX->width;
+ else
+ width = 0;
+ args->layout.width = width;
+
+ if (elemX->heightObj != NULL)
+ height = elemX->height;
+ else if ((masterX != NULL) && (masterX->heightObj != NULL))
+ height = masterX->height;
+ else
+ height = 0;
+ args->layout.height = height;
+}
+
+static int StateProcBorder(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementBorder *elemX = (ElementBorder *) elem;
+ ElementBorder *masterX = (ElementBorder *) elem->master;
+ int match, match2;
+ Tk_3DBorder border1, border2;
+ int relief1, relief2;
+ int mask = 0;
+
+ border1 = PerStateBorder_ForState(tree, &elemX->border, args->states.state1, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ Tk_3DBorder border = PerStateBorder_ForState(tree, &masterX->border, args->states.state1, &match2);
+ if (match2 > match)
+ border1 = border;
+ }
+
+ relief1 = PerStateRelief_ForState(tree, &elemX->relief, args->states.state1, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ int relief = PerStateRelief_ForState(tree, &masterX->relief, args->states.state1, &match2);
+ if (match2 > match)
+ relief1 = relief;
+ }
+
+ border2 = PerStateBorder_ForState(tree, &elemX->border, args->states.state2, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ Tk_3DBorder border = PerStateBorder_ForState(tree, &masterX->border, args->states.state2, &match2);
+ if (match2 > match)
+ border2 = border;
+ }
+
+ relief2 = PerStateRelief_ForState(tree, &elemX->relief, args->states.state2, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ int relief = PerStateRelief_ForState(tree, &masterX->relief, args->states.state2, &match2);
+ if (match2 > match)
+ relief2 = relief;
+ }
+
+ if ((border1 != border2) || (relief1 != relief2))
+ mask |= CS_DISPLAY;
+
+ return mask;
+}
+
+static void UndefProcBorder(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementBorder *elemX = (ElementBorder *) args->elem;
+
+ PerStateInfo_Undefine(tree, &pstBorder, &elemX->border, args->state);
+ PerStateInfo_Undefine(tree, &pstRelief, &elemX->relief, args->state);
+}
+
+static int ActualProcBorder(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementBorder *elemX = (ElementBorder *) args->elem;
+ ElementBorder *masterX = (ElementBorder *) args->elem->master;
+ static CONST char *optionName[] = {
+ "-background", "-relief",
+ (char *) NULL };
+ int index, match, matchM;
+ Tcl_Obj *obj = NULL, *objM;
+
+ 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, &pstBorder, &elemX->border, args->state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ objM = PerStateInfo_ObjForState(tree, &pstBorder, &masterX->border, args->state, &matchM);
+ if (matchM > match)
+ obj = objM;
+ }
+ break;
+ }
+ case 1:
+ {
+ obj = PerStateInfo_ObjForState(tree, &pstRelief, &elemX->relief, args->state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ objM = PerStateInfo_ObjForState(tree, &pstRelief, &masterX->relief, args->state, &matchM);
+ if (matchM > match)
+ obj = objM;
+ }
+ if (ObjectIsEmpty(obj))
+ obj = Tcl_NewStringObj("flat", -1);
+ break;
+ }
+ }
+ if (obj != NULL)
+ Tcl_SetObjResult(tree->interp, obj);
+ return TCL_OK;
+}
+
+ElementType elemTypeBorder = {
+ "border",
+ sizeof(ElementBorder),
+ borderOptionSpecs,
+ NULL,
+ CreateBorder,
+ DeleteBorder,
+ ConfigBorder,
+ DisplayBorder,
+ LayoutBorder,
+ WorldChangedBorder,
+ StateProcBorder,
+ UndefProcBorder,
+ ActualProcBorder
+};
+
+/*****/
+
+typedef struct ElementImage ElementImage;
+
+struct ElementImage
+{
+ Element header;
+ PerStateInfo image;
+ int width;
+ Tcl_Obj *widthObj;
+ int height;
+ Tcl_Obj *heightObj;
+};
+
+#define IMAGE_CONF_IMAGE 0x0001
+#define IMAGE_CONF_SIZE 0x0002
+
+static Tk_OptionSpec imageOptionSpecs[] = {
+ {TK_OPTION_PIXELS, "-height", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementImage, heightObj),
+ Tk_Offset(ElementImage, height),
+ TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_SIZE},
+ {TK_OPTION_STRING, "-image", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementImage, image.obj), -1,
+ TK_OPTION_NULL_OK, (ClientData) NULL, IMAGE_CONF_IMAGE},
+ {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementImage, widthObj),
+ Tk_Offset(ElementImage, width),
+ 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 DeleteImage(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementImage *elemX = (ElementImage *) elem;
+
+ PerStateInfo_Free(tree, &pstImage, &elemX->image);
+}
+
+static int WorldChangedImage(ElementArgs *args)
+{
+ int flagM = args->change.flagMaster;
+ int flagS = args->change.flagSelf;
+ int mask = 0;
+
+ if ((flagS | flagM) & (IMAGE_CONF_IMAGE | IMAGE_CONF_SIZE))
+ mask |= CS_DISPLAY | CS_LAYOUT;
+
+ return mask;
+}
+
+static int ConfigImage(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementImage *elemX = (ElementImage *) elem;
+ ElementImage savedX;
+ 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;
+ }
+
+ if (args->config.flagSelf & IMAGE_CONF_IMAGE)
+ {
+ PSTSave(&elemX->image, &savedX.image);
+ if (PerStateInfo_FromObj(tree, &pstImage, &elemX->image) != TCL_OK)
+ continue;
+ }
+
+ if (args->config.flagSelf & IMAGE_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 & IMAGE_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 CreateImage(ElementArgs *args)
+{
+ return TCL_OK;
+}
+
+static void DisplayImage(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementImage *elemX = (ElementImage *) elem;
+ ElementImage *masterX = (ElementImage *) 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 ((image == NULL) || (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 /* + args->display.pad[LEFT] */ + dx,
+ args->display.y /* + args->display.pad[TOP] */ + dy);
+ }
+}
+
+static void LayoutImage(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementImage *elemX = (ElementImage *) elem;
+ ElementImage *masterX = (ElementImage *) 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 ((image == NULL) || (match2 > match))
+ image = image2;
+ }
+
+ if (image != NULL)
+ Tk_SizeOfImage(image, &width, &height);
+
+ if (elemX->widthObj != NULL)
+ width = elemX->width;
+ else if ((masterX != NULL) && (masterX->widthObj != NULL))
+ width = masterX->width;
+ args->layout.width = width;
+
+ if (elemX->heightObj != NULL)
+ height = elemX->height;
+ else if ((masterX != NULL) && (masterX->heightObj != NULL))
+ height = masterX->height;
+ args->layout.height = height;
+}
+
+static int StateProcImage(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementImage *elemX = (ElementImage *) elem;
+ ElementImage *masterX = (ElementImage *) 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 ((image1 == NULL) || (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 ((image1 == NULL) || (match2 > match))
+ image1 = 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 void UndefProcImage(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementImage *elemX = (ElementImage *) args->elem;
+
+ PerStateInfo_Undefine(tree, &pstImage, &elemX->image, args->state);
+}
+
+static int ActualProcImage(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementImage *elemX = (ElementImage *) args->elem;
+ ElementImage *masterX = (ElementImage *) args->elem->master;
+ static CONST char *optionName[] = {
+ "-image",
+ (char *) NULL };
+ int index, match, matchM;
+ Tcl_Obj *obj = NULL, *objM;
+
+ 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;
+}
+
+ElementType elemTypeImage = {
+ "image",
+ sizeof(ElementImage),
+ imageOptionSpecs,
+ NULL,
+ CreateImage,
+ DeleteImage,
+ ConfigImage,
+ DisplayImage,
+ LayoutImage,
+ WorldChangedImage,
+ StateProcImage,
+ UndefProcImage,
+ ActualProcImage
+};
+
+/*****/
+
+typedef struct ElementRect ElementRect;
+
+struct ElementRect
+{
+ Element header;
+ int width;
+ Tcl_Obj *widthObj;
+ int height;
+ Tcl_Obj *heightObj;
+ PerStateInfo fill;
+ PerStateInfo outline;
+ int outlineWidth;
+ Tcl_Obj *outlineWidthObj;
+ int open;
+ char *openString;
+ int showFocus;
+};
+
+#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
+
+static Tk_OptionSpec rectOptionSpecs[] = {
+ {TK_OPTION_STRING, "-fill", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementRect, fill.obj), -1,
+ 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_STRING, "-open", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(ElementRect, openString),
+ TK_OPTION_NULL_OK, (ClientData) NULL, RECT_CONF_OPEN},
+ {TK_OPTION_STRING, "-outline", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementRect, outline.obj), -1,
+ 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_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 DeleteRect(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementRect *elemX = (ElementRect *) args->elem;
+
+ PerStateInfo_Free(tree, &pstColor, &elemX->fill);
+ PerStateInfo_Free(tree, &pstColor, &elemX->outline);
+}
+
+static int WorldChangedRect(ElementArgs *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) & (RECT_CONF_FILL | RECT_CONF_OUTLINE |
+ RECT_CONF_OPEN | RECT_CONF_FOCUS))
+ mask |= CS_DISPLAY;
+
+ return mask;
+}
+
+static int ConfigRect(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementRect *elemX = (ElementRect *) elem;
+ ElementRect savedX;
+ Tk_SavedOptions savedOptions;
+ int error;
+ Tcl_Obj *errorResult = NULL;
+ int i;
+
+ 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;
+ }
+
+ if (args->config.flagSelf & RECT_CONF_FILL)
+ {
+ PSTSave(&elemX->fill, &savedX.fill);
+ if (PerStateInfo_FromObj(tree, &pstColor, &elemX->fill) != TCL_OK)
+ continue;
+ }
+
+ if (args->config.flagSelf & RECT_CONF_OUTLINE)
+ {
+ PSTSave(&elemX->outline, &savedX.outline);
+ if (PerStateInfo_FromObj(tree, &pstColor, &elemX->outline) != TCL_OK)
+ continue;
+ }
+
+ if (args->config.flagSelf & RECT_CONF_OPEN)
+ {
+ savedX.open = elemX->open;
+ elemX->open = 0;
+ if (elemX->openString != NULL)
+ {
+ for (i = 0; elemX->openString[i]; i++)
+ {
+ switch (elemX->openString[i])
+ {
+ case 'w': elemX->open |= 0x01; break;
+ case 'n': elemX->open |= 0x02; break;
+ case 'e': elemX->open |= 0x04; break;
+ case 's': elemX->open |= 0x08; break;
+ }
+ }
+ }
+ }
+
+ if (args->config.flagSelf & RECT_CONF_FILL)
+ PerStateInfo_Free(tree, &pstColor, &savedX.fill);
+ if (args->config.flagSelf & RECT_CONF_OUTLINE)
+ PerStateInfo_Free(tree, &pstColor, &savedX.outline);
+ Tk_FreeSavedOptions(&savedOptions);
+ break;
+ }
+ else
+ {
+ errorResult = Tcl_GetObjResult(tree->interp);
+ Tcl_IncrRefCount(errorResult);
+ Tk_RestoreSavedOptions(&savedOptions);
+
+ if (args->config.flagSelf & RECT_CONF_FILL)
+ PSTRestore(tree, &pstColor, &elemX->fill, &savedX.fill);
+
+ if (args->config.flagSelf & RECT_CONF_OUTLINE)
+ PSTRestore(tree, &pstColor, &elemX->outline, &savedX.outline);
+
+ if (args->config.flagSelf & RECT_CONF_OPEN)
+ elemX->open = savedX.open;
+
+ Tcl_SetObjResult(tree->interp, errorResult);
+ Tcl_DecrRefCount(errorResult);
+ return TCL_ERROR;
+ }
+ }
+
+ return TCL_OK;
+}
+
+static int CreateRect(ElementArgs *args)
+{
+ ElementRect *elemX = (ElementRect *) args->elem;
+
+ elemX->showFocus = -1;
+ return TCL_OK;
+}
+
+static void DisplayRect(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementRect *elemX = (ElementRect *) elem;
+ ElementRect *masterX = (ElementRect *) elem->master;
+ int state = args->state;
+ int match, match2;
+ XColor *color, *color2;
+ int open = 0;
+ int outlineWidth = 0;
+ int showFocus = 0;
+
+ if (elemX->outlineWidthObj != NULL)
+ outlineWidth = elemX->outlineWidth;
+ else if ((masterX != NULL) && (masterX->outlineWidthObj != NULL))
+ outlineWidth = masterX->outlineWidth;
+
+ if (elemX->openString != NULL)
+ open = elemX->open;
+ else if ((masterX != NULL) && (masterX->openString != NULL))
+ open = masterX->open;
+
+ if (elemX->showFocus != -1)
+ showFocus = elemX->showFocus;
+ else if ((masterX != NULL) && (masterX->showFocus != -1))
+ showFocus = masterX->showFocus;
+
+ color = PerStateColor_ForState(tree, &elemX->fill, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ color2 = PerStateColor_ForState(tree, &masterX->fill, state, &match2);
+ if (match2 > match)
+ color = color2;
+ }
+ if (color != NULL)
+ {
+ XFillRectangle(tree->display, args->display.drawable,
+ Tk_GCForColor(color, Tk_WindowId(tree->tkwin)),
+ args->display.x, args->display.y,
+ args->display.width, args->display.height);
+ }
+
+ color = PerStateColor_ForState(tree, &elemX->outline, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ color2 = PerStateColor_ForState(tree, &masterX->outline, state, &match2);
+ if (match2 > match)
+ color = color2;
+ }
+ if ((color != NULL) && (outlineWidth > 0))
+ {
+ GC gc = Tk_GCForColor(color, Tk_WindowId(tree->tkwin));
+ int w1, w2;
+
+ w1 = outlineWidth / 2;
+ w2 = outlineWidth - w1;
+#if 0
+ if (open == 0)
+ {
+ XDrawRectangle(tree->display, args->display.drawable, gc,
+ args->display.x + w1, args->display.y + w1,
+ args->display.width - outlineWidth,
+ args->display.height - outlineWidth);
+ }
+ else
+#endif
+ {
+ int x = args->display.x;
+ int y = args->display.y;
+ int w = args->display.width;
+ int h = args->display.height;
+
+ if (!(open & 0x01))
+ XFillRectangle(tree->display, args->display.drawable, gc,
+ x, y, outlineWidth, h);
+ if (!(open & 0x02))
+ XFillRectangle(tree->display, args->display.drawable, gc,
+ x, y, w, outlineWidth);
+ if (!(open & 0x04))
+ XFillRectangle(tree->display, args->display.drawable, gc,
+ x + w - outlineWidth, y, outlineWidth, h);
+ if (!(open & 0x08))
+ XFillRectangle(tree->display, args->display.drawable, gc,
+ x, y + h - outlineWidth, w, outlineWidth);
+ }
+ }
+
+ if (showFocus && (state & STATE_FOCUS) && (state & STATE_ACTIVE))
+ {
+ DrawActiveOutline(tree, args->display.drawable,
+ args->display.x, args->display.y,
+ args->display.width, args->display.height,
+ open);
+ }
+}
+
+static void LayoutRect(ElementArgs *args)
+{
+ Element *elem = args->elem;
+ ElementRect *elemX = (ElementRect *) elem;
+ ElementRect *masterX = (ElementRect *) elem->master;
+ int width, height, outlineWidth;
+
+ if (elemX->outlineWidthObj != NULL)
+ outlineWidth = elemX->outlineWidth;
+ else if ((masterX != NULL) && (masterX->outlineWidthObj != NULL))
+ outlineWidth = masterX->outlineWidth;
+ else
+ outlineWidth = 0;
+
+ if (elemX->widthObj != NULL)
+ width = elemX->width;
+ else if ((masterX != NULL) && (masterX->widthObj != NULL))
+ width = masterX->width;
+ else
+ width = 0;
+ args->layout.width = MAX(width, outlineWidth * 2);
+
+ if (elemX->heightObj != NULL)
+ height = elemX->height;
+ else if ((masterX != NULL) && (masterX->heightObj != NULL))
+ height = masterX->height;
+ else
+ height = 0;
+ args->layout.height = MAX(height, outlineWidth * 2);
+}
+
+static int StateProcRect(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementRect *elemX = (ElementRect *) elem;
+ ElementRect *masterX = (ElementRect *) elem->master;
+ int match, match2;
+ XColor *f1, *f2;
+ XColor *o1, *o2;
+ int s1, s2;
+ int showFocus = 0;
+ int mask = 0;
+
+ if (elemX->showFocus != -1)
+ showFocus = elemX->showFocus;
+ else if ((masterX != NULL) && (masterX->showFocus != -1))
+ showFocus = masterX->showFocus;
+
+ f1 = PerStateColor_ForState(tree, &elemX->fill, args->states.state1, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *f = PerStateColor_ForState(tree, &masterX->fill, args->states.state1, &match2);
+ if (match2 > match)
+ f1 = f;
+ }
+
+ o1 = PerStateColor_ForState(tree, &elemX->outline, args->states.state1, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *o = PerStateColor_ForState(tree, &masterX->outline, args->states.state1, &match2);
+ if (match2 > match)
+ o1 = o;
+ }
+
+ s1 = showFocus &&
+ (args->states.state1 & STATE_FOCUS) &&
+ (args->states.state1 & STATE_ACTIVE);
+
+ f2 = PerStateColor_ForState(tree, &elemX->fill, args->states.state2, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *f = PerStateColor_ForState(tree, &masterX->fill, args->states.state2, &match2);
+ if (match2 > match)
+ f2 = f;
+ }
+
+ o2 = PerStateColor_ForState(tree, &elemX->outline, args->states.state2, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *o = PerStateColor_ForState(tree, &masterX->outline, args->states.state2, &match2);
+ if (match2 > match)
+ o2 = o;
+ }
+
+ s2 = showFocus &&
+ (args->states.state2 & STATE_FOCUS) &&
+ (args->states.state2 & STATE_ACTIVE);
+
+ if ((f1 != f2) || (o1 != o2) || (s1 != s2))
+ mask |= CS_DISPLAY;
+
+ return mask;
+}
+
+static void UndefProcRect(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementRect *elemX = (ElementRect *) args->elem;
+
+ PerStateInfo_Undefine(tree, &pstColor, &elemX->fill, args->state);
+ PerStateInfo_Undefine(tree, &pstColor, &elemX->outline, args->state);
+}
+
+static int ActualProcRect(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementRect *elemX = (ElementRect *) args->elem;
+ ElementRect *masterX = (ElementRect *) args->elem->master;
+ static CONST char *optionName[] = {
+ "-fill", "-outline",
+ (char *) NULL };
+ int index, match, matchM;
+ Tcl_Obj *obj = NULL, *objM;
+
+ 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, &pstColor, &elemX->fill, args->state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ objM = PerStateInfo_ObjForState(tree, &pstColor, &masterX->fill, args->state, &matchM);
+ if (matchM > match)
+ obj = objM;
+ }
+ break;
+ }
+ case 1:
+ {
+ obj = PerStateInfo_ObjForState(tree, &pstColor, &elemX->outline, args->state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ objM = PerStateInfo_ObjForState(tree, &pstColor, &masterX->outline, args->state, &matchM);
+ if (matchM > match)
+ obj = objM;
+ }
+ break;
+ }
+ }
+ if (obj != NULL)
+ Tcl_SetObjResult(tree->interp, obj);
+ return TCL_OK;
+}
+
+ElementType elemTypeRect = {
+ "rect",
+ sizeof(ElementRect),
+ rectOptionSpecs,
+ NULL,
+ CreateRect,
+ DeleteRect,
+ ConfigRect,
+ DisplayRect,
+ LayoutRect,
+ WorldChangedRect,
+ StateProcRect,
+ UndefProcRect,
+ ActualProcRect
+};
+
+/*****/
+
+typedef struct ElementText ElementText;
+
+/* Compile-time option */
+#define USE_TEXT_DATA 1
+
+struct ElementText
+{
+ Element header;
+ Tcl_Obj *textObj; /* -text */
+ char *text;
+ int textLen;
+#ifdef USE_TEXT_DATA
+ Tcl_Obj *dataObj;
+#define TDT_NULL -1
+#define TDT_DOUBLE 0
+#define TDT_INTEGER 1
+#define TDT_LONG 2
+#define TDT_STRING 3
+#define TDT_TIME 4
+#define TEXT_CONF_DATA 0x0001000 /* for Tk_SetOptions() */
+ int dataType; /* -datatype */
+ Tcl_Obj *formatObj; /* -format */
+ int stringRepInvalid;
+#endif /* USE_TEXT_DATA */
+ PerStateInfo font;
+ PerStateInfo fill;
+ struct PerStateGC *gc;
+#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_WORD 1
+ int wrap; /* -wrap */
+ TextLayout layout;
+ int layoutInvalid;
+ int layoutWidth;
+};
+
+/* for Tk_SetOptions() */
+#define TEXT_CONF_FONT 0x00000001
+#define TEXT_CONF_FILL 0x00000002
+#define TEXT_CONF_TEXTOBJ 0x00000010
+#define TEXT_CONF_LAYOUT 0x00000020
+
+static CONST char *textDataTypeST[] = { "double", "integer", "long", "string",
+ "time", (char *) NULL };
+static StringTableClientData textDataTypeCD =
+{
+ textDataTypeST,
+ "datatype"
+};
+static Tk_ObjCustomOption textDataTypeCO =
+{
+ "datatype",
+ StringTableSet,
+ StringTableGet,
+ StringTableRestore,
+ NULL,
+ (ClientData) &textDataTypeCD
+};
+
+static CONST char *textJustifyST[] = { "left", "right", "center", (char *) NULL };
+static StringTableClientData textJustifyCD =
+{
+ textJustifyST,
+ "justification"
+};
+static Tk_ObjCustomOption textJustifyCO =
+{
+ "justification",
+ StringTableSet,
+ StringTableGet,
+ StringTableRestore,
+ NULL,
+ (ClientData) &textJustifyCD
+};
+
+static IntegerClientData textLinesCD =
+{
+ 0, /* min */
+ 0, /* max (ignored) */
+ -1, /* empty */
+ 0x01 /* flags: min */
+};
+static Tk_ObjCustomOption textLinesCO =
+{
+ "integer",
+ IntegerSet,
+ IntegerGet,
+ IntegerRestore,
+ NULL,
+ (ClientData) &textLinesCD
+};
+
+static CONST char *textWrapST[] = { "char", "word", (char *) NULL };
+static StringTableClientData textWrapCD =
+{
+ textWrapST,
+ "wrap"
+};
+static Tk_ObjCustomOption textWrapCO =
+{
+ "wrap",
+ StringTableSet,
+ StringTableGet,
+ StringTableRestore,
+ NULL,
+ (ClientData) &textWrapCD
+};
+
+static Tk_OptionSpec textOptionSpecs[] = {
+#ifdef USE_TEXT_DATA
+ {TK_OPTION_STRING, "-data", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementText, dataObj), -1,
+ TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_DATA},
+ {TK_OPTION_CUSTOM, "-datatype", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(ElementText, dataType),
+ TK_OPTION_NULL_OK, (ClientData) &textDataTypeCO, TEXT_CONF_DATA},
+ {TK_OPTION_STRING, "-format", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementText, formatObj), -1,
+ TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_DATA},
+#endif /* USE_TEXT_DATA */
+ {TK_OPTION_STRING, "-fill", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementText, fill.obj), -1,
+ TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_FILL},
+ {TK_OPTION_STRING, "-font", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementText, font.obj), -1,
+ TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_FONT},
+ {TK_OPTION_CUSTOM, "-justify", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(ElementText, justify),
+ TK_OPTION_NULL_OK, (ClientData) &textJustifyCO, TEXT_CONF_LAYOUT},
+ {TK_OPTION_CUSTOM, "-lines", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(ElementText, lines),
+ TK_OPTION_NULL_OK, (ClientData) &textLinesCO, TEXT_CONF_LAYOUT},
+ {TK_OPTION_STRING, "-text", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementText, textObj),
+ Tk_Offset(ElementText, text),
+ TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_TEXTOBJ},
+ {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL,
+ (char *) NULL, Tk_Offset(ElementText, widthObj),
+ Tk_Offset(ElementText, width),
+ TK_OPTION_NULL_OK, (ClientData) NULL, TEXT_CONF_LAYOUT},
+ {TK_OPTION_CUSTOM, "-wrap", (char *) NULL, (char *) NULL,
+ (char *) NULL, -1, Tk_Offset(ElementText, wrap),
+ TK_OPTION_NULL_OK, (ClientData) &textWrapCO, TEXT_CONF_LAYOUT},
+ {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, 0, 0}
+};
+
+static int WorldChangedText(ElementArgs *args)
+{
+/* TreeCtrl *tree = args->tree;*/
+ Element *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;
+
+#ifdef USE_TEXT_DATA
+ if ((flagS | flagM) & (TEXT_CONF_DATA | TEXT_CONF_TEXTOBJ))
+ {
+ elemX->stringRepInvalid = TRUE;
+ mask |= CS_DISPLAY | CS_LAYOUT;
+ }
+#endif /* USE_TEXT_DATA */
+
+ if (elemX->stringRepInvalid ||
+ ((flagS | flagM) & (TEXT_CONF_FONT | TEXT_CONF_LAYOUT)) ||
+ /* Not always needed */
+ (flagT & TREE_CONF_FONT))
+ {
+ elemX->layoutInvalid = TRUE;
+ mask |= CS_DISPLAY | CS_LAYOUT;
+ }
+
+ if ((flagS | flagM) & TEXT_CONF_FILL)
+ mask |= CS_DISPLAY;
+
+ return mask;
+}
+
+#ifdef USE_TEXT_DATA
+
+static void TextUpdateStringRep(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementText *elemX = (ElementText *) elem;
+ ElementText *masterX = (ElementText *) elem->master;
+ Tcl_Obj *dataObj, *formatObj, *textObj;
+ int dataType;
+
+ dataObj = elemX->dataObj;
+ if ((dataObj == NULL) && (masterX != NULL))
+ dataObj = masterX->dataObj;
+
+ dataType = elemX->dataType;
+ if ((dataType == TDT_NULL) && (masterX != NULL))
+ dataType = masterX->dataType;
+
+ formatObj = elemX->formatObj;
+ if ((formatObj == NULL) && (masterX != NULL))
+ formatObj = masterX->formatObj;
+
+ textObj = elemX->textObj;
+ if ((textObj == NULL) && (masterX != NULL))
+ textObj = masterX->textObj;
+
+ if ((elemX->textObj == NULL) && (elemX->text != NULL))
+ {
+ ckfree(elemX->text);
+ elemX->text = NULL;
+ }
+
+ /* If -text is specified, -data, -datatype and -format are ignored */
+ if (textObj != NULL)
+ {
+ (void) Tcl_GetStringFromObj(textObj, &elemX->textLen);
+ }
+
+ /* Only create a string rep if elemX (not masterX) has dataObj,
+ dataType or formatObj. */
+ else if ((dataObj != NULL) && (dataType != TDT_NULL) &&
+ ((elemX->dataObj != NULL) ||
+ (elemX->dataType != TDT_NULL) ||
+ (elemX->formatObj != NULL)))
+ {
+ int i, objc = 0;
+ Tcl_Obj *objv[5], *resultObj = NULL;
+ static Tcl_Obj *staticObj[3] = { NULL };
+ static Tcl_Obj *staticFormat[4] = { NULL };
+ Tcl_ObjCmdProc *clockObjCmd = NULL;
+ Tcl_ObjCmdProc *formatObjCmd = NULL;
+
+ if (staticFormat[0] == NULL)
+ {
+ staticFormat[0] = Tcl_NewStringObj("%g", -1);
+ staticFormat[1] = Tcl_NewStringObj("%d", -1);
+ staticFormat[2] = Tcl_NewStringObj("%ld", -1);
+ staticFormat[3] = Tcl_NewStringObj("%s", -1);
+ for (i = 0; i < 4; i++)
+ Tcl_IncrRefCount(staticFormat[i]);
+ }
+ if (staticObj[0] == NULL)
+ {
+ staticObj[0] = Tcl_NewStringObj("clock", -1);
+ staticObj[1] = Tcl_NewStringObj("format", -1);
+ staticObj[2] = Tcl_NewStringObj("-format", -1);
+ for (i = 0; i < 3; i++)
+ Tcl_IncrRefCount(staticObj[i]);
+ }
+ if (clockObjCmd == NULL)
+ {
+ Tcl_CmdInfo cmdInfo;
+
+ if (Tcl_GetCommandInfo(tree->interp, "::clock", &cmdInfo) == 1)
+ clockObjCmd = cmdInfo.objProc;
+ }
+ if (formatObjCmd == NULL)
+ {
+ Tcl_CmdInfo cmdInfo;
+
+ if (Tcl_GetCommandInfo(tree->interp, "::format", &cmdInfo) == 1)
+ formatObjCmd = cmdInfo.objProc;
+ }
+
+ /* 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 = staticFormat[0];
+ objv[objc++] = staticObj[1]; /* format */
+ objv[objc++] = formatObj;
+ objv[objc++] = dataObj;
+ if (formatObjCmd(NULL, tree->interp, objc, objv) == TCL_OK)
+ resultObj = Tcl_GetObjResult(tree->interp);
+ break;
+ case TDT_INTEGER:
+ if (formatObjCmd == NULL)
+ break;
+ if (formatObj == NULL) formatObj = staticFormat[1];
+ objv[objc++] = staticObj[1]; /* format */
+ objv[objc++] = formatObj;
+ objv[objc++] = dataObj;
+ if (formatObjCmd(NULL, tree->interp, objc, objv) == TCL_OK)
+ resultObj = Tcl_GetObjResult(tree->interp);
+ break;
+ case TDT_LONG:
+ if (formatObjCmd == NULL)
+ break;
+ if (formatObj == NULL) formatObj = staticFormat[2];
+ objv[objc++] = staticObj[1]; /* format */
+ objv[objc++] = formatObj;
+ objv[objc++] = dataObj;
+ if (formatObjCmd(NULL, tree->interp, objc, objv) == TCL_OK)
+ resultObj = Tcl_GetObjResult(tree->interp);
+ break;
+ case TDT_STRING:
+ if (formatObjCmd == NULL)
+ break;
+ if (formatObj == NULL) formatObj = staticFormat[3];
+ objv[objc++] = staticObj[1]; /* format */
+ objv[objc++] = formatObj;
+ objv[objc++] = dataObj;
+ if (formatObjCmd(NULL, tree->interp, objc, objv) == TCL_OK)
+ resultObj = Tcl_GetObjResult(tree->interp);
+ break;
+ case TDT_TIME:
+ if (clockObjCmd == NULL)
+ break;
+ objv[objc++] = staticObj[0];
+ objv[objc++] = staticObj[1];
+ objv[objc++] = dataObj;
+ if (formatObj != NULL)
+ {
+ objv[objc++] = staticObj[2];
+ objv[objc++] = formatObj;
+ }
+ if (clockObjCmd(NULL, tree->interp, objc, objv) == TCL_OK)
+ resultObj = Tcl_GetObjResult(tree->interp);
+ break;
+ default:
+ panic("unknown ElementText dataType");
+ break;
+ }
+
+ if (resultObj != NULL)
+ {
+ char *string = Tcl_GetStringFromObj(resultObj, &elemX->textLen);
+ elemX->text = ckalloc(elemX->textLen);
+ memcpy(elemX->text, string, elemX->textLen);
+ }
+ }
+}
+
+#endif /* USE_TEXT_DATA */
+
+static void TextUpdateLayout(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementText *elemX = (ElementText *) elem;
+ ElementText *masterX = (ElementText *) elem->master;
+ int state = args->state;
+ int match, match2;
+ Tk_Font tkfont, tkfont2;
+ 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;
+
+ if (elemX->layout != NULL)
+ {
+/*if (tree->debug.enable && tree->debug.display)
+ dbwin("TextUpdateLayout %s: free %p (%s)\n", Tk_PathName(tree->tkwin), elemX, masterX ? "instance" : "master");*/
+ TextLayout_Free(elemX->layout);
+ elemX->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;
+
+ for (i = 0; i < textLen; i++)
+ {
+ if ((text[i] == '\n') || (text[i] == '\r'))
+ {
+ multiLine = TRUE;
+ break;
+ }
+ }
+
+ if (elemX->lines != -1)
+ lines = elemX->lines;
+ else if ((masterX != NULL) && (masterX->lines != -1))
+ lines = masterX->lines;
+
+ if (args->layout.width != -1)
+ width = args->layout.width;
+ else if (elemX->widthObj != NULL)
+ width = elemX->width;
+ else if ((masterX != NULL) && (masterX->widthObj != NULL))
+ width = masterX->width;
+
+ if ((lines == 1) || (!multiLine && (width == 0)))
+ return;
+
+ if (elemX->justify != TK_JUSTIFY_NULL)
+ justify = elemX->justify;
+ else if ((masterX != NULL) && (masterX->justify != TK_JUSTIFY_NULL))
+ justify = masterX->justify;
+
+ if (elemX->wrap != TEXT_WRAP_NULL)
+ wrap = elemX->wrap;
+ else if ((masterX != NULL) && (masterX->wrap != TEXT_WRAP_NULL))
+ wrap = masterX->wrap;
+
+ tkfont = PerStateFont_ForState(tree, &elemX->font, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ tkfont2 = PerStateFont_ForState(tree, &masterX->font, state, &match2);
+ if (match2 > match)
+ tkfont = tkfont2;
+ }
+ if (tkfont == NULL)
+ tkfont = tree->tkfont;
+
+ if (wrap == TEXT_WRAP_WORD)
+ flags |= TK_WHOLE_WORDS;
+
+ elemX->layout = TextLayout_Compute(tkfont, text,
+ textLen, width, justify, lines, flags);
+
+/*if (tree->debug.enable && tree->debug.display)
+ dbwin("TextUpdateLayout %s: alloc %p (%s)\n", Tk_PathName(tree->tkwin), elemX, masterX ? "instance" : "master");*/
+}
+
+static void DeleteText(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementText *elemX = (ElementText *) elem;
+
+ if (elemX->gc != NULL)
+ PerStateGC_Free(tree, &elemX->gc);
+ PerStateInfo_Free(tree, &pstColor, &elemX->fill);
+ PerStateInfo_Free(tree, &pstFont, &elemX->font);
+#ifdef USE_TEXT_DATA
+ if ((elemX->textObj == NULL) && (elemX->text != NULL))
+ {
+ ckfree(elemX->text);
+ elemX->text = NULL;
+ }
+#endif
+ if (elemX->layout != NULL)
+ TextLayout_Free(elemX->layout);
+}
+
+static int ConfigText(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementText *elemX = (ElementText *) elem;
+ ElementText savedX;
+ 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;
+ }
+
+ if (args->config.flagSelf & TEXT_CONF_FILL)
+ {
+ PSTSave(&elemX->fill, &savedX.fill);
+ if (PerStateInfo_FromObj(tree, &pstColor, &elemX->fill) != TCL_OK)
+ continue;
+ }
+
+ if (args->config.flagSelf & TEXT_CONF_FONT)
+ {
+ PSTSave(&elemX->font, &savedX.font);
+ if (PerStateInfo_FromObj(tree, &pstFont, &elemX->font) != TCL_OK)
+ continue;
+ }
+
+ if (args->config.flagSelf & TEXT_CONF_FILL)
+ PerStateInfo_Free(tree, &pstColor, &savedX.fill);
+ if (args->config.flagSelf & TEXT_CONF_FONT)
+ PerStateInfo_Free(tree, &pstFont, &savedX.font);
+ Tk_FreeSavedOptions(&savedOptions);
+ break;
+ }
+ else
+ {
+ errorResult = Tcl_GetObjResult(tree->interp);
+ Tcl_IncrRefCount(errorResult);
+ Tk_RestoreSavedOptions(&savedOptions);
+
+ if (args->config.flagSelf & TEXT_CONF_FILL)
+ PSTRestore(tree, &pstColor, &elemX->fill, &savedX.fill);
+
+ if (args->config.flagSelf & TEXT_CONF_FONT)
+ PSTRestore(tree, &pstFont, &elemX->font, &savedX.font);
+
+ Tcl_SetObjResult(tree->interp, errorResult);
+ Tcl_DecrRefCount(errorResult);
+ return TCL_ERROR;
+ }
+ }
+
+ return TCL_OK;
+}
+
+static int CreateText(ElementArgs *args)
+{
+ ElementText *elemX = (ElementText *) args->elem;
+
+#ifdef USE_TEXT_DATA
+ elemX->dataType = TDT_NULL;
+#endif
+ elemX->justify = TK_JUSTIFY_NULL;
+ elemX->lines = -1;
+ elemX->wrap = TEXT_WRAP_NULL;
+ return TCL_OK;
+}
+
+static void DisplayText(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementText *elemX = (ElementText *) elem;
+ ElementText *masterX = (ElementText *) elem->master;
+ int state = args->state;
+ int match, match2;
+ XColor *color, *color2;
+ char *text = elemX->text;
+ int textLen = elemX->textLen;
+ Tk_Font tkfont, tkfont2;
+ TextLayout layout = NULL;
+ Tk_FontMetrics fm;
+ GC gc;
+ int bytesThatFit, pixelsForText;
+ char *ellipsis = "...";
+
+ if ((text == NULL) && (masterX != NULL))
+ {
+ text = masterX->text;
+ textLen = masterX->textLen;
+ }
+
+ if (text == NULL) /* always false (or layout sets height/width to zero) */
+ return;
+
+ color = PerStateColor_ForState(tree, &elemX->fill, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ color2 = PerStateColor_ForState(tree, &masterX->fill, state, &match2);
+ if (match2 > match)
+ color = color2;
+ }
+
+ tkfont = PerStateFont_ForState(tree, &elemX->font, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ tkfont2 = PerStateFont_ForState(tree, &masterX->font, state, &match2);
+ if (match2 > match)
+ tkfont = tkfont2;
+ }
+
+ /* FIXME: -font {"" {state...}}*/
+ if ((color != NULL) || (tkfont != NULL))
+ {
+ XGCValues gcValues;
+ unsigned long gcMask = 0;
+ if (color == NULL)
+ color = tree->fgColorPtr;
+ gcValues.foreground = color->pixel;
+ gcMask |= GCForeground;
+ if (tkfont == NULL)
+ tkfont = tree->tkfont;
+ gcValues.font = Tk_FontId(tkfont);
+ gcMask |= GCFont;
+ gcValues.graphics_exposures = False;
+ gcMask |= GCGraphicsExposures;
+ gc = PerStateGC_Get(tree, (masterX != NULL) ? &masterX->gc :
+ &elemX->gc, gcMask, &gcValues);
+ }
+ else
+ {
+ tkfont = tree->tkfont;
+ gc = tree->textGC;
+ }
+
+ if (elemX->layout != NULL)
+ layout = elemX->layout;
+ else if ((elemX->text == NULL) && (masterX != NULL) &&
+ (masterX->layout != NULL))
+ layout = masterX->layout;
+
+ if (layout != NULL)
+ {
+ TextLayout_Draw(tree->display, args->display.drawable, gc,
+ layout,
+ args->display.x /* + args->display.pad[LEFT] */,
+ args->display.y /* + args->display.pad[TOP] */,
+ 0, -1);
+ return;
+ }
+
+ Tk_GetFontMetrics(tkfont, &fm);
+
+ pixelsForText = args->display.width /* - args->display.pad[LEFT] -
+ args->display.pad[RIGHT] */;
+ bytesThatFit = Ellipsis(tkfont, text, textLen, &pixelsForText, ellipsis);
+ if (bytesThatFit != textLen)
+ {
+ char staticStr[256], *buf = staticStr;
+ int bufLen = abs(bytesThatFit);
+ int ellipsisLen = 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, args->display.x /* + args->display.pad[LEFT] */,
+ args->display.y /* + args->display.pad[TOP] */ + fm.ascent);
+ if (buf != staticStr)
+ ckfree(buf);
+ }
+ else
+ {
+ Tk_DrawChars(tree->display, args->display.drawable, gc,
+ tkfont, text, textLen, args->display.x /* + args->display.pad[LEFT] */,
+ args->display.y /* + args->display.pad[TOP] */ + fm.ascent);
+ }
+}
+
+static void LayoutText(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementText *elemX = (ElementText *) elem;
+ ElementText *masterX = (ElementText *) elem->master;
+ int state = args->state;
+ int match, match2;
+ char *text = NULL;
+ int textLen = 0;
+ Tk_Font tkfont;
+ Tk_FontMetrics fm;
+ int width = 0;
+ TextLayout layout = NULL;
+
+#ifdef USE_TEXT_DATA
+ if ((masterX != NULL) /* && (elemX != masterX) */ && masterX->stringRepInvalid)
+ {
+ args->elem = (Element *) masterX;
+ TextUpdateStringRep(args);
+ args->elem = elem;
+ masterX->stringRepInvalid = FALSE;
+ }
+ if (elemX->stringRepInvalid)
+ {
+ TextUpdateStringRep(args);
+ elemX->stringRepInvalid = FALSE;
+ }
+#endif
+
+ if ((masterX != NULL) /* && (elemX != masterX) */ &&
+ (masterX->layoutInvalid || (masterX->layoutWidth != args->layout.width)))
+ {
+ args->elem = (Element *) masterX;
+ TextUpdateLayout(args);
+ args->elem = elem;
+ masterX->layoutInvalid = FALSE;
+ masterX->layoutWidth = args->layout.width;
+ }
+ if (elemX->layoutInvalid || (elemX->layoutWidth != args->layout.width))
+ {
+ TextUpdateLayout(args);
+ elemX->layoutInvalid = FALSE;
+ elemX->layoutWidth = args->layout.width;
+ }
+
+ if (elemX->layout != NULL)
+ layout = elemX->layout;
+ else if ((elemX->text == NULL) && (masterX != NULL) &&
+ (masterX->layout != NULL))
+ layout = masterX->layout;
+
+ if (layout != NULL)
+ {
+ TextLayout_Size(layout, &args->layout.width, &args->layout.height);
+ return;
+ }
+
+ 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)
+ {
+ tkfont = PerStateFont_ForState(tree, &elemX->font, state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ Tk_Font tkfont2 = PerStateFont_ForState(tree, &masterX->font, state, &match2);
+ if (match2 > match)
+ tkfont = tkfont2;
+ }
+ if (tkfont == NULL)
+ tkfont = tree->tkfont;
+
+#if 0
+ /* Weird bug with MS Sans Serif 8 bold */
+ Tk_MeasureChars(font, text, textLen, -1, 0, &width);
+ width2 = width;
+ while (Tk_MeasureChars(font, text, textLen, width2, 0, &width) != textLen)
+ width2++;
+ args->layout.width = width2;
+#else
+ args->layout.width = Tk_TextWidth(tkfont, text, textLen);
+#endif
+ if (elemX->widthObj != NULL)
+ width = elemX->width;
+ else if ((masterX != NULL) && (masterX->widthObj != NULL))
+ width = masterX->width;
+ if (width && (width < args->layout.width))
+ args->layout.width = width;
+ Tk_GetFontMetrics(tkfont, &fm);
+ args->layout.height = fm.linespace; /* TODO: multi-line strings */
+ return;
+ }
+
+ args->layout.width = args->layout.height = 0;
+}
+
+int Element_GetSortData(TreeCtrl *tree, Element *elem, int type, long *lv, double *dv, char **sv)
+{
+ ElementText *elemX = (ElementText *) elem;
+ ElementText *masterX = (ElementText *) elem->master;
+ Tcl_Obj *dataObj = elemX->dataObj;
+ int dataType = elemX->dataType;
+ Tcl_Obj *obj;
+
+ if (dataType == TDT_NULL && masterX != NULL)
+ dataType = masterX->dataType;
+
+ switch (type)
+ {
+ case SORT_ASCII:
+ case SORT_DICT:
+ if (dataObj != NULL && dataType != TDT_NULL)
+ (*sv) = Tcl_GetString(dataObj);
+ else
+ (*sv) = elemX->text;
+ break;
+ case SORT_DOUBLE:
+ if (dataObj != NULL && dataType == TDT_DOUBLE)
+ obj = dataObj;
+ else
+ obj = elemX->textObj;
+ if (obj == NULL)
+ return TCL_ERROR;
+ if (Tcl_GetDoubleFromObj(tree->interp, obj, dv) != TCL_OK)
+ return TCL_ERROR;
+ break;
+ 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->textObj != NULL)
+ if (Tcl_GetLongFromObj(tree->interp, elemX->textObj, lv) != TCL_OK)
+ return TCL_ERROR;
+ break;
+ }
+ return TCL_OK;
+}
+
+static int StateProcText(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ Element *elem = args->elem;
+ ElementText *elemX = (ElementText *) elem;
+ ElementText *masterX = (ElementText *) elem->master;
+ int match, match2;
+ XColor *f1, *f2;
+ Tk_Font tkfont1, tkfont2;
+ int mask = 0;
+
+ f1 = PerStateColor_ForState(tree, &elemX->fill, args->states.state1, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *f = PerStateColor_ForState(tree, &masterX->fill, args->states.state1, &match2);
+ if (match2 > match)
+ f1 = f;
+ }
+
+ tkfont1 = PerStateFont_ForState(tree, &elemX->font, args->states.state1, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ Tk_Font tkfont = PerStateFont_ForState(tree, &masterX->font, args->states.state1, &match2);
+ if (match2 > match)
+ tkfont1 = tkfont;
+ }
+
+ f2 = PerStateColor_ForState(tree, &elemX->fill, args->states.state2, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ XColor *f = PerStateColor_ForState(tree, &masterX->fill, args->states.state2, &match2);
+ if (match2 > match)
+ f2 = f;
+ }
+
+ tkfont2 = PerStateFont_ForState(tree, &elemX->font, args->states.state2, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ Tk_Font tkfont = PerStateFont_ForState(tree, &masterX->font, args->states.state2, &match2);
+ if (match2 > match)
+ tkfont2 = tkfont;
+ }
+
+ if (tkfont1 != tkfont2)
+ mask |= CS_DISPLAY | CS_LAYOUT;
+
+ if (f1 != f2)
+ mask |= CS_DISPLAY;
+
+ return mask;
+}
+
+static void UndefProcText(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementText *elemX = (ElementText *) args->elem;
+
+ PerStateInfo_Undefine(tree, &pstColor, &elemX->fill, args->state);
+ PerStateInfo_Undefine(tree, &pstFont, &elemX->font, args->state);
+}
+
+static int ActualProcText(ElementArgs *args)
+{
+ TreeCtrl *tree = args->tree;
+ ElementText *elemX = (ElementText *) args->elem;
+ ElementText *masterX = (ElementText *) args->elem->master;
+ static CONST char *optionName[] = {
+ "-fill", "-font",
+ (char *) NULL };
+ int index, match, matchM;
+ Tcl_Obj *obj = NULL, *objM;
+
+ 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, &pstColor, &elemX->fill, args->state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ objM = PerStateInfo_ObjForState(tree, &pstColor, &masterX->fill, args->state, &matchM);
+ if (matchM > match)
+ obj = objM;
+ }
+ if (ObjectIsEmpty(obj))
+ obj = tree->fgObj;
+ break;
+ }
+ case 1:
+ {
+ obj = PerStateInfo_ObjForState(tree, &pstFont, &elemX->font, args->state, &match);
+ if ((match != MATCH_EXACT) && (masterX != NULL))
+ {
+ objM = PerStateInfo_ObjForState(tree, &pstFont, &masterX->font, args->state, &matchM);
+ if (matchM > match)
+ obj = objM;
+ }
+ if (ObjectIsEmpty(obj))
+ obj = tree->fontObj;
+ break;
+ }
+ }
+ if (obj != NULL)
+ Tcl_SetObjResult(tree->interp, obj);
+ return TCL_OK;
+}
+
+ElementType elemTypeText = {
+ "text",
+ sizeof(ElementText),
+ textOptionSpecs,
+ NULL,
+ CreateText,
+ DeleteText,
+ ConfigText,
+ DisplayText,
+ LayoutText,
+ WorldChangedText,
+ StateProcText,
+ UndefProcText,
+ ActualProcText
+};
+
+/*****/
+
diff --git a/generic/tkTreeElem.h b/generic/tkTreeElem.h
new file mode 100644
index 0000000..3e83f1c
--- /dev/null
+++ b/generic/tkTreeElem.h
@@ -0,0 +1,79 @@
+typedef struct ElementType ElementType;
+typedef struct Element Element;
+typedef struct ElementArgs ElementArgs;
+
+struct ElementArgs
+{
+ TreeCtrl *tree;
+ Element *elem;
+ int state;
+ struct {
+ } create;
+ struct {
+ } delete;
+ struct {
+ int objc;
+ Tcl_Obj *CONST *objv;
+ int flagSelf;
+ } config;
+ struct {
+ int x;
+ int y;
+ int width;
+ int height;
+ int pad[4];
+ Drawable drawable;
+ } display;
+ struct {
+ int width;
+ int height;
+ } layout;
+ struct {
+ int flagTree;
+ int flagMaster;
+ int flagSelf;
+ } change;
+ struct {
+ int state1;
+ int state2;
+ } states;
+ struct {
+ Tcl_Obj *obj;
+ } actual;
+};
+
+struct ElementType
+{
+ char *name; /* "image", "text" */
+ int size; /* size of an Element */
+ Tk_OptionSpec *optionSpecs;
+ Tk_OptionTable optionTable;
+ int (*createProc)(ElementArgs *args);
+ void (*deleteProc)(ElementArgs *args);
+ int (*configProc)(ElementArgs *args);
+ void (*displayProc)(ElementArgs *args);
+ void (*layoutProc)(ElementArgs *args);
+ int (*changeProc)(ElementArgs *args);
+ int (*stateProc)(ElementArgs *args);
+ void (*undefProc)(ElementArgs *args);
+ int (*actualProc)(ElementArgs *args);
+ ElementType *next;
+};
+
+/* list of these for each style */
+struct Element
+{
+ Tk_Uid name; /* "image", "text" etc */
+ ElementType *typePtr;
+ Element *master; /* NULL if this is master */
+ /* type-specific data here */
+};
+
+extern ElementType elemTypeBitmap;
+extern ElementType elemTypeBorder;
+extern ElementType elemTypeImage;
+extern ElementType elemTypeRect;
+extern ElementType elemTypeText;
+
+extern int Element_GetSortData(TreeCtrl *tree, Element *elem, int type, long *lv, double *dv, char **sv);
+
diff --git a/generic/tkTreeItem.c b/generic/tkTreeItem.c
new file mode 100644
index 0000000..89cdf42
--- /dev/null
+++ b/generic/tkTreeItem.c
@@ -0,0 +1,3662 @@
+#include "tkTreeCtrl.h"
+
+typedef struct Column Column;
+typedef struct Item Item;
+
+struct Column
+{
+ int neededWidth;
+ int neededHeight;
+ TreeStyle style;
+ Column *next;
+};
+
+struct Item
+{
+ int id; /* unique id */
+ int depth; /* tree depth (-1 for the unique root item) */
+ int neededHeight; /* miniumum height of this item (max of all columns) */
+ int fixedHeight; /* desired height of this item (zero for no-such-value) */
+ int numChildren;
+ int index; /* "row" in flattened tree */
+ int indexVis; /* visible "row" in flattened tree, or -1 if not visible */
+ int state; /* STATE_xxx */
+ int isVisible;
+ int hasButton;
+ Item *parent;
+ Item *firstChild;
+ Item *lastChild;
+ Item *prevSibling;
+ Item *nextSibling;
+ TreeItemDInfo dInfo; /* display info, or NULL */
+ TreeItemRInfo rInfo; /* range info, or NULL */
+ Column *columns;
+};
+
+#define ISROOT(i) ((i)->depth == -1)
+
+/*****/
+
+static Column *Column_Alloc(void)
+{
+ Column *column = (Column *) ckalloc(sizeof(Column));
+ memset(column, '\0', sizeof(Column));
+ return column;
+}
+
+void TreeItemColumn_InvalidateSize(TreeCtrl *tree, TreeItemColumn column_)
+{
+ Column *column = (Column *) column_;
+
+ column->neededWidth = column->neededHeight = -1;
+}
+
+#if 0
+
+int Column_NeededHeight(TreeCtrl *tree, Item *item, Column *self)
+{
+ int width, height;
+
+ if (self->style != NULL)
+ TreeStyle_GetNeededSize(tree, self->style, item->state, &width, &height);
+ else
+ width = height = 0;
+ return height;
+}
+
+#endif
+
+int TreeItemColumn_NeededWidth(TreeCtrl *tree, TreeItem item_, TreeItemColumn column_)
+{
+ Item *item = (Item *) item_;
+ Column *self = (Column *) column_;
+
+ if (self->style != NULL)
+ return TreeStyle_NeededWidth(tree, self->style, item->state);
+ return 0;
+}
+
+TreeStyle TreeItemColumn_GetStyle(TreeCtrl *tree, TreeItemColumn column)
+{
+ return ((Column *) column)->style;
+}
+
+void TreeItemColumn_ForgetStyle(TreeCtrl *tree, TreeItemColumn column_)
+{
+ Column *self = (Column *) column_;
+
+ if (self->style != NULL)
+ {
+ TreeStyle_FreeResources(tree, self->style);
+ self->style = NULL;
+ self->neededWidth = self->neededHeight = 0;
+ }
+}
+
+TreeItemColumn TreeItemColumn_GetNext(TreeCtrl *tree, TreeItemColumn column)
+{
+ return (TreeItemColumn) ((Column *) column)->next;
+}
+
+Column *Column_FreeResources(TreeCtrl *tree, Column *self)
+{
+ Column *next = self->next;
+
+ if (self->style != NULL)
+ TreeStyle_FreeResources(tree, self->style);
+ WFREE(self, Column);
+ return next;
+}
+
+/*****/
+
+static void Item_UpdateIndex(TreeCtrl *tree, Item *item, int *index, int *indexVis)
+{
+ Item *child;
+ int parentVis, parentOpen;
+
+ /* Also track max depth */
+ if (item->parent != NULL)
+ item->depth = item->parent->depth + 1;
+ else
+ item->depth = 0;
+ if (item->depth > tree->depth)
+ tree->depth = item->depth;
+
+ item->index = (*index)++;
+ item->indexVis = -1;
+ if (item->parent != NULL)
+ {
+ parentOpen = (item->parent->state & STATE_OPEN) != 0;
+ parentVis = item->parent->indexVis != -1;
+ if (ISROOT(item->parent) && !tree->showRoot)
+ {
+ parentOpen = TRUE;
+ parentVis = item->parent->isVisible;
+ }
+ if (parentVis && parentOpen && item->isVisible)
+ item->indexVis = (*indexVis)++;
+ }
+ child = item->firstChild;
+ while (child != NULL)
+ {
+ Item_UpdateIndex(tree, child, index, indexVis);
+ child = child->nextSibling;
+ }
+}
+
+void Tree_UpdateItemIndex(TreeCtrl *tree)
+{
+ Item *item = (Item *) tree->root;
+ int index = 1, indexVis = 0;
+
+if (tree->debug.enable && tree->debug.data)
+ dbwin("Tree_UpdateItemIndex %s\n", Tk_PathName(tree->tkwin));
+
+ /* Also track max depth */
+ tree->depth = 0;
+
+ item->index = 0;
+ item->indexVis = -1;
+ if (tree->showRoot && item->isVisible)
+ item->indexVis = indexVis++;
+ item = item->firstChild;
+ while (item != NULL)
+ {
+ Item_UpdateIndex(tree, item, &index, &indexVis);
+ item = item->nextSibling;
+ }
+ tree->itemVisCount = indexVis;
+ tree->updateIndex = 0;
+}
+
+TreeItem TreeItem_Alloc(TreeCtrl *tree)
+{
+ Item *item = (Item *) ckalloc(sizeof(Item));
+ memset(item, '\0', sizeof(Item));
+ item->isVisible = TRUE;
+ item->state =
+ STATE_OPEN |
+ STATE_ENABLED;
+ if (tree->gotFocus)
+ item->state |= STATE_FOCUS;
+ item->indexVis = -1;
+ Tree_AddItem(tree, (TreeItem) item);
+ return (TreeItem) item;
+}
+
+TreeItem TreeItem_AllocRoot(TreeCtrl *tree)
+{
+ Item *item;
+
+ item = (Item *) TreeItem_Alloc(tree);
+ item->depth = -1;
+ item->state |= STATE_ACTIVE;
+ return (TreeItem) item;
+}
+
+TreeItemColumn TreeItem_GetFirstColumn(TreeCtrl *tree, TreeItem item)
+{
+ return (TreeItemColumn) ((Item *) item)->columns;
+}
+
+int TreeItem_GetState(TreeCtrl *tree, TreeItem item_)
+{
+ return ((Item *) item_)->state;
+}
+
+int TreeItem_ChangeState(TreeCtrl *tree, TreeItem item_, int stateOff, int stateOn)
+{
+ Item *item = (Item *) item_;
+ Column *column;
+ int columnIndex = 0, state;
+ int sMask, iMask = 0;
+
+ state = item->state;
+ state &= ~stateOff;
+ state |= stateOn;
+
+ if (state == item->state)
+ return 0;
+
+ column = item->columns;
+ while (column != NULL)
+ {
+ if (column->style != NULL)
+ {
+ sMask = TreeStyle_ChangeState(tree, column->style, item->state, state);
+ if (sMask)
+ {
+ if (sMask & CS_LAYOUT)
+ Tree_InvalidateColumnWidth(tree, columnIndex);
+ iMask |= sMask;
+ }
+ }
+ columnIndex++;
+ column = column->next;
+ }
+
+ /* OPEN -> CLOSED or vice versa */
+ if ((stateOff | stateOn) & STATE_OPEN)
+ {
+ /* This item has a button */
+ if (item->hasButton && tree->showButtons && (!ISROOT(item) || tree->showRootButton))
+ {
+ /* Image or bitmap is used */
+ if ((tree->openButtonWidth != tree->closedButtonWidth) ||
+ (tree->openButtonHeight != tree->closedButtonHeight))
+ {
+ iMask |= CS_LAYOUT;
+ }
+ iMask |= CS_DISPLAY;
+ }
+ }
+
+ if (iMask & CS_LAYOUT)
+ {
+ TreeItem_InvalidateHeight(tree, item_);
+ Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
+ }
+ if (iMask & CS_DISPLAY)
+ Tree_InvalidateItemDInfo(tree, item_, NULL);
+
+ item->state = state;
+
+ return iMask;
+}
+
+void TreeItem_Undefine(TreeCtrl *tree, TreeItem item_, int state)
+{
+ Item *item = (Item *) item_;
+ item->state &= ~state;
+}
+
+int TreeItem_GetButton(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return item->hasButton;
+}
+
+int TreeItem_SetButton(TreeCtrl *tree, TreeItem item_, int hasButton)
+{
+ Item *item = (Item *) item_;
+ return item->hasButton = hasButton;
+}
+
+int TreeItem_GetDepth(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+#if 0
+ if (tree->updateIndex)
+ {
+ if (tree->debug.enable && tree->debug.data) dbwin("%s: ", __FUNCTION__);
+ Tree_UpdateItemIndex(tree);
+ }
+#endif
+ return item->depth;
+}
+
+int TreeItem_SetDepth(TreeCtrl *tree, TreeItem item_, int depth)
+{
+ Item *item = (Item *) item_;
+ return item->depth = depth;
+}
+
+int TreeItem_GetID(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return item->id;
+}
+
+int TreeItem_SetID(TreeCtrl *tree, TreeItem item_, int id)
+{
+ Item *item = (Item *) item_;
+ return item->id = id;
+}
+
+int TreeItem_GetOpen(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return (item->state & STATE_OPEN) != 0;
+}
+
+int TreeItem_SetOpen(TreeCtrl *tree, TreeItem item_, int isOpen)
+{
+ Item *item = (Item *) item_;
+ if (isOpen)
+ item->state |= STATE_OPEN;
+ else
+ item->state &= ~STATE_OPEN;
+ return isOpen;
+}
+
+int TreeItem_GetSelected(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return (item->state & STATE_SELECTED) != 0;
+}
+
+int TreeItem_SetSelected(TreeCtrl *tree, TreeItem item_, int isSelected)
+{
+ Item *item = (Item *) item_;
+ if (isSelected)
+ item->state |= STATE_SELECTED;
+ else
+ item->state &= ~STATE_SELECTED;
+ return isSelected;
+}
+
+TreeItem TreeItem_SetFirstChild(TreeCtrl *tree, TreeItem item_, TreeItem firstChild)
+{
+ Item *item = (Item *) item_;
+ return (TreeItem) (item->firstChild = (Item *) firstChild);
+}
+
+TreeItem TreeItem_GetFirstChild(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return (TreeItem) item->firstChild;
+}
+
+TreeItem TreeItem_SetLastChild(TreeCtrl *tree, TreeItem item_, TreeItem lastChild)
+{
+ Item *item = (Item *) item_;
+ return (TreeItem) (item->lastChild = (Item *) lastChild);
+}
+
+TreeItem TreeItem_GetLastChild(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return (TreeItem) item->lastChild;
+}
+
+TreeItem TreeItem_SetParent(TreeCtrl *tree, TreeItem item_, TreeItem parent)
+{
+ Item *item = (Item *) item_;
+ return (TreeItem) (item->parent = (Item *) parent);
+}
+
+TreeItem TreeItem_GetParent(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return (TreeItem) item->parent;
+}
+
+TreeItem TreeItem_SetNextSibling(TreeCtrl *tree, TreeItem item_, TreeItem nextSibling)
+{
+ Item *item = (Item *) item_;
+ return (TreeItem) (item->nextSibling = (Item *) nextSibling);
+}
+
+TreeItem TreeItem_GetNextSibling(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return (TreeItem) item->nextSibling;
+}
+
+TreeItem TreeItem_SetPrevSibling(TreeCtrl *tree, TreeItem item_, TreeItem prevSibling)
+{
+ Item *item = (Item *) item_;
+ return (TreeItem) (item->prevSibling = (Item *) prevSibling);
+}
+
+TreeItem TreeItem_GetPrevSibling(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return (TreeItem) item->prevSibling;
+}
+
+void TreeItem_SetDInfo(TreeCtrl *tree, TreeItem item_, TreeItemDInfo dInfo)
+{
+ Item *item = (Item *) item_;
+ item->dInfo = dInfo;
+}
+
+TreeItemDInfo TreeItem_GetDInfo(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return item->dInfo;
+}
+
+void TreeItem_SetRInfo(TreeCtrl *tree, TreeItem item_, TreeItemRInfo rInfo)
+{
+ Item *item = (Item *) item_;
+ item->rInfo = rInfo;
+}
+
+TreeItemRInfo TreeItem_GetRInfo(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ return item->rInfo;
+}
+
+TreeItem TreeItem_Next(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+
+ if (item->firstChild != NULL)
+ return (TreeItem) item->firstChild;
+ if (item->nextSibling != NULL)
+ return (TreeItem) item->nextSibling;
+ while (1)
+ {
+ item = item->parent;
+ if (item == NULL)
+ break;
+ if (item->nextSibling != NULL)
+ return (TreeItem) item->nextSibling;
+ }
+ return NULL;
+}
+
+TreeItem TreeItem_NextVisible(TreeCtrl *tree, TreeItem item)
+{
+ item = TreeItem_Next(tree, item);
+ while (item != NULL)
+ {
+ if (TreeItem_ReallyVisible(tree, item))
+ return item;
+ item = TreeItem_Next(tree, item);
+ }
+ return NULL;
+}
+
+TreeItem TreeItem_Prev(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ Item *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 (TreeItem) walk;
+}
+
+TreeItem TreeItem_PrevVisible(TreeCtrl *tree, TreeItem item)
+{
+ item = TreeItem_Prev(tree, item);
+ while (item != NULL)
+ {
+ if (TreeItem_ReallyVisible(tree, item))
+ return item;
+ item = TreeItem_Prev(tree, item);
+ }
+ return NULL;
+}
+
+void TreeItem_ToIndex(TreeCtrl *tree, TreeItem item_, int *index, int *indexVis)
+{
+ Item *item = (Item *) item_;
+
+ if (tree->updateIndex)
+ {
+ if (tree->debug.enable && tree->debug.data) dbwin("%s: ", __FUNCTION__);
+ Tree_UpdateItemIndex(tree);
+ }
+ if (index != NULL) (*index) = item->index;
+ if (indexVis != NULL) (*indexVis) = item->indexVis;
+}
+
+static int IndexFromList(int listIndex, int objc, Tcl_Obj **objv, CONST char **indexNames)
+{
+ Tcl_Obj *elemPtr;
+ int index;
+
+ if (listIndex >= objc)
+ return -1;
+ elemPtr = objv[listIndex];
+ if (Tcl_GetIndexFromObj(NULL, elemPtr, indexNames, NULL, 0, &index) != TCL_OK)
+ return -1;
+ return index;
+}
+
+/*
+%W index all
+%W index "active MODIFIERS"
+%W index "anchor MODIFIERS"
+%W index "nearest x y MODIFIERS"
+%W index "root MODIFIERS"
+%W index "first MODIFIERS"
+%W index "last MODIFIERS"
+%W index "ID MODIFIERS"
+MODIFIERS:
+ above
+ below
+ left
+ right
+ top
+ bottom
+ leftmost
+ rightmost
+ next
+ prev
+ parent
+ firstchild
+ lastchild
+ child N
+ nextsibling
+ prevsibling
+ sibling N
+ visible
+
+Examples:
+ %W index "first visible firstchild"
+ %W index "first visible firstchild visible"
+ %W index "nearest x y nextsibling visible"
+*/
+
+int TreeItem_FromObj(TreeCtrl *tree, Tcl_Obj *objPtr, TreeItem *itemPtr, int flags)
+{
+ Tcl_Interp *interp = tree->interp;
+ int objc;
+ int index, listIndex, id;
+ Tcl_HashEntry *hPtr;
+ Tcl_Obj **objv, *elemPtr;
+ Item *item = NULL;
+ static CONST char *indexName[] = { "active", "all", "anchor", "first", "last",
+ "nearest", "rnc", "root", (char *) NULL };
+ enum indexEnum {
+ INDEX_ACTIVE, INDEX_ALL, INDEX_ANCHOR, INDEX_FIRST, INDEX_LAST,
+ INDEX_NEAREST, INDEX_RNC, INDEX_ROOT
+ } ;
+ static CONST char *modifiers[] = { "above", "below", "bottom", "child",
+ "firstchild", "lastchild", "left", "leftmost", "next", "nextsibling",
+ "parent", "prev", "prevsibling", "right", "rightmost", "sibling", "top",
+ "visible", (char *) NULL };
+ enum modEnum {
+ MOD_ABOVE, MOD_BELOW, MOD_BOTTOM, MOD_CHILD, MOD_FIRSTCHILD, MOD_LASTCHILD,
+ MOD_LEFT, MOD_LEFTMOST, MOD_NEXT, MOD_NEXTSIBLING, MOD_PARENT, MOD_PREV, MOD_PREVSIBLING,
+ MOD_RIGHT, MOD_RIGHTMOST, MOD_SIBLING, MOD_TOP, MOD_VISIBLE
+ };
+ static int modArgs[] = { 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1 };
+
+ 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)
+ {
+ switch ((enum indexEnum) index)
+ {
+ case INDEX_ACTIVE:
+ {
+ item = (Item *) tree->activeItem;
+ break;
+ }
+ case INDEX_ALL:
+ {
+ if (!(flags & IFO_ALLOK))
+ {
+ Tcl_AppendResult(interp,
+ "can't specify \"all\" for this command", NULL);
+ return TCL_ERROR;
+ }
+ if (objc > 1)
+ goto baditem;
+ (*itemPtr) = ITEM_ALL;
+ return TCL_OK;
+ }
+ case INDEX_ANCHOR:
+ {
+ item = (Item *) tree->anchorItem;
+ break;
+ }
+ case INDEX_FIRST:
+ {
+ item = (Item *) tree->root;
+ if (IndexFromList(listIndex, objc, objv, modifiers) == MOD_VISIBLE)
+ {
+ if (!item->isVisible)
+ item = NULL;
+ else if (!tree->showRoot)
+ item = (Item *) TreeItem_NextVisible(tree, (TreeItem) item);
+ listIndex++;
+ }
+ break;
+ }
+ case INDEX_LAST:
+ {
+ item = (Item *) tree->root;
+ while (item->lastChild)
+ {
+ item = item->lastChild;
+ }
+ if (IndexFromList(listIndex, objc, objv, modifiers) == MOD_VISIBLE)
+ {
+ if (!((Item *) tree->root)->isVisible)
+ item = NULL; /* nothing is visible */
+ else if (item == (Item *) tree->root && !tree->showRoot)
+ item = NULL; /* no item but root, not visible */
+ else if (!TreeItem_ReallyVisible(tree, (TreeItem) item))
+ item = (Item *) TreeItem_PrevVisible(tree, (TreeItem) item);
+ listIndex++;
+ }
+ break;
+ }
+ case INDEX_NEAREST:
+ {
+ int x, y;
+
+ if (objc < 3)
+ goto baditem;
+ if (Tcl_GetIntFromObj(NULL, objv[listIndex++], &x) != TCL_OK)
+ goto baditem;
+ if (Tcl_GetIntFromObj(NULL, objv[listIndex++], &y) != TCL_OK)
+ goto baditem;
+ item = (Item *) Tree_ItemUnderPoint(tree, &x, &y, TRUE);
+ break;
+ }
+ case INDEX_RNC:
+ {
+ int row, col;
+
+ if (objc < 3)
+ goto baditem;
+ if (Tcl_GetIntFromObj(NULL, objv[listIndex++], &row) != TCL_OK)
+ goto baditem;
+ if (Tcl_GetIntFromObj(NULL, objv[listIndex++], &col) != TCL_OK)
+ goto baditem;
+ item = (Item *) Tree_RNCToItem(tree, row, col);
+ break;
+ }
+ case INDEX_ROOT:
+ {
+ if ((flags & IFO_NOTROOT))
+ {
+ Tcl_AppendResult(interp,
+ "can't specify \"root\" for this command", NULL);
+ return TCL_ERROR;
+ }
+ item = (Item *) tree->root;
+ break;
+ }
+ }
+ }
+ else if (Tcl_GetIntFromObj(NULL, elemPtr, &id) == TCL_OK)
+ {
+ hPtr = Tcl_FindHashEntry(&tree->itemHash, (char *) id);
+ if (!hPtr)
+ {
+ if (!(flags & IFO_NULLOK))
+ goto noitem;
+ (*itemPtr) = NULL;
+ return TCL_OK;
+ }
+ item = (Item *) Tcl_GetHashValue(hPtr);
+ }
+ else
+ {
+ goto baditem;
+ }
+ /* This means a valid specification was given, but there is no such item */
+ if (item == NULL)
+ {
+ if (!(flags & IFO_NULLOK))
+ goto noitem;
+ (*itemPtr) = (TreeItem) item;
+ return TCL_OK;
+ }
+ for (; listIndex < objc; /* nothing */)
+ {
+ int nextIsVisible = FALSE;
+
+ elemPtr = objv[listIndex];
+ if (Tcl_GetIndexFromObj(interp, elemPtr, modifiers, "modifier", 0, &index) != TCL_OK)
+ return TCL_ERROR;
+ if (objc - listIndex < modArgs[index])
+ goto baditem;
+ if (IndexFromList(listIndex + modArgs[index], objc, objv, modifiers) == MOD_VISIBLE)
+ nextIsVisible = TRUE;
+ switch ((enum modEnum) index)
+ {
+ case MOD_ABOVE:
+ {
+ item = (Item *) Tree_ItemAbove(tree, (TreeItem) item);
+ break;
+ }
+ case MOD_BELOW:
+ {
+ item = (Item *) Tree_ItemBelow(tree, (TreeItem) item);
+ break;
+ }
+ case MOD_BOTTOM:
+ {
+ item = (Item *) Tree_ItemBottom(tree, (TreeItem) item);
+ break;
+ }
+ case MOD_CHILD:
+ {
+ int n;
+
+ if (Tcl_GetIntFromObj(interp, objv[listIndex + 1], &n) != TCL_OK)
+ return TCL_ERROR;
+ item = item->firstChild;
+ if (nextIsVisible)
+ {
+ while (item != NULL)
+ {
+ if (TreeItem_ReallyVisible(tree, (TreeItem) item))
+ if (n-- <= 0)
+ break;
+ item = item->nextSibling;
+ }
+ }
+ else
+ {
+ while ((n-- > 0) && (item != NULL))
+ item = item->nextSibling;
+ }
+ break;
+ }
+ case MOD_FIRSTCHILD:
+ {
+ item = item->firstChild;
+ if (nextIsVisible)
+ {
+ while ((item != NULL) && !TreeItem_ReallyVisible(tree, (TreeItem) item))
+ item = item->nextSibling;
+ }
+ break;
+ }
+ case MOD_LASTCHILD:
+ {
+ item = item->lastChild;
+ if (nextIsVisible)
+ {
+ while ((item != NULL) && !TreeItem_ReallyVisible(tree, (TreeItem) item))
+ item = item->prevSibling;
+ }
+ break;
+ }
+ case MOD_LEFT:
+ {
+ item = (Item *) Tree_ItemLeft(tree, (TreeItem) item);
+ break;
+ }
+ case MOD_LEFTMOST:
+ {
+ item = (Item *) Tree_ItemLeftMost(tree, (TreeItem) item);
+ break;
+ }
+ case MOD_NEXT:
+ {
+ if (nextIsVisible)
+ item = (Item *) TreeItem_NextVisible(tree, (TreeItem) item);
+ else
+ item = (Item *) TreeItem_Next(tree, (TreeItem) item);
+ break;
+ }
+ case MOD_NEXTSIBLING:
+ {
+ item = item->nextSibling;
+ if (nextIsVisible)
+ {
+ while ((item != NULL) && !TreeItem_ReallyVisible(tree, (TreeItem) item)) {
+ item = item->nextSibling;
+ }
+ }
+ break;
+ }
+ case MOD_PARENT:
+ {
+ item = item->parent;
+ break;
+ }
+ case MOD_PREV:
+ {
+ if (nextIsVisible)
+ item = (Item *) TreeItem_PrevVisible(tree, (TreeItem) item);
+ else
+ item = (Item *) TreeItem_Prev(tree, (TreeItem) item);
+ break;
+ }
+ case MOD_PREVSIBLING:
+ {
+ item = item->prevSibling;
+ if (nextIsVisible)
+ {
+ while ((item != NULL) && !TreeItem_ReallyVisible(tree, (TreeItem) item)) {
+ item = item->prevSibling;
+ }
+ }
+ break;
+ }
+ case MOD_RIGHT:
+ {
+ item = (Item *) Tree_ItemRight(tree, (TreeItem) item);
+ break;
+ }
+ case MOD_RIGHTMOST:
+ {
+ item = (Item *) Tree_ItemRightMost(tree, (TreeItem) item);
+ break;
+ }
+ case MOD_SIBLING:
+ {
+ int n;
+
+ if (Tcl_GetIntFromObj(interp, objv[listIndex + 1], &n) != TCL_OK)
+ return TCL_ERROR;
+ item = item->parent;
+ if (item == NULL)
+ break;
+ item = item->firstChild;
+ if (nextIsVisible)
+ {
+ while (item != NULL)
+ {
+ if (TreeItem_ReallyVisible(tree, (TreeItem) item))
+ if (n-- <= 0)
+ break;
+ item = item->nextSibling;
+ }
+ }
+ else
+ {
+ while ((n-- > 0) && (item != NULL))
+ item = item->nextSibling;
+ }
+ break;
+ }
+ case MOD_TOP:
+ {
+ item = (Item *) Tree_ItemTop(tree, (TreeItem) item);
+ break;
+ }
+ case MOD_VISIBLE:
+ {
+ break;
+ }
+ }
+ if (item == NULL)
+ {
+ if (!(flags & IFO_NULLOK))
+ goto noitem;
+ (*itemPtr) = (TreeItem) item;
+ return TCL_OK;
+ }
+ listIndex += modArgs[index];
+ if (nextIsVisible)
+ listIndex++;
+ }
+ (*itemPtr) = (TreeItem) item;
+ return TCL_OK;
+baditem:
+ Tcl_AppendResult(interp, "bad item description \"", Tcl_GetString(objPtr),
+ "\"", NULL);
+ return TCL_ERROR;
+noitem:
+ Tcl_AppendResult(interp, "item \"", Tcl_GetString(objPtr),
+ "\" doesn't exist", NULL);
+ return TCL_ERROR;
+}
+
+static void Item_Toggle(TreeCtrl *tree, Item *item, int stateOff, int stateOn)
+{
+ int mask;
+
+ mask = TreeItem_ChangeState(tree, (TreeItem) item, stateOff, stateOn);
+
+ if (ISROOT(item) && !tree->showRoot)
+ return;
+
+#if 0
+ /* Don't affect display if we weren't visible */
+ if (!TreeItem_ReallyVisible(tree, (TreeItem) item))
+ return;
+
+ /* Invalidate display info for this item, so it is redrawn later. */
+ Tree_InvalidateItemDInfo(tree, (TreeItem) 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 */
+ Tree_InvalidateColumnWidth(tree, -1);
+ }
+
+ /* If this item was previously onscreen, this call is repetitive. */
+ Tree_EventuallyRedraw(tree);
+}
+
+void TreeItem_OpenClose(TreeCtrl *tree, TreeItem item_, int mode, int recurse)
+{
+ Item *item = (Item *) item_;
+ Item *child;
+ int stateOff = 0, stateOn = 0;
+
+ if (mode == -1)
+ {
+ if (item->state & STATE_OPEN)
+ stateOff = STATE_OPEN;
+ else
+ stateOn = STATE_OPEN;
+ }
+ else if (!mode && (item->state & STATE_OPEN))
+ stateOff = STATE_OPEN;
+ else if (mode && !(item->state & STATE_OPEN))
+ stateOn = STATE_OPEN;
+
+ if (stateOff != stateOn)
+ {
+ TreeNotify_OpenClose(tree, item_, stateOn, TRUE);
+ Item_Toggle(tree, item, stateOff, stateOn);
+ TreeNotify_OpenClose(tree, item_, stateOn, FALSE);
+ }
+ if (recurse)
+ {
+ for (child = item->firstChild; child != NULL; child = child->nextSibling)
+ TreeItem_OpenClose(tree, (TreeItem) child, mode, recurse);
+ }
+}
+
+void TreeItem_Delete(TreeCtrl *tree, TreeItem item_)
+{
+ Item *self = (Item *) item_;
+
+ if (TreeItem_ReallyVisible(tree, item_))
+ Tree_InvalidateColumnWidth(tree, -1);
+
+ while (self->numChildren > 0)
+ TreeItem_Delete(tree, (TreeItem) self->firstChild);
+
+ TreeItem_RemoveFromParent(tree, item_);
+ Tree_RemoveItem(tree, item_);
+ TreeItem_FreeResources(tree, item_);
+ if (tree->activeItem == item_)
+ {
+ tree->activeItem = tree->root;
+ TreeItem_ChangeState(tree, tree->activeItem, 0, STATE_ACTIVE);
+ }
+ if (tree->anchorItem == item_)
+ tree->anchorItem = tree->root;
+ if (tree->debug.enable && tree->debug.data)
+ Tree_Debug(tree);
+}
+
+void TreeItem_UpdateDepth(TreeCtrl *tree, TreeItem item_)
+{
+ Item *self = (Item *) item_;
+ Item *child;
+
+ if (ISROOT(self))
+ return;
+ if (self->parent != NULL)
+ self->depth = self->parent->depth + 1;
+ else
+ self->depth = 0;
+ child = self->firstChild;
+ while (child != NULL)
+ {
+ TreeItem_UpdateDepth(tree, (TreeItem) child);
+ child = child->nextSibling;
+ }
+}
+
+void TreeItem_AddToParent(TreeCtrl *tree, TreeItem item_)
+{
+ Item *self = (Item *) item_;
+ Item *last;
+
+ /* 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 ((self->prevSibling != NULL) &&
+ (self->nextSibling == NULL) &&
+ tree->showLines)
+ {
+ last = self->prevSibling;
+ while (last->lastChild != NULL)
+ last = last->lastChild;
+ Tree_InvalidateItemDInfo(tree, (TreeItem) self->prevSibling,
+ (TreeItem) last);
+ }
+
+ 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_);
+
+ Tree_InvalidateColumnWidth(tree, -1);
+ if (tree->debug.enable && tree->debug.data)
+ Tree_Debug(tree);
+}
+
+static void RemoveFromParentAux(TreeCtrl *tree, Item *self, int *index)
+{
+ Item *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 (self->dInfo != NULL)
+ Tree_InvalidateItemDInfo(tree, (TreeItem) self, NULL);
+
+ if (self->parent != NULL)
+ self->depth = self->parent->depth + 1;
+ else
+ self->depth = 0;
+ self->index = (*index)++;
+ child = self->firstChild;
+ while (child != NULL)
+ {
+ RemoveFromParentAux(tree, child, index);
+ child = child->nextSibling;
+ }
+}
+
+void TreeItem_RemoveFromParent(TreeCtrl *tree, TreeItem item_)
+{
+ Item *self = (Item *) item_;
+ Item *parent = self->parent;
+ Item *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 ((self->prevSibling != NULL) &&
+ (self->nextSibling == NULL) &&
+ tree->showLines)
+ {
+ last = self->prevSibling;
+ while (last->lastChild != NULL)
+ last = last->lastChild;
+ Tree_InvalidateItemDInfo(tree, (TreeItem) self->prevSibling,
+ (TreeItem) last);
+ }
+
+ tree->updateIndex = 1;
+ Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
+
+ if (self->prevSibling)
+ self->prevSibling->nextSibling = self->nextSibling;
+ if (self->nextSibling)
+ self->nextSibling->prevSibling = self->prevSibling;
+ if (parent->firstChild == self)
+ {
+ parent->firstChild = self->nextSibling;
+ if (!parent->firstChild)
+ parent->lastChild = NULL;
+ }
+ if (parent->lastChild == self)
+ parent->lastChild = self->prevSibling;
+ self->prevSibling = self->nextSibling = NULL;
+ self->parent = NULL;
+ parent->numChildren--;
+
+ /* Update depth, index and indexVis. Index is needed for some operations
+ * that use a range of items, such as delete. */
+ RemoveFromParentAux(tree, self, &index);
+}
+
+void TreeItem_RemoveColumn(TreeCtrl *tree, TreeItem item_, TreeItemColumn column_)
+{
+ Item *self = (Item *) item_;
+ Column *column, *prev;
+
+ column = self->columns;
+ prev = NULL;
+ while (column != NULL)
+ {
+ if (column == (Column *) column_)
+ {
+ if (prev != NULL)
+ prev->next = column->next;
+ else
+ self->columns = column->next;
+ Column_FreeResources(tree, column);
+ break;
+ }
+ prev = column;
+ column = column->next;
+ }
+ if (column == NULL)
+ panic("TreeItem_RemoveColumn: can't find column");
+}
+
+void TreeItem_FreeResources(TreeCtrl *tree, TreeItem item_)
+{
+ Item *self = (Item *) item_;
+ Column *column;
+
+ column = self->columns;
+ while (column != NULL)
+ column = Column_FreeResources(tree, column);
+ if (self->dInfo != NULL)
+ Tree_FreeItemDInfo(tree, item_, NULL);
+ if (self->rInfo != NULL)
+ Tree_FreeItemRInfo(tree, item_);
+ WFREE(self, Item);
+}
+
+int TreeItem_NeededHeight(TreeCtrl *tree, TreeItem item_)
+{
+ Item *self = (Item *) item_;
+ Column *column;
+
+ self->neededHeight = 0;
+ for (column = self->columns; column != NULL; column = column->next)
+ {
+ if (column->style != NULL)
+ {
+ self->neededHeight = MAX(self->neededHeight,
+ TreeStyle_NeededHeight(tree, column->style, self->state));
+ }
+ }
+ return self->neededHeight;
+}
+
+int TreeItem_UseHeight(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ Column *column = item->columns;
+ TreeColumn treeColumn = tree->columns;
+ StyleDrawArgs drawArgs;
+ int height = 0;
+
+ drawArgs.tree = tree;
+ drawArgs.state = item->state;
+
+ while (column != NULL)
+ {
+ if (TreeColumn_Visible(treeColumn) && (column->style != NULL))
+ {
+ drawArgs.style = column->style;
+ if (TreeColumn_FixedWidth(treeColumn) != -1)
+ {
+ drawArgs.width = TreeColumn_UseWidth(treeColumn);
+ if (TreeColumn_Index(treeColumn) == tree->columnTree)
+ drawArgs.width -= TreeItem_Indent(tree, item_);
+ }
+ else
+ drawArgs.width = -1;
+ height = MAX(height, TreeStyle_UseHeight(&drawArgs));
+ }
+ treeColumn = TreeColumn_Next(treeColumn);
+ column = column->next;
+ }
+
+ return height;
+}
+
+int TreeItem_Height(TreeCtrl *tree, TreeItem item_)
+{
+ Item *self = (Item *) item_;
+ int buttonHeight = 0;
+ int useHeight;
+
+ if (!self->isVisible || (ISROOT(self) && !tree->showRoot))
+ return 0;
+
+ /* Update column + style + element sizes */
+ useHeight = TreeItem_UseHeight(tree, item_);
+
+ /* Can't have less height than our button */
+ if (tree->showButtons && self->hasButton && (!ISROOT(self) || tree->showRootButton))
+ {
+ buttonHeight = (self->state & STATE_OPEN) ?
+ tree->openButtonHeight : tree->closedButtonHeight;
+ }
+
+ /* User specified a fixed height for this item */
+ if (self->fixedHeight > 0)
+ return MAX(self->fixedHeight, buttonHeight);
+
+ /* Fixed height of all items */
+ if (tree->itemHeight > 0)
+ return MAX(tree->itemHeight, buttonHeight);
+
+ /* No fixed height specified */
+ return MAX(useHeight, buttonHeight);
+}
+
+void TreeItem_InvalidateHeight(TreeCtrl *tree, TreeItem item_)
+{
+ Item *self = (Item *) item_;
+
+ if (self->neededHeight < 0)
+ return;
+ self->neededHeight = -1;
+}
+
+static Column *Item_CreateColumn(TreeCtrl *tree, Item *self, int columnIndex, int *isNew)
+{
+ Column *column;
+ int i;
+
+ if (isNew != NULL) (*isNew) = FALSE;
+ column = self->columns;
+ if (column == NULL)
+ {
+ column = Column_Alloc();
+ column->neededWidth = column->neededHeight = -1;
+ self->columns = column;
+ if (isNew != NULL) (*isNew) = TRUE;
+ }
+ for (i = 0; i < columnIndex; i++)
+ {
+ if (column->next == NULL)
+ {
+ column->next = Column_Alloc();
+ column->next->neededWidth = column->next->neededHeight = -1;
+ if (isNew != NULL) (*isNew) = TRUE;
+ }
+ column = column->next;
+ }
+
+ Tree_CreateColumn(tree, columnIndex, NULL);
+
+ return column;
+}
+
+static Column *Item_FindColumn(TreeCtrl *tree, Item *self, int columnIndex)
+{
+ Column *column;
+ int i = 0;
+
+ column = self->columns;
+ if (!column)
+ return NULL;
+ while (column != NULL && i < columnIndex)
+ {
+ column = column->next;
+ i++;
+ }
+ return column;
+}
+
+static int Item_FindColumnFromObj(TreeCtrl *tree, Item *item, Tcl_Obj *obj,
+ Column **column, int *indexPtr)
+{
+ int columnIndex;
+
+ if (Tcl_GetIntFromObj(NULL, obj, &columnIndex) == TCL_OK)
+ {
+ if (columnIndex < 0)
+ {
+ FormatResult(tree->interp, "bad column index \"%d\": must be > 0",
+ columnIndex);
+ return TCL_ERROR;
+ }
+ }
+ else
+ {
+ TreeColumn treeColumn;
+
+ if (Tree_FindColumnByTag(tree, obj, &treeColumn, CFO_NOT_TAIL) != TCL_OK)
+ return TCL_ERROR;
+ columnIndex = TreeColumn_Index(treeColumn);
+ }
+ (*column) = Item_FindColumn(tree, item, columnIndex);
+ if ((*column) == NULL)
+ {
+ FormatResult(tree->interp, "item %d doesn't have column %d",
+ item->id, columnIndex);
+ return TCL_ERROR;
+ }
+ if (indexPtr != NULL)
+ (*indexPtr) = columnIndex;
+ return TCL_OK;
+}
+
+TreeItemColumn TreeItem_FindColumn(TreeCtrl *tree, TreeItem item, int columnIndex)
+{
+ return (TreeItemColumn) Item_FindColumn(tree, (Item *) item, columnIndex);
+}
+
+int TreeItem_ColumnFromObj(TreeCtrl *tree, TreeItem item, Tcl_Obj *obj, TreeItemColumn *columnPtr, int *indexPtr)
+{
+ return Item_FindColumnFromObj(tree, (Item *) item, obj, (Column **) columnPtr, indexPtr);
+}
+
+static int Item_CreateColumnFromObj(TreeCtrl *tree, Item *item, Tcl_Obj *obj, Column **column, int *indexPtr)
+{
+ int columnIndex;
+
+ if (Tcl_GetIntFromObj(NULL, obj, &columnIndex) == TCL_OK)
+ {
+ if (columnIndex < 0 || columnIndex >= 20)
+ {
+ FormatResult(tree->interp,
+ "bad column index \"%d\": must be from 0 to 19",
+ columnIndex);
+ return TCL_ERROR;
+ }
+ }
+ else
+ {
+ TreeColumn treeColumn;
+
+ if (Tree_FindColumnByTag(tree, obj, &treeColumn, CFO_NOT_TAIL) != TCL_OK)
+ return TCL_ERROR;
+ columnIndex = TreeColumn_Index(treeColumn);
+ }
+ (*column) = Item_CreateColumn(tree, item, columnIndex, NULL);
+ if (indexPtr != NULL)
+ (*indexPtr) = columnIndex;
+ return TCL_OK;
+}
+
+int TreeItem_Indent(TreeCtrl *tree, TreeItem item_)
+{
+ Item *self = (Item *) item_;
+ int indent;
+
+ if (ISROOT(self))
+ return (tree->showRoot && tree->showButtons && tree->showRootButton) ? tree->useIndent : 0;
+
+ if (tree->updateIndex)
+ {
+ if (tree->debug.enable && tree->debug.data) dbwin("%s: ", __FUNCTION__);
+ Tree_UpdateItemIndex(tree);
+ }
+
+ indent = tree->useIndent * self->depth;
+ if (tree->showRoot || tree->showButtons || tree->showLines)
+ indent += tree->useIndent;
+ if (tree->showRoot && tree->showButtons && tree->showRootButton)
+ indent += tree->useIndent;
+ return indent;
+}
+
+static void ItemDrawBackground(TreeCtrl *tree, TreeColumn treeColumn,
+ Item *item, Column *column, Drawable drawable, int x, int y, int width,
+ int height, int index)
+{
+ GC gc = None;
+
+ gc = TreeColumn_BackgroundGC(treeColumn, index);
+ if (gc == None)
+ gc = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC);
+ XFillRectangle(tree->display, drawable, gc, x, y, width, height);
+}
+
+void TreeItem_Draw(TreeCtrl *tree, TreeItem item_, int x, int y,
+ int width, int height, Drawable drawable, int minX, int maxX, int index)
+{
+ Item *self = (Item *) item_;
+ int indent, columnWidth, totalWidth;
+ Column *column;
+ StyleDrawArgs drawArgs;
+ TreeColumn treeColumn;
+
+ drawArgs.tree = tree;
+ drawArgs.drawable = drawable;
+ drawArgs.state = self->state;
+
+ totalWidth = 0;
+ treeColumn = tree->columns;
+ column = self->columns;
+ while (treeColumn != NULL)
+ {
+ if (!TreeColumn_Visible(treeColumn))
+ columnWidth = 0;
+ else if (tree->columnCountVis == 1)
+ columnWidth = width;
+ else
+ columnWidth = TreeColumn_UseWidth(treeColumn);
+ if (columnWidth > 0)
+ {
+ if (TreeColumn_Index(treeColumn) == tree->columnTree)
+ {
+ indent = TreeItem_Indent(tree, item_);
+#if 0
+ /* This means the tree lines/buttons don't share the item background color */
+ if ((x + totalWidth < maxX) &&
+ (x + totalWidth + indent > minX))
+ {
+ GC gc = Tk_3DBorderGC(tree->tkwin, tree->border, TK_3D_FLAT_GC);
+ XFillRectangle(tree->display, drawable, gc,
+ x + totalWidth, y, indent, height);
+ }
+#endif
+ }
+ else
+ indent = 0;
+ if ((x /* + indent */ + totalWidth < maxX) &&
+ (x + totalWidth + columnWidth > minX))
+ {
+ ItemDrawBackground(tree, treeColumn, self, column, drawable,
+ x + totalWidth /* + indent*/ , y,
+ columnWidth /* - indent */, height,
+ index);
+ if ((column != NULL) && (column->style != NULL))
+ {
+ drawArgs.style = column->style;
+ drawArgs.x = x + indent + totalWidth;
+ drawArgs.y = y;
+ drawArgs.width = columnWidth - indent;
+ drawArgs.height = height;
+ drawArgs.justify = TreeColumn_Justify(treeColumn);
+ TreeStyle_Draw(&drawArgs);
+ }
+ }
+ totalWidth += columnWidth;
+ }
+ treeColumn = TreeColumn_Next(treeColumn);
+ if (column != NULL)
+ column = column->next;
+ }
+}
+
+void TreeItem_DrawLines(TreeCtrl *tree, TreeItem item_, int x, int y, int width, int height, Drawable drawable)
+{
+ Item *self = (Item *) item_;
+ Item *parent;
+ int indent, left, lineLeft, lineTop;
+ int hasPrev = FALSE, hasNext = FALSE;
+ int i, vert = 0;
+
+ indent = TreeItem_Indent(tree, item_);
+
+ /* 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 */
+ lineTop = y + (height - tree->lineThickness) / 2;
+
+ /* Vertical line to parent and/or previous/next sibling */
+ /* The root may not actually be visible if showRoot is FALSE */
+ if ((self->parent != NULL) &&
+ TreeItem_ReallyVisible(tree, (TreeItem) self->parent))
+ hasPrev = TRUE;
+ else if ((self->prevSibling != NULL) &&
+ TreeItem_ReallyVisible(tree, (TreeItem) self->prevSibling))
+ hasPrev = TRUE;
+ if ((self->nextSibling != NULL) &&
+ TreeItem_ReallyVisible(tree, (TreeItem) self->nextSibling))
+ hasNext = TRUE;
+ 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++)
+ VDotLine(tree, drawable, tree->lineGC,
+ lineLeft + i,
+ top,
+ bottom);
+ }
+ else
+ XFillRectangle(tree->display, drawable, tree->lineGC,
+ lineLeft,
+ top,
+ tree->lineThickness,
+ bottom - top);
+
+ /* Don't overlap horizontal line */
+ vert = tree->lineThickness;
+ }
+
+ /* Horizontal line to self */
+ if (!ISROOT(self) || (tree->showRoot && tree->showButtons && tree->showRootButton))
+ {
+ if (tree->lineStyle == LINE_STYLE_DOT)
+ {
+ for (i = 0; i < tree->lineThickness; i++)
+ HDotLine(tree, drawable, tree->lineGC,
+ lineLeft + vert,
+ lineTop + i,
+ x + tree->columnTreeLeft + indent);
+ }
+ else
+ XFillRectangle(tree->display, drawable, tree->lineGC,
+ lineLeft + vert,
+ lineTop,
+ left + tree->useIndent - (lineLeft + vert),
+ tree->lineThickness);
+ }
+
+ /* Vertical lines from ancestors to their next siblings */
+ for (parent = self->parent;
+ parent != NULL;
+ parent = parent->parent)
+ {
+ lineLeft -= tree->useIndent;
+ if (parent->nextSibling != NULL &&
+ TreeItem_ReallyVisible(tree, (TreeItem) parent->nextSibling))
+ {
+ if (tree->lineStyle == LINE_STYLE_DOT)
+ {
+ for (i = 0; i < tree->lineThickness; i++)
+ VDotLine(tree, drawable, tree->lineGC,
+ lineLeft + i,
+ y,
+ y + height);
+ }
+ else
+ XFillRectangle(tree->display, drawable, tree->lineGC,
+ lineLeft,
+ y,
+ tree->lineThickness,
+ height);
+ }
+ }
+}
+
+void TreeItem_DrawButton(TreeCtrl *tree, TreeItem item_, int x, int y, int width, int height, Drawable drawable)
+{
+ Item *self = (Item *) item_;
+ int indent, left, lineLeft, lineTop;
+ Tk_Image image = NULL;
+ Pixmap bitmap = None;
+ int imgW, imgH;
+ int buttonLeft, buttonTop, w1;
+
+ if (!self->hasButton)
+ return;
+ if (ISROOT(self) && !tree->showRootButton)
+ return;
+
+ indent = TreeItem_Indent(tree, item_);
+
+ /* Left edge of button/line area */
+ left = x + tree->columnTreeLeft + indent - tree->useIndent;
+
+ if (self->state & STATE_OPEN)
+ {
+ imgW = tree->openButtonWidth;
+ imgH = tree->openButtonHeight;
+ if (tree->openButtonImage != NULL)
+ image = tree->openButtonImage;
+ else if (tree->openButtonBitmap != None)
+ bitmap = tree->openButtonBitmap;
+ }
+ else
+ {
+ imgW = tree->closedButtonWidth;
+ imgH = tree->closedButtonHeight;
+ if (tree->closedButtonImage != NULL)
+ image = tree->closedButtonImage;
+ else if (tree->closedButtonBitmap != None)
+ bitmap = tree->closedButtonBitmap;
+ }
+ if (image != NULL)
+ {
+ Tk_RedrawImage(image, 0, 0, imgW, imgH, drawable,
+ left + (tree->useIndent - imgW) / 2,
+ y + (height - imgH) / 2);
+ return;
+ }
+ if (bitmap != None)
+ {
+ GC gc = (self->state & STATE_OPEN) ? tree->buttonOpenGC : tree->buttonClosedGC;
+ int bx = left + (tree->useIndent - imgW) / 2;
+ int by = y + (height - imgH) / 2;
+
+ XSetClipOrigin(tree->display, gc, bx, by);
+ XCopyPlane(tree->display, bitmap, drawable, gc,
+ 0, 0, imgW, imgH,
+ bx, by, 1);
+ XSetClipOrigin(tree->display, gc, 0, 0);
+ 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() */
+ lineTop = y + (height - tree->buttonThickness) / 2;
+
+ buttonLeft = left + (tree->useIndent - tree->buttonSize) / 2;
+ buttonTop = y + (height - tree->buttonSize) / 2;
+
+ /* Erase button background */
+ XFillRectangle(tree->display, 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, drawable, tree->buttonGC,
+ buttonLeft + w1,
+ buttonTop + w1,
+ tree->buttonSize - tree->buttonThickness,
+ tree->buttonSize - tree->buttonThickness);
+
+ /* Horizontal '-' */
+ XFillRectangle(tree->display, drawable, tree->buttonGC,
+ buttonLeft + tree->buttonThickness * 2,
+ lineTop,
+ tree->buttonSize - tree->buttonThickness * 4,
+ tree->buttonThickness);
+
+ if (!(self->state & STATE_OPEN))
+ {
+ /* Finish '+' */
+ XFillRectangle(tree->display, drawable, tree->buttonGC,
+ lineLeft,
+ buttonTop + tree->buttonThickness * 2,
+ tree->buttonThickness,
+ tree->buttonSize - tree->buttonThickness * 4);
+ }
+}
+
+int TreeItem_ReallyVisible(TreeCtrl *tree, TreeItem item_)
+{
+ Item *self = (Item *) item_;
+
+ if (!tree->updateIndex)
+ return self->indexVis != -1;
+
+ if (!self->isVisible)
+ return 0;
+ if (self->parent == NULL)
+ return ISROOT(self) ? tree->showRoot : 0;
+ if (ISROOT(self->parent))
+ {
+ if (!self->parent->isVisible)
+ return 0;
+ if (!tree->showRoot)
+ return 1;
+ if (!(self->parent->state & STATE_OPEN))
+ return 0;
+ }
+ if (!self->parent->isVisible || !(self->parent->state & STATE_OPEN))
+ return 0;
+ return TreeItem_ReallyVisible(tree, (TreeItem) self->parent);
+}
+
+TreeItem TreeItem_RootAncestor(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+
+ while (item->parent != NULL)
+ item = item->parent;
+ return (TreeItem) item;
+}
+
+int TreeItem_IsAncestor(TreeCtrl *tree, TreeItem item1, TreeItem item2)
+{
+ if (item1 == item2)
+ return 0;
+ while (item2 && item2 != item1)
+ item2 = (TreeItem) ((Item *) item2)->parent;
+ return item2 != NULL;
+}
+
+Tcl_Obj *TreeItem_ToObj(TreeCtrl *tree, TreeItem item_)
+{
+ return Tcl_NewIntObj(((Item *) item_)->id);
+}
+
+static int ItemElementCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ static CONST char *commandNames[] = { "actual", "cget", "configure", (char *) NULL };
+ enum { COMMAND_ACTUAL, COMMAND_CGET, COMMAND_CONFIGURE };
+ int index;
+ int columnIndex;
+ Column *column;
+ Item *item;
+
+ if (Tcl_GetIndexFromObj(interp, objv[3], commandNames, "command", 0,
+ &index) != TCL_OK)
+ return TCL_ERROR;
+
+ if (TreeItem_FromObj(tree, objv[4], (TreeItem *) &item, 0) != TCL_OK)
+ return TCL_ERROR;
+
+ if (Item_FindColumnFromObj(tree, item, objv[5], &column, &columnIndex) != TCL_OK)
+ return TCL_ERROR;
+
+ if (column->style == NULL)
+ {
+ FormatResult(interp, "item %d column %d has no style",
+ item->id, columnIndex);
+ return TCL_ERROR;
+ }
+
+ switch (index)
+ {
+ /* T item element actual I C E option */
+ case COMMAND_ACTUAL:
+ {
+ if (objc != 8)
+ {
+ Tcl_WrongNumArgs(tree->interp, 4, objv,
+ "item column element option");
+ return TCL_ERROR;
+ }
+ return TreeStyle_ElementActual(tree, column->style, item->state,
+ objv[6], objv[7]);
+ }
+
+ /* T item element cget I C E option */
+ case COMMAND_CGET:
+ {
+ if (objc != 8)
+ {
+ Tcl_WrongNumArgs(tree->interp, 4, objv,
+ "item column element option");
+ return TCL_ERROR;
+ }
+ return TreeStyle_ElementCget(tree, column->style, objv[6], objv[7]);
+ }
+
+ /* T item element configure I C E ... */
+ case COMMAND_CONFIGURE:
+ {
+ int result;
+ result = TreeStyle_ElementConfigure(tree, column->style, objv[6],
+ objc - 7, (Tcl_Obj **) objv + 7);
+ if (objc - 7 > 1)
+ {
+ column->neededWidth = column->neededHeight = -1;
+ Tree_InvalidateColumnWidth(tree, columnIndex);
+ TreeItem_InvalidateHeight(tree, (TreeItem) item);
+ Tree_FreeItemDInfo(tree, (TreeItem) item, NULL);
+ }
+ return result;
+ }
+ }
+
+ return TCL_OK;
+}
+
+static int ItemStyleCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ static CONST char *commandNames[] = { "elements", "map", "set", (char *) NULL };
+ enum { COMMAND_ELEMENTS, COMMAND_MAP, COMMAND_SET };
+ int index;
+ Item *item;
+
+ if (Tcl_GetIndexFromObj(interp, objv[3], commandNames, "command", 0,
+ &index) != TCL_OK)
+ {
+ return TCL_ERROR;
+ }
+
+ if (TreeItem_FromObj(tree, objv[4], (TreeItem *) &item, 0) != TCL_OK)
+ {
+ return TCL_ERROR;
+ }
+
+ switch (index)
+ {
+ /* T item style elements I C */
+ case COMMAND_ELEMENTS:
+ {
+ Column *column;
+ int columnIndex;
+
+ if (objc != 6)
+ {
+ Tcl_WrongNumArgs(interp, 4, objv, "item column");
+ return TCL_ERROR;
+ }
+ if (Item_FindColumnFromObj(tree, item, objv[5], &column, &columnIndex) != TCL_OK)
+ {
+ return TCL_ERROR;
+ }
+ if (column->style == NULL)
+ {
+ FormatResult(interp, "item %d column %d has no style",
+ item->id, columnIndex);
+ return TCL_ERROR;
+ }
+ TreeStyle_ListElements(tree, column->style);
+ break;
+ }
+
+ /* T item style map I C S map */
+ case COMMAND_MAP:
+ {
+ TreeStyle style;
+ Column *column;
+ int columnIndex;
+ int objcM;
+ Tcl_Obj **objvM;
+
+ if (objc != 8)
+ {
+ Tcl_WrongNumArgs(interp, 4, objv, "item column style map");
+ return TCL_ERROR;
+ }
+ if (Item_CreateColumnFromObj(tree, item, objv[5], &column, &columnIndex) != TCL_OK)
+ return TCL_ERROR;
+ if (TreeStyle_FromObj(tree, objv[6], &style) != TCL_OK)
+ return TCL_ERROR;
+ if (column->style != NULL)
+ {
+ if (Tcl_ListObjGetElements(interp, objv[7], &objcM, &objvM) != TCL_OK)
+ return TCL_ERROR;
+ if (objcM & 1)
+ {
+ FormatResult(interp, "list must contain even number of elements");
+ return TCL_ERROR;
+ }
+ if (TreeStyle_Remap(tree, column->style, style, objcM, objvM) != TCL_OK)
+ return TCL_ERROR;
+ }
+ else
+ column->style = TreeStyle_NewInstance(tree, style);
+ Tree_InvalidateColumnWidth(tree, columnIndex);
+ TreeItem_InvalidateHeight(tree, (TreeItem) item);
+ Tree_FreeItemDInfo(tree, (TreeItem) item, NULL);
+ break;
+ }
+
+ /* T item style set I ?C? ?S? ?C S ...?*/
+ case COMMAND_SET:
+ {
+ TreeStyle style;
+ Column *column;
+ int i, columnIndex, length;
+
+ if (objc < 5)
+ {
+ Tcl_WrongNumArgs(interp, 4, objv, "item ?column? ?style? ?column style ...?");
+ return TCL_ERROR;
+ }
+ if (objc == 5)
+ {
+ Tcl_Obj *listObj = Tcl_NewListObj(0, NULL);
+ column = item->columns;
+ while (column != NULL)
+ {
+ if (column->style != NULL)
+ Tcl_ListObjAppendElement(interp, listObj,
+ TreeStyle_ToObj(column->style));
+ else
+ Tcl_ListObjAppendElement(interp, listObj,
+ Tcl_NewObj());
+ column = column->next;
+ }
+ Tcl_SetObjResult(interp, listObj);
+ break;
+ }
+ if (objc == 6)
+ {
+ if (Item_FindColumnFromObj(tree, item, objv[5], &column, NULL) != TCL_OK)
+ return TCL_ERROR;
+ if (column->style != NULL)
+ Tcl_SetObjResult(interp, TreeStyle_ToObj(column->style));
+ break;
+ }
+ if ((objc - 5) & 1)
+ return TCL_ERROR;
+ for (i = 5; i < objc; i += 2)
+ {
+ if (Item_CreateColumnFromObj(tree, item, objv[i], &column, &columnIndex) != TCL_OK)
+ return TCL_ERROR;
+ (void) Tcl_GetStringFromObj(objv[i + 1], &length);
+ if (length == 0)
+ {
+ if (column->style == NULL)
+ continue;
+ TreeItemColumn_ForgetStyle(tree, (TreeItemColumn) column);
+ }
+ else
+ {
+ if (TreeStyle_FromObj(tree, objv[i + 1], &style) != TCL_OK)
+ return TCL_ERROR;
+ TreeItemColumn_ForgetStyle(tree, (TreeItemColumn) column);
+ column->style = TreeStyle_NewInstance(tree, style);
+ }
+ Tree_InvalidateColumnWidth(tree, columnIndex);
+ TreeItem_InvalidateHeight(tree, (TreeItem) item);
+ Tree_FreeItemDInfo(tree, (TreeItem) item, NULL);
+ }
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
+
+#if 0
+T item sort I
+ -first I (default firstchild)
+ -last I (default lastchild)
+ -command $cmd
+ -dictionary
+ -integer
+ -real
+ -increasing
+ -decreasing
+ -column C (default 0)
+ -element E (default first "text")
+#endif
+
+/* one per column per SortItem */
+struct SortItem1
+{
+ long longValue;
+ double doubleValue;
+ char *string;
+};
+
+/* one per Item */
+struct SortItem
+{
+ Item *item;
+ struct SortItem1 *item1;
+ Tcl_Obj *obj; /* TreeItem_ToObj() */
+};
+
+struct
+{
+ TreeCtrl *tree;
+ struct SortItem *items;
+ struct SortItem1 *item1s; /* SortItem.item1 points in here */
+ int (*proc[20])(struct SortItem *, struct SortItem *, int); /* one per column */
+ int sortBy[20]; /* one per column */
+ int column[20]; /* one per column */
+ int order[20]; /* one per column */
+ Tcl_Obj *command[20]; /* one per column */
+ int count; /* max number of columns to compare */
+ int result;
+} sortData;
+
+/* 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)) /* INTL: digit */
+ && 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(struct SortItem *a, struct SortItem *b, int n)
+{
+ return strcmp(a->item1[n].string, b->item1[n].string);
+}
+
+static int CompareDict(struct SortItem *a, struct SortItem *b, int n)
+{
+ return DictionaryCompare(a->item1[n].string, b->item1[n].string);
+}
+
+static int CompareDouble(struct SortItem *a, struct SortItem *b, int n)
+{
+ return (a->item1[n].doubleValue < b->item1[n].doubleValue) ? -1 :
+ ((a->item1[n].doubleValue == b->item1[n].doubleValue) ? 0 : 1);
+}
+
+static int CompareLong(struct SortItem *a, struct SortItem *b, int n)
+{
+ return (a->item1[n].longValue < b->item1[n].longValue) ? -1 :
+ ((a->item1[n].longValue == b->item1[n].longValue) ? 0 : 1);
+}
+
+static int CompareCmd(struct SortItem *a, struct SortItem *b, int n)
+{
+ 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.command[n], &objc);
+ Tcl_ListObjReplace(interp, sortData.command[n], objc - 2,
+ 2, 2, paramObjv);
+ Tcl_ListObjGetElements(interp, sortData.command[n],
+ &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(struct SortItem *a, struct SortItem *b)
+{
+ int i, v;
+
+ for (i = 0; i < sortData.count; i++)
+ {
+ v = (*sortData.proc[i])(a, b, i);
+
+ /* -command returned error */
+ if (sortData.result != TCL_OK)
+ return 0;
+
+ if (v != 0)
+ {
+ if (i && (sortData.order[i] != sortData.order[0]))
+ v *= -1;
+ return v;
+ }
+ }
+ return 0;
+}
+
+/* BEGIN custom quicksort() */
+
+static int find_pivot(struct SortItem *left, struct SortItem *right, struct SortItem *pivot)
+{
+ struct SortItem *a, *b, *c, *p;
+ int v;
+
+ a = left;
+ b = (left + (right - left) / 2);
+ c = right;
+
+ v = CompareProc(a, b);
+ if (sortData.result != TCL_OK)
+ return 0;
+ if (v < 0) { p = a; a = b; b = p; }
+
+ v = CompareProc(a, c);
+ if (sortData.result != TCL_OK)
+ return 0;
+ if (v < 0) { p = a; a = c; c = p; }
+
+ v = CompareProc(b, c);
+ if (sortData.result != TCL_OK)
+ return 0;
+ if (v < 0) { p = b; b = c; c = p; }
+
+ v = CompareProc(a, b);
+ if (sortData.result != TCL_OK)
+ return 0;
+ if (v < 0)
+ {
+ (*pivot) = *b;
+ return 1;
+ }
+
+ v = CompareProc(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(p, left);
+ if (sortData.result != TCL_OK)
+ return 0;
+ if (v != 0)
+ {
+ (*pivot) = (v < 0) ? *left : *p;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static struct SortItem *partition(struct SortItem *left, struct SortItem *right, struct SortItem *pivot)
+{
+ int v;
+
+ while (left <= right)
+ {
+ while (1)
+ {
+ v = CompareProc(left, pivot);
+ if (sortData.result != TCL_OK)
+ return NULL;
+ if (v >= 0)
+ break;
+ left++;
+ }
+ while (1)
+ {
+ v = CompareProc(right, pivot);
+ if (sortData.result != TCL_OK)
+ return NULL;
+ if (v < 0)
+ break;
+ right--;
+ }
+ if (left < right)
+ {
+ struct SortItem tmp = *left;
+ *left = *right;
+ *right = tmp;
+ left++;
+ right--;
+ }
+ }
+ return left;
+}
+
+static void quicksort(struct SortItem *left, struct SortItem *right)
+{
+ struct SortItem *p, pivot;
+
+ if (sortData.result != TCL_OK)
+ return;
+
+ if (find_pivot(left, right, &pivot) == 1)
+ {
+ p = partition(left, right, &pivot);
+ if (sortData.result != TCL_OK)
+ return;
+
+ quicksort(left, p - 1);
+ if (sortData.result != TCL_OK)
+ return;
+
+ quicksort(p, right);
+ }
+}
+
+/* END custom quicksort() */
+
+int ItemSortCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ Item *item, *first, *last, *walk, *lastChild;
+ Column *column;
+ int i, count, index, indexF = 0, indexL = 0;
+ int sawColumn = FALSE, sawCmd = FALSE;
+ static int (*sortProc[5])(struct SortItem *, struct SortItem *, int) =
+ { CompareAscii, CompareDict, CompareDouble, CompareLong, CompareCmd };
+ TreeColumn treeColumn;
+ int notReally = FALSE;
+ int result = TCL_OK;
+
+ if (TreeItem_FromObj(tree, objv[3], (TreeItem *) &item, 0) != TCL_OK)
+ return TCL_ERROR;
+
+ if (item->numChildren <= 1)
+ return TCL_OK;
+
+ /* Defaults: sort ascii strings in column 0 only */
+ sortData.tree = tree;
+ sortData.count = 1;
+ sortData.column[0] = 0;
+ sortData.sortBy[0] = SORT_ASCII;
+ sortData.order[0] = 1;
+ sortData.result = TCL_OK;
+
+ first = item->firstChild;
+ last = item->lastChild;
+
+ for (i = 4; i < objc; )
+ {
+ static CONST char *optionName[] = { "-ascii", "-column", "-command",
+ "-decreasing", "-dictionary", "-first", "-increasing", "-integer",
+ "-last", "-notreally", "-real", NULL };
+ int numArgs[] = { 1, 2, 2, 1, 1, 2, 1, 1, 2, 1, 1 };
+ enum { OPT_ASCII, OPT_COLUMN, OPT_COMMAND, OPT_DECREASING, OPT_DICT,
+ 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.sortBy[sortData.count - 1] = SORT_ASCII;
+ break;
+ case OPT_COLUMN:
+ if (TreeColumn_FromObj(tree, objv[i + 1], &treeColumn, 0) != TCL_OK)
+ return TCL_ERROR;
+ /* The first -column we see is the first column we compare */
+ if (sawColumn)
+ {
+ sortData.count++;
+ /* Defaults for this column */
+ sortData.sortBy[sortData.count - 1] = SORT_ASCII;
+ sortData.order[sortData.count - 1] = 1;
+ }
+ sortData.column[sortData.count - 1] = TreeColumn_Index(treeColumn);
+ sawColumn = TRUE;
+ break;
+ case OPT_COMMAND:
+ sortData.command[sortData.count - 1] = objv[i + 1];
+ sortData.sortBy[sortData.count - 1] = SORT_COMMAND;
+ sawCmd = TRUE;
+ break;
+ case OPT_DECREASING:
+ sortData.order[sortData.count - 1] = 0;
+ break;
+ case OPT_DICT:
+ sortData.sortBy[sortData.count - 1] = SORT_DICT;
+ break;
+ case OPT_FIRST:
+ if (TreeItem_FromObj(tree, objv[i + 1], (TreeItem *) &first, 0) != TCL_OK)
+ return TCL_ERROR;
+ if (first->parent != item)
+ {
+ FormatResult(interp, "item %d is not a child of item %d",
+ first->id, item->id);
+ return TCL_ERROR;
+ }
+ break;
+ case OPT_INCREASING:
+ sortData.order[sortData.count - 1] = 1;
+ break;
+ case OPT_INTEGER:
+ sortData.sortBy[sortData.count - 1] = SORT_LONG;
+ break;
+ case OPT_LAST:
+ if (TreeItem_FromObj(tree, objv[i + 1], (TreeItem *) &last, 0) != TCL_OK)
+ return TCL_ERROR;
+ if (last->parent != item)
+ {
+ FormatResult(interp, "item %d is not a child of item %d",
+ last->id, item->id);
+ return TCL_ERROR;
+ }
+ break;
+ case OPT_NOT_REALLY:
+ notReally = TRUE;
+ break;
+ case OPT_REAL:
+ sortData.sortBy[sortData.count - 1] = SORT_DOUBLE;
+ break;
+ }
+ i += numArgs[index];
+ }
+
+ if (first == last)
+ return TCL_OK;
+
+ for (i = 0; i < sortData.count; i++)
+ {
+ sortData.proc[i] = sortProc[sortData.sortBy[i]];
+
+ if (sortData.sortBy[i] == SORT_COMMAND)
+ {
+ Tcl_Obj *obj = Tcl_DuplicateObj(sortData.command[i]);
+ 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);
+ /* FIXME: free other .command[] */
+ return TCL_ERROR;
+ }
+ (void) Tcl_ListObjAppendElement(interp, obj, obj2);
+ sortData.command[i] = 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.count);
+ sortData.items = (struct SortItem *) ckalloc(sizeof(struct SortItem) * count);
+ for (i = 0; i < count; i++)
+ {
+ sortData.items[i].item1 = sortData.item1s + i * sortData.count;
+ sortData.items[i].obj = NULL;
+ }
+
+ index = 0;
+ walk = first;
+ while (walk != last->nextSibling)
+ {
+ struct SortItem *sortItem = &sortData.items[index];
+
+ sortItem->item = walk;
+ if (sawCmd)
+ {
+ Tcl_Obj *obj = TreeItem_ToObj(tree, (TreeItem) walk);
+ Tcl_IncrRefCount(obj);
+ sortData.items[index].obj = obj;
+ }
+ for (i = 0; i < sortData.count; i++)
+ {
+ struct SortItem1 *sortItem1 = sortItem->item1 + i;
+
+ if (sortData.sortBy[i] == SORT_COMMAND)
+ continue;
+
+ column = Item_FindColumn(tree, walk, sortData.column[i]);
+ if (column == NULL)
+ {
+ FormatResult(interp, "item %d doesn't have column %d",
+ walk->id, sortData.column[i]);
+ result = TCL_ERROR;
+ goto done;
+ }
+ if (column->style == NULL)
+ {
+ FormatResult(interp, "item %d column %d has no style",
+ walk->id, sortData.column[i]);
+ result = TCL_ERROR;
+ goto done;
+ }
+ if (TreeStyle_GetSortData(tree,
+ column->style, sortData.sortBy[i],
+ &sortItem1->longValue,
+ &sortItem1->doubleValue,
+ &sortItem1->string) != TCL_OK)
+ {
+ result = TCL_ERROR;
+ goto done;
+ }
+ }
+ index++;
+ walk = walk->nextSibling;
+ }
+
+ quicksort(sortData.items, sortData.items + count - 1);
+
+ if (sortData.result != TCL_OK)
+ {
+ result = TCL_ERROR;
+ goto done;
+ }
+
+ if (sawCmd)
+ Tcl_ResetResult(interp);
+
+ if (notReally)
+ {
+ Tcl_Obj *listObj = Tcl_NewListObj(0, NULL);
+ Tcl_Obj *itemObj;
+
+ /* Smallest to largest */
+ if (sortData.order[0] == 1)
+ {
+ for (i = 0; i < count; i++)
+ {
+ itemObj = sortData.items[i].obj;
+ if (itemObj == NULL)
+ itemObj = TreeItem_ToObj(tree,
+ (TreeItem) 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,
+ (TreeItem) 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.order[0] == 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)
+ {
+ if (lastChild->dInfo != NULL)
+ Tree_InvalidateItemDInfo(tree, (TreeItem) lastChild,
+ (TreeItem) NULL);
+ if (item->lastChild->dInfo != NULL)
+ Tree_InvalidateItemDInfo(tree, (TreeItem) item->lastChild,
+ (TreeItem) 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.count; i++)
+ if (sortData.sortBy[i] == SORT_COMMAND)
+ Tcl_DecrRefCount(sortData.command[i]);
+ ckfree((char *) sortData.item1s);
+ ckfree((char *) sortData.items);
+
+ if (tree->debug.enable && tree->debug.data)
+ Tree_Debug(tree);
+
+ return result;
+}
+
+int TreeItemCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ static CONST char *commandNames[] = {
+ "ancestors",
+ "children",
+ "create",
+ "delete",
+ "firstchild",
+ "lastchild",
+ "nextsibling",
+ "numchildren",
+ "parent",
+ "prevsibling",
+ "remove",
+
+ "bbox",
+ "complex",
+ "dump",
+ "element",
+ "hasbutton",
+ "index",
+ "isancestor",
+ "isopen",
+ "rnc",
+ "sort",
+ "state",
+ "style",
+ "text",
+ "visible",
+ (char *) NULL
+ };
+ enum {
+ COMMAND_ANCESTORS,
+ COMMAND_CHILDREN,
+ COMMAND_CREATE,
+ COMMAND_DELETE,
+ COMMAND_FIRSTCHILD,
+ COMMAND_LASTCHILD,
+ COMMAND_NEXTSIBLING,
+ COMMAND_NUMCHILDREN,
+ COMMAND_PARENT,
+ COMMAND_PREVSIBLING,
+ COMMAND_REMOVE,
+
+ COMMAND_BBOX,
+ COMMAND_COMPLEX,
+ COMMAND_DUMP,
+ COMMAND_ELEMENT,
+ COMMAND_HASBUTTON,
+ COMMAND_INDEX,
+ COMMAND_ISANCESTOR,
+ COMMAND_ISOPEN,
+ COMMAND_RNC,
+ COMMAND_SORT,
+ COMMAND_STATE,
+ COMMAND_STYLE,
+ COMMAND_TEXT,
+ COMMAND_VISIBLE
+ };
+#define AF_NOTANCESTOR 0x00010000 /* item can't be ancestor of other item */
+#define AF_PARENT 0x00020000 /* item must have a parent */
+#define AF_EQUALOK 0x00040000 /* second item can be same as first */
+#define AF_SAMEROOT 0x00080000 /* both items must be descendants of a common ancestor */
+ struct {
+ int minArgs;
+ int maxArgs;
+ int flags;
+ int flags2;
+ char *argString;
+ } argInfo[] = {
+ { 1, 1, 0, 0, "item" }, /* ancestors */
+ { 1, 1, 0, 0, "item" }, /* children */
+ { 0, 0, 0, 0, NULL }, /* create */
+ { 1, 2, IFO_ALLOK | IFO_NOTROOT, IFO_ALLOK | IFO_NOTROOT | AF_EQUALOK | AF_SAMEROOT, "first ?last?" }, /* delete */
+ { 1, 2, 0, IFO_NOTROOT | AF_NOTANCESTOR, "item ?newFirstChild?" }, /* firstchild */
+ { 1, 2, 0, IFO_NOTROOT | AF_NOTANCESTOR, "item ?newLastChild?" }, /* lastchild */
+ { 1, 2, IFO_NOTROOT | AF_PARENT, IFO_NOTROOT | AF_NOTANCESTOR, "item ?newNextSibling?" }, /* nextsibling */
+ { 1, 1, 0, 0, "item" }, /* numchildren */
+ { 1, 1, 0, 0, "item" }, /* parent */
+ { 1, 2, IFO_NOTROOT | AF_PARENT, IFO_NOTROOT | AF_NOTANCESTOR, "item ?newPrevSibling?" }, /* prevsibling */
+ { 1, 1, IFO_NOTROOT, 0, "item" }, /* remove */
+
+ { 1, 3, 0, 0, "item ?column? ?element?" }, /* bbox */
+ { 2, 100000, 0, 0, "item list..." }, /* complex */
+ { 1, 1, 0, 0, "item" }, /* dump */
+ { 4, 100000, 0, 0, "command item column element ?arg ...?" }, /* element */
+ { 1, 2, 0, 0, "item ?boolean?" }, /* hasbutton */
+ { 1, 1, 0, 0, "item" }, /* index */
+ { 2, 2, 0, AF_EQUALOK, "item item2" }, /* isancestor */
+ { 1, 1, 0, 0, "item" }, /* isopen */
+ { 1, 1, 0, 0, "item" }, /* rnc */
+ { 1, 100000, 0, 0, "item ?option ...?" }, /* sort */
+ { 1, 100000, 0, 0, "item ?state ...?" }, /* state */
+ { 2, 100000, 0, 0, "command item ?arg ...?" }, /* style */
+ { 2, 100000, 0, 0, "item column ?text? ?column text ...?" }, /* text */
+ { 1, 2, 0, 0, "item ?boolean?" }, /* visible */
+ };
+ int index;
+ int numArgs = objc - 3;
+ Item *item, *item2 = NULL, *child;
+
+ 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;
+ }
+
+ if ((numArgs < argInfo[index].minArgs) ||
+ (numArgs > argInfo[index].maxArgs))
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, argInfo[index].argString);
+ return TCL_ERROR;
+ }
+
+ switch (index)
+ {
+ case COMMAND_ELEMENT:
+ {
+ return ItemElementCmd(clientData, interp, objc, objv);
+ }
+ case COMMAND_SORT:
+ {
+ return ItemSortCmd(clientData, interp, objc, objv);
+ }
+ case COMMAND_STYLE:
+ {
+ return ItemStyleCmd(clientData, interp, objc, objv);
+ }
+ }
+
+ if (numArgs >= 1)
+ {
+ if (TreeItem_FromObj(tree, objv[3], (TreeItem *) &item,
+ argInfo[index].flags & 0xFFFF) != TCL_OK)
+ {
+ return TCL_ERROR;
+ }
+
+ switch (index)
+ {
+ /* T item bbox I ?C? ?E? */
+ case COMMAND_BBOX:
+ {
+ int x, y, w, h;
+ int i, columnIndex, indent, totalWidth;
+ TreeColumn treeColumn;
+ TreeItemColumn itemColumn;
+ StyleDrawArgs drawArgs;
+ TreeItem item_ = (TreeItem) item;
+ XRectangle rect;
+
+ if (!TreeItem_ReallyVisible(tree, item_))
+ return TCL_OK;
+ Tree_ItemBbox(tree, item_, &x, &y, &w, &h);
+ if (objc > 4)
+ {
+ if (TreeItem_ColumnFromObj(tree, item_, objv[4],
+ &itemColumn, &columnIndex) != TCL_OK)
+ return TCL_ERROR;
+ totalWidth = 0;
+ treeColumn = tree->columns;
+ for (i = 0; i < columnIndex; i++)
+ {
+ totalWidth += TreeColumn_UseWidth(treeColumn);
+ treeColumn = TreeColumn_Next(treeColumn);
+ }
+ if (columnIndex == tree->columnTree)
+ indent = TreeItem_Indent(tree, item_);
+ else
+ indent = 0;
+ if (objc == 5)
+ {
+ FormatResult(interp, "%d %d %d %d",
+ x + totalWidth + indent - tree->xOrigin,
+ y - tree->yOrigin,
+ x + totalWidth + TreeColumn_UseWidth(treeColumn) - tree->xOrigin,
+ y + h - tree->yOrigin);
+ return TCL_OK;
+ }
+ drawArgs.style = TreeItemColumn_GetStyle(tree, itemColumn);
+ if (drawArgs.style == NULL)
+ {
+ FormatResult(interp, "item %d column %d has no style",
+ TreeItem_GetID(tree, item_), columnIndex);
+ return TCL_ERROR;
+ }
+ drawArgs.tree = tree;
+ drawArgs.drawable = None;
+ drawArgs.state = TreeItem_GetState(tree, item_);
+ drawArgs.x = x + indent + totalWidth;
+ drawArgs.y = y;
+ drawArgs.width = TreeColumn_UseWidth(treeColumn) - indent;
+ drawArgs.height = h;
+ drawArgs.justify = TreeColumn_Justify(treeColumn);
+ if (TreeStyle_GetElemRects(&drawArgs, objc - 5, objv + 5,
+ &rect) == -1)
+ return TCL_ERROR;
+ x = rect.x;
+ y = rect.y;
+ w = rect.width;
+ h = rect.height;
+ }
+ FormatResult(interp, "%d %d %d %d",
+ x - tree->xOrigin,
+ y - tree->yOrigin,
+ x - tree->xOrigin + w,
+ y - tree->yOrigin + h);
+ return TCL_OK;
+ }
+ case COMMAND_COMPLEX:
+ {
+ int i, j, columnIndex;
+ int objc1, objc2;
+ Tcl_Obj **objv1, **objv2;
+ Column *column;
+
+ if (objc > 4)
+ {
+ columnIndex = 0;
+ for (i = 4; i < objc; i++, columnIndex++)
+ {
+ column = Item_FindColumn(tree, item, columnIndex);
+ if (column == NULL)
+ {
+ FormatResult(interp, "item %d doesn't have column %d",
+ item->id, columnIndex);
+ return TCL_ERROR;
+ }
+ /* List of element-configs per column */
+ if (Tcl_ListObjGetElements(interp, objv[i],
+ &objc1, &objv1) != TCL_OK)
+ return TCL_ERROR;
+ if (objc1 == 0)
+ continue;
+ if (column->style == NULL)
+ {
+ FormatResult(interp, "item %d column %d has no style",
+ item->id, columnIndex);
+ return TCL_ERROR;
+ }
+ for (j = 0; j < objc1; j++)
+ {
+ /* elem option value... */
+ if (Tcl_ListObjGetElements(interp, objv1[j],
+ &objc2, &objv2) != TCL_OK)
+ return TCL_ERROR;
+ if (objc2 < 3)
+ {
+ FormatResult(interp,
+ "wrong # args: should be \"element option value...\"");
+ return TCL_ERROR;
+ }
+ if (TreeStyle_ElementConfigure(tree, column->style,
+ objv2[0], objc2 - 1, objv2 + 1) != TCL_OK)
+ return TCL_ERROR;
+ }
+ column->neededWidth = column->neededHeight = -1;
+ }
+ Tree_InvalidateColumnWidth(tree, -1);
+ TreeItem_InvalidateHeight(tree, (TreeItem) item);
+ Tree_FreeItemDInfo(tree, (TreeItem) item, NULL);
+ }
+ return TCL_OK;
+ }
+ case COMMAND_DUMP:
+ {
+ if (tree->updateIndex)
+ Tree_UpdateItemIndex(tree);
+ FormatResult(interp, "index %d indexVis %d neededHeight %d",
+ item->index, item->indexVis, item->neededHeight);
+ return TCL_OK;
+ }
+ case COMMAND_HASBUTTON:
+ {
+ int hasButton;
+
+ if (objc == 5)
+ {
+ if (Tcl_GetBooleanFromObj(interp, objv[4], &hasButton) != TCL_OK)
+ return TCL_ERROR;
+ if (hasButton != item->hasButton)
+ {
+ item->hasButton = hasButton;
+ Tree_InvalidateItemDInfo(tree, (TreeItem) item, NULL);
+ }
+ }
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(item->hasButton));
+ return TCL_OK;
+ }
+ /* T item state I ?state ...? */
+ case COMMAND_STATE:
+ {
+ int i, j, negate, stateOn = 0, stateOff = 0;
+ char *string;
+
+ if (objc == 4)
+ {
+ Tcl_Obj *listObj = Tcl_NewListObj(0, NULL);
+ for (i = 0; i < 32; i++)
+ {
+ if (tree->stateNames[i] == NULL)
+ continue;
+ if (item->state & (1L << i))
+ {
+ Tcl_ListObjAppendElement(interp, listObj,
+ Tcl_NewStringObj(tree->stateNames[i], -1));
+ }
+ }
+ Tcl_SetObjResult(interp, listObj);
+ return TCL_OK;
+ }
+ for (i = 4; i < objc; i++)
+ {
+ negate = 0;
+ string = Tcl_GetString(objv[i]);
+ if (string[0] == '!')
+ negate = 1;
+ for (j = STATE_USER - 1; j < 32; j++)
+ {
+ if (tree->stateNames[j] == NULL)
+ continue;
+ if (strcmp(tree->stateNames[j], string + negate) == 0)
+ break;
+ }
+ if (j == 32)
+ {
+ FormatResult(interp, "cannot change state \"%s\"", string);
+ return TCL_ERROR;
+ }
+ if (negate)
+ stateOff |= 1L << j;
+ else
+ stateOn |= 1L << j;
+ }
+ TreeItem_ChangeState(tree, (TreeItem) item, stateOff, stateOn);
+ return TCL_OK;
+ }
+ case COMMAND_VISIBLE:
+ {
+ int visible;
+
+ if (objc == 5)
+ {
+ if (Tcl_GetBooleanFromObj(interp, objv[4], &visible) != TCL_OK)
+ return TCL_ERROR;
+ if (visible != item->isVisible)
+ {
+ item->isVisible = visible;
+
+ /* May change the width of any column */
+ Tree_InvalidateColumnWidth(tree, -1);
+
+ /* 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)
+ {
+ Item *last = item->prevSibling;
+ while (last->lastChild != NULL)
+ last = last->lastChild;
+ Tree_InvalidateItemDInfo(tree,
+ (TreeItem) item->prevSibling,
+ (TreeItem) last);
+ }
+
+ tree->updateIndex = 1;
+ Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
+ }
+ }
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(item->isVisible));
+ return TCL_OK;
+ }
+ case COMMAND_ISOPEN:
+ {
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(item->state & STATE_OPEN));
+ return TCL_OK;
+ }
+ case COMMAND_INDEX:
+ {
+ FormatResult(interp, "%d %d", item->index, item->indexVis);
+ return TCL_OK;
+ }
+ case COMMAND_RNC:
+ {
+ int row,col;
+
+ if (Tree_ItemToRNC(tree, (TreeItem) item, &row, &col) == TCL_OK)
+ FormatResult(interp, "%d %d", row, col);
+ return TCL_OK;
+ }
+
+ /* T item text I C ?text? ?C text ...? */
+ case COMMAND_TEXT:
+ {
+ Column *column;
+ Tcl_Obj *textObj;
+ int i, columnIndex;
+
+ if (objc == 5)
+ {
+ if (Item_FindColumnFromObj(tree, item, objv[4], &column, NULL) != TCL_OK)
+ {
+ return TCL_ERROR;
+ }
+ if (column->style != NULL)
+ {
+ textObj = TreeStyle_GetText(tree, column->style);
+ if (textObj != NULL)
+ Tcl_SetObjResult(interp, textObj);
+ }
+ return TCL_OK;
+ }
+ if ((objc - 4) & 1)
+ {
+ FormatResult(interp, "wrong # args: should be \"column text column text...\"");
+ return TCL_ERROR;
+ }
+ TreeItem_InvalidateHeight(tree, (TreeItem) item);
+ Tree_InvalidateItemDInfo(tree, (TreeItem) item, NULL);
+ Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
+ for (i = 4; i < objc; i += 2)
+ {
+ if (Item_CreateColumnFromObj(tree, item, objv[i], &column, &columnIndex) != TCL_OK)
+ return TCL_ERROR;
+ if (column->style == NULL)
+ {
+ FormatResult(interp, "item %d column %d has no style",
+ item->id, columnIndex);
+ return TCL_ERROR;
+ }
+ TreeStyle_SetText(tree, column->style, objv[i + 1]);
+ column->neededWidth = column->neededHeight = -1;
+ Tree_InvalidateColumnWidth(tree, columnIndex);
+ }
+ return TCL_OK;
+ }
+ }
+
+ if ((argInfo[index].flags & AF_PARENT) && (item->parent == NULL))
+ {
+ FormatResult(interp, "item %d must have a parent", item->id);
+ return TCL_ERROR;
+ }
+ }
+ if (numArgs >= 2)
+ {
+ if (TreeItem_FromObj(tree, objv[4], (TreeItem *) &item2,
+ argInfo[index].flags2 & 0xFFFF) != TCL_OK)
+ {
+ return TCL_ERROR;
+ }
+ if (!(argInfo[index].flags2 & AF_EQUALOK) && (item == item2))
+ {
+ FormatResult(interp, "item %d same as second item", item->id);
+ return TCL_ERROR;
+ }
+ if ((argInfo[index].flags2 & AF_PARENT) && (item2->parent == NULL))
+ {
+ FormatResult(interp, "item %d must have a parent", item2->id);
+ return TCL_ERROR;
+ }
+ if ((argInfo[index].flags & AF_NOTANCESTOR) &&
+ TreeItem_IsAncestor(tree, (TreeItem) item, (TreeItem) item2))
+ {
+ FormatResult(interp, "item %d is ancestor of item %d",
+ item->id, item2->id);
+ return TCL_ERROR;
+ }
+ if ((argInfo[index].flags2 & AF_NOTANCESTOR) &&
+ TreeItem_IsAncestor(tree, (TreeItem) item2, (TreeItem) item))
+ {
+ FormatResult(interp, "item %d is ancestor of item %d",
+ item2->id, item->id);
+ return TCL_ERROR;
+ }
+ if ((argInfo[index].flags2 & AF_SAMEROOT) &&
+ TreeItem_RootAncestor(tree, (TreeItem) item) !=
+ TreeItem_RootAncestor(tree, (TreeItem) item2))
+ {
+ FormatResult(interp,
+ "item %d and item %d don't share a common ancestor",
+ item->id, item2->id);
+ return TCL_ERROR;
+ }
+ }
+
+ switch (index)
+ {
+ case COMMAND_ANCESTORS:
+ {
+ Tcl_Obj *listObj;
+ Item *parent = item->parent;
+
+ listObj = Tcl_NewListObj(0, NULL);
+ while (parent != NULL)
+ {
+ Tcl_ListObjAppendElement(interp, listObj,
+ TreeItem_ToObj(tree, (TreeItem) parent));
+ parent = parent->parent;
+ }
+ Tcl_SetObjResult(interp, listObj);
+ 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, (TreeItem) child));
+ child = child->nextSibling;
+ }
+ Tcl_SetObjResult(interp, listObj);
+ }
+ break;
+ }
+ case COMMAND_CREATE:
+ {
+ item = (Item *) TreeItem_Alloc(tree);
+ Tcl_SetObjResult(interp, TreeItem_ToObj(tree, (TreeItem) item));
+ break;
+ }
+ case COMMAND_DELETE:
+ {
+ int index1, index2;
+
+ if (item == (Item *) ITEM_ALL || item2 == (Item *) ITEM_ALL)
+ {
+ /* Do it this way so any detached items are deleted */
+ while (1)
+ {
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ item = (Item *) Tcl_GetHashValue(hPtr);
+ if (item == (Item *) tree->root)
+ hPtr = Tcl_NextHashEntry(&search);
+ if (hPtr == NULL)
+ break;
+ item = (Item *) Tcl_GetHashValue(hPtr);
+ TreeItem_Delete(tree, (TreeItem) item);
+ }
+ }
+ else if (item2 != NULL)
+ {
+ TreeItem_ToIndex(tree, (TreeItem) item, &index1, NULL);
+ TreeItem_ToIndex(tree, (TreeItem) item2, &index2, NULL);
+ if (index1 > index2)
+ {
+ Item *swap = item;
+ item = item2;
+ item2 = swap;
+ }
+ while (1)
+ {
+ Item *prev = (Item *) TreeItem_Prev(tree, (TreeItem) item2);
+ TreeItem_Delete(tree, (TreeItem) item2);
+ if (item2 == item)
+ break;
+ item2 = prev;
+ }
+ }
+ else
+ {
+ TreeItem_Delete(tree, (TreeItem) item);
+ }
+ break;
+ }
+ case COMMAND_FIRSTCHILD:
+ {
+ if (item2 != NULL && item2 != item->firstChild)
+ {
+ TreeItem_RemoveFromParent(tree, (TreeItem) 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, (TreeItem) item2);
+ }
+ if (item->firstChild != NULL)
+ Tcl_SetObjResult(interp, TreeItem_ToObj(tree, (TreeItem) item->firstChild));
+ break;
+ }
+ case COMMAND_ISANCESTOR:
+ {
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
+ TreeItem_IsAncestor(tree, (TreeItem) item, (TreeItem) item2)));
+ break;
+ }
+ case COMMAND_LASTCHILD:
+ {
+ if (item2 != NULL && item2 != item->lastChild)
+ {
+ TreeItem_RemoveFromParent(tree, (TreeItem) 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, (TreeItem) item2);
+ }
+ if (item->lastChild != NULL)
+ Tcl_SetObjResult(interp, TreeItem_ToObj(tree, (TreeItem) item->lastChild));
+ break;
+ }
+ case COMMAND_NEXTSIBLING:
+ {
+ if (item2 != NULL && item2 != item->nextSibling)
+ {
+ TreeItem_RemoveFromParent(tree, (TreeItem) 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, (TreeItem) item2);
+ }
+ if (item->nextSibling != NULL)
+ Tcl_SetObjResult(interp, TreeItem_ToObj(tree, (TreeItem) item->nextSibling));
+ break;
+ }
+ case COMMAND_NUMCHILDREN:
+ {
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(item->numChildren));
+ break;
+ }
+ case COMMAND_PARENT:
+ {
+ if (item->parent != NULL)
+ Tcl_SetObjResult(interp, TreeItem_ToObj(tree, (TreeItem) item->parent));
+ break;
+ }
+ case COMMAND_PREVSIBLING:
+ {
+ if (item2 != NULL && item2 != item->prevSibling)
+ {
+ TreeItem_RemoveFromParent(tree, (TreeItem) 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, (TreeItem) item2);
+ }
+ if (item->prevSibling != NULL)
+ Tcl_SetObjResult(interp, TreeItem_ToObj(tree, (TreeItem) item->prevSibling));
+ break;
+ }
+ case COMMAND_REMOVE:
+ {
+ if (item->parent == NULL)
+ break;
+ TreeItem_RemoveFromParent(tree, (TreeItem) item);
+ if (tree->debug.enable && tree->debug.data)
+ Tree_Debug(tree);
+ Tree_InvalidateColumnWidth(tree, -1);
+ Tree_FreeItemDInfo(tree, (TreeItem) item, NULL);
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
+
+int TreeItem_Debug(TreeCtrl *tree, TreeItem item_)
+{
+ Item *item = (Item *) item_;
+ Item *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, (TreeItem) child) != TCL_OK)
+ return TCL_ERROR;
+ child = child->nextSibling;
+ }
+ }
+ return TCL_OK;
+}
+
+char *TreeItem_Identify(TreeCtrl *tree, TreeItem item_, int x, int y)
+{
+ Item *self = (Item *) item_;
+ int left, top, width, height;
+ int indent, columnWidth, totalWidth;
+ Column *column;
+ StyleDrawArgs drawArgs;
+ TreeColumn treeColumn;
+
+ if (!TreeItem_ReallyVisible(tree, item_))
+ return NULL;
+
+ Tree_ItemBbox(tree, item_, &left, &top, &width, &height);
+#if 0
+ if (y >= Tk_Height(tree->tkwin) || y + height <= 0)
+ return NULL;
+#endif
+ drawArgs.tree = tree;
+ drawArgs.drawable = None;
+ drawArgs.state = self->state;
+
+ totalWidth = 0;
+ treeColumn = tree->columns;
+ column = self->columns;
+ while (column != NULL)
+ {
+ if (!TreeColumn_Visible(treeColumn))
+ columnWidth = 0;
+ else if (tree->columnCountVis == 1)
+ columnWidth = width;
+ else
+ columnWidth = TreeColumn_UseWidth(treeColumn);
+ if (columnWidth > 0)
+ {
+ if (TreeColumn_Index(treeColumn) == tree->columnTree)
+ indent = TreeItem_Indent(tree, item_);
+ else
+ indent = 0;
+ if ((x >= totalWidth + indent) && (x < totalWidth + columnWidth))
+ {
+ if (column->style != NULL)
+ {
+ drawArgs.style = column->style;
+ drawArgs.x = indent + totalWidth;
+ drawArgs.y = 0;
+ drawArgs.width = columnWidth - indent;
+ drawArgs.height = height;
+ drawArgs.justify = TreeColumn_Justify(treeColumn);
+ return TreeStyle_Identify(&drawArgs, x, y);
+ }
+ return NULL;
+ }
+ totalWidth += columnWidth;
+ }
+ treeColumn = TreeColumn_Next(treeColumn);
+ column = column->next;
+ }
+ return NULL;
+}
+
+void TreeItem_Identify2(TreeCtrl *tree, TreeItem item_,
+ int x1, int y1, int x2, int y2, Tcl_Obj *listObj)
+{
+ Item *self = (Item *) item_;
+ int indent, columnWidth, totalWidth;
+ int x, y, w, h;
+ Column *column;
+ StyleDrawArgs drawArgs;
+ TreeColumn treeColumn;
+
+ if (!TreeItem_ReallyVisible(tree, item_))
+ return;
+
+ Tree_ItemBbox(tree, item_, &x, &y, &w, &h);
+
+ drawArgs.tree = tree;
+ drawArgs.drawable = None;
+ drawArgs.state = self->state;
+
+ totalWidth = 0;
+ treeColumn = tree->columns;
+ column = self->columns;
+ while (column != NULL)
+ {
+ if (!TreeColumn_Visible(treeColumn))
+ columnWidth = 0;
+ else if (tree->columnCountVis == 1)
+ columnWidth = w;
+ else
+ columnWidth = TreeColumn_UseWidth(treeColumn);
+ if (columnWidth > 0)
+ {
+ if (TreeColumn_Index(treeColumn) == tree->columnTree)
+ indent = TreeItem_Indent(tree, item_);
+ else
+ indent = 0;
+ if ((x2 >= x + totalWidth + indent) && (x1 < x + totalWidth + columnWidth))
+ {
+ Tcl_Obj *subListObj = Tcl_NewListObj(0, NULL);
+ Tcl_ListObjAppendElement(tree->interp, subListObj,
+ Tcl_NewIntObj(TreeColumn_Index(treeColumn)));
+ if (column->style != NULL)
+ {
+ drawArgs.style = column->style;
+ drawArgs.x = x + totalWidth + indent;
+ drawArgs.y = y;
+ drawArgs.width = columnWidth - indent;
+ drawArgs.height = h;
+ drawArgs.justify = TreeColumn_Justify(treeColumn);
+ TreeStyle_Identify2(&drawArgs, x1, y1, x2, y2, subListObj);
+ }
+ Tcl_ListObjAppendElement(tree->interp, listObj, subListObj);
+ }
+ totalWidth += columnWidth;
+ }
+ treeColumn = TreeColumn_Next(treeColumn);
+ column = column->next;
+ }
+}
+
diff --git a/generic/tkTreeMarquee.c b/generic/tkTreeMarquee.c
new file mode 100644
index 0000000..2e2b7ad
--- /dev/null
+++ b/generic/tkTreeMarquee.c
@@ -0,0 +1,364 @@
+#include "tkTreeCtrl.h"
+
+typedef struct Marquee Marquee;
+
+struct Marquee
+{
+ TreeCtrl *tree;
+ int visible;
+ int x1, y1, x2, y2;
+ int onScreen;
+ int sx, sy;
+};
+
+static Tk_OptionSpec optionSpecs[] = {
+ {TK_OPTION_BOOLEAN, "-visible", (char *) NULL, (char *) NULL,
+ "0", -1, Tk_Offset(Marquee, visible),
+ 0, (ClientData) NULL, 0},
+ {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, 0, 0}
+};
+
+static Tk_OptionTable optionTable = NULL;
+
+int TreeMarquee_Init(TreeCtrl *tree)
+{
+ Marquee *marquee;
+
+ if (optionTable == NULL)
+ optionTable = Tk_CreateOptionTable(tree->interp, optionSpecs);
+
+ marquee = (Marquee *) ckalloc(sizeof(Marquee));
+ memset(marquee, '\0', sizeof(Marquee));
+ marquee->tree = tree;
+ if (Tk_InitOptions(tree->interp, (char *) marquee, optionTable,
+ tree->tkwin) != TCL_OK)
+ {
+ WFREE(marquee, Marquee);
+ return TCL_ERROR;
+ }
+ tree->marquee = (TreeMarquee) marquee;
+ return TCL_OK;
+}
+
+void TreeMarquee_Free(TreeMarquee marquee_)
+{
+ Marquee *marquee = (Marquee *) marquee_;
+
+ Tk_FreeConfigOptions((char *) marquee, optionTable,
+ marquee->tree->tkwin);
+ WFREE(marquee, Marquee);
+}
+
+void TreeMarquee_Display(TreeMarquee marquee_)
+{
+ Marquee *marquee = (Marquee *) marquee_;
+ TreeCtrl *tree = marquee->tree;
+
+ if (!marquee->onScreen && marquee->visible)
+ {
+ marquee->sx = 0 - tree->xOrigin;
+ marquee->sy = 0 - tree->yOrigin;
+ TreeMarquee_Draw(marquee_, Tk_WindowId(tree->tkwin), marquee->sx, marquee->sy);
+ marquee->onScreen = TRUE;
+ }
+}
+
+void TreeMarquee_Undisplay(TreeMarquee marquee_)
+{
+ Marquee *marquee = (Marquee *) marquee_;
+ TreeCtrl *tree = marquee->tree;
+
+ if (marquee->onScreen)
+ {
+ TreeMarquee_Draw(marquee_, Tk_WindowId(tree->tkwin), marquee->sx, marquee->sy);
+ marquee->onScreen = FALSE;
+ }
+}
+
+void TreeMarquee_Draw(TreeMarquee marquee_, Drawable drawable, int x1, int y1)
+{
+ Marquee *marquee = (Marquee *) marquee_;
+ TreeCtrl *tree = marquee->tree;
+ int x, y, w, h;
+ DotState dotState;
+
+/* 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;
+
+ DotRect_Setup(tree, drawable, &dotState);
+ DotRect_Draw(&dotState, x1 + x, y1 + y, w, h);
+ DotRect_Restore(&dotState);
+}
+
+static int Marquee_Config(Marquee *marquee, int objc, Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = marquee->tree;
+ Tk_SavedOptions savedOptions;
+ int mask, result;
+
+ result = Tk_SetOptions(tree->interp, (char *) marquee, optionTable,
+ objc, objv, tree->tkwin, &savedOptions, &mask);
+ if (result != TCL_OK)
+ {
+ Tk_RestoreSavedOptions(&savedOptions);
+ return TCL_ERROR;
+ }
+ Tk_FreeSavedOptions(&savedOptions);
+
+/* Marquee_Redraw(marquee); */
+
+ return TCL_OK;
+}
+
+int TreeMarqueeCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ Marquee *marquee = (Marquee *) tree->marquee;
+ static CONST char *commandNames[] = { "anchor", "cget", "configure",
+ "coords", "corner", "identify", "visible", (char *) NULL };
+ enum { COMMAND_ANCHOR, COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_COORDS,
+ COMMAND_CORNER, COMMAND_IDENTIFY, COMMAND_VISIBLE };
+ 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,
+ 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,
+ 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_TotalWidth(tree);
+ int totalHeight = Tree_TotalHeight(tree);
+ TreeItem *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;
+
+ items = Tree_ItemsInArea(tree, x1, y1, x2, y2);
+ if (items == NULL)
+ break;
+
+ listObj = Tcl_NewListObj(0, NULL);
+ while (items[n] != NULL)
+ {
+ Tcl_Obj *subListObj = Tcl_NewListObj(0, NULL);
+ Tcl_ListObjAppendElement(interp, subListObj,
+ TreeItem_ToObj(tree, items[n]));
+ TreeItem_Identify2(tree, items[n], x1, y1, x2, y2, subListObj);
+ Tcl_ListObjAppendElement(interp, listObj, subListObj);
+ n++;
+ }
+ ckfree((char *) items);
+ Tcl_SetObjResult(interp, listObj);
+ break;
+ }
+
+ /* T marquee visible ?boolean? */
+ case COMMAND_VISIBLE:
+ {
+ int visible;
+
+ if (objc != 3 && objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "?boolean?");
+ return TCL_ERROR;
+ }
+ if (objc == 4)
+ {
+ if (Tcl_GetBooleanFromObj(interp, objv[3], &visible) != TCL_OK)
+ return TCL_ERROR;
+ if (visible != marquee->visible)
+ {
+ marquee->visible = visible;
+ TreeMarquee_Undisplay(tree->marquee);
+ TreeMarquee_Display(tree->marquee);
+ }
+ }
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(marquee->visible));
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
diff --git a/generic/tkTreeNotify.c b/generic/tkTreeNotify.c
new file mode 100644
index 0000000..aeb1990
--- /dev/null
+++ b/generic/tkTreeNotify.c
@@ -0,0 +1,389 @@
+#include "tkTreeCtrl.h"
+
+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;
+
+/*
+ * %-substitution for any event
+ */
+static void Percents_Any(QE_ExpandArgs *args)
+{
+ struct {
+ TreeCtrl *tree;
+ } *data = args->clientData;
+
+ 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 'W': /* object */
+ QE_ExpandString((char *) args->object, args->result);
+ break;
+
+ case 'T': /* tree */
+ QE_ExpandString(Tk_PathName(data->tree->tkwin), args->result);
+ break;
+
+ default:
+ QE_ExpandUnknown(args->which, args->result);
+ break;
+ }
+}
+
+static void Percents_Expand(QE_ExpandArgs *args)
+{
+ struct {
+ TreeCtrl *tree;
+ int id;
+ } *data = args->clientData;
+
+ switch (args->which)
+ {
+ case 'I':
+ QE_ExpandNumber(data->id, args->result);
+ break;
+
+ default:
+ Percents_Any(args);
+ break;
+ }
+}
+
+static void Percents_Selection(QE_ExpandArgs *args)
+{
+ struct {
+ TreeCtrl *tree;
+ int *select;
+ int *deselect;
+ int count;
+ } *data = args->clientData;
+ int *items = NULL;
+ int i = 0;
+ char string[TCL_INTEGER_SPACE];
+
+ switch (args->which)
+ {
+ case 'c':
+ QE_ExpandNumber(data->count, args->result);
+ break;
+ case 'D':
+ case 'S':
+ items = (args->which == 'D') ? data->deselect : data->select;
+ if (items == NULL)
+ {
+ Tcl_DStringAppend(args->result, "{}", 2);
+ break;
+ }
+ Tcl_DStringStartSublist(args->result);
+ while (items[i] != -1)
+ {
+ TclFormatInt(string, items[i]);
+ Tcl_DStringAppendElement(args->result, string);
+ i++;
+ }
+ Tcl_DStringEndSublist(args->result);
+ break;
+
+ default:
+ Percents_Any(args);
+ break;
+ }
+}
+
+static void Percents_ActiveItem(QE_ExpandArgs *args)
+{
+ struct {
+ TreeCtrl *tree;
+ int prev;
+ int current;
+ } *data = args->clientData;
+
+ switch (args->which)
+ {
+ case 'c':
+ QE_ExpandNumber(data->current, args->result);
+ break;
+
+ case 'p':
+ QE_ExpandNumber(data->prev, args->result);
+ break;
+
+ default:
+ Percents_Any(args);
+ break;
+ }
+}
+
+static void Percents_Scroll(QE_ExpandArgs *args)
+{
+ struct {
+ TreeCtrl *tree;
+ 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);
+ break;
+ }
+}
+
+int TreeNotifyCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ static CONST char *commandName[] = { "bind", "configure", "detailnames",
+ "eventnames", "generate", "install", "linkage", "uninstall",
+ (char *) NULL };
+ enum {
+ COMMAND_BIND, COMMAND_CONFIGURE, COMMAND_DETAILNAMES,
+ COMMAND_EVENTNAMES, COMMAND_GENERATE, COMMAND_INSTALL,
+ COMMAND_LINKAGE, 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_UNINSTALL:
+ {
+ return QE_UninstallCmd(tree->bindingTable, 2, objc, objv);
+ }
+ }
+
+ return TCL_OK;
+}
+
+void TreeNotify_OpenClose(TreeCtrl *tree, TreeItem item, int state, int before)
+{
+ QE_Event event;
+ struct {
+ TreeCtrl *tree; /* Must be first*/
+ int id;
+ } data;
+
+ data.tree = tree;
+ data.id = TreeItem_GetID(tree, item);
+
+ if (state & STATE_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);
+}
+
+void TreeNotify_Selection(TreeCtrl *tree, TreeItem select[], TreeItem deselect[])
+{
+ QE_Event event;
+ struct {
+ TreeCtrl *tree; /* Must be first*/
+ int *select;
+ int *deselect;
+ int count;
+ } data;
+ int staticS[20], staticD[20];
+ int i;
+
+ data.tree = tree;
+
+ if (select == NULL)
+ data.select = NULL;
+ else
+ {
+ for (i = 0; select[i] != NULL; i++)
+ /* nothing */;
+ if (i < sizeof(staticS) / sizeof(staticS[0]))
+ data.select = staticS;
+ else
+ data.select = (int *) ckalloc(sizeof(int) * (i + 1));
+ for (i = 0; select[i] != NULL; i++)
+ data.select[i] = TreeItem_GetID(tree, select[i]);
+ data.select[i] = -1;
+ }
+
+ if (deselect == NULL)
+ data.deselect = NULL;
+ else
+ {
+ for (i = 0; deselect[i] != NULL; i++)
+ /* nothing */;
+ if (i < sizeof(staticD) / sizeof(staticD[0]))
+ data.deselect = staticD;
+ else
+ data.deselect = (int *) ckalloc(sizeof(int) * (i + 1));
+ for (i = 0; deselect[i] != NULL; i++)
+ data.deselect[i] = TreeItem_GetID(tree, deselect[i]);
+ data.deselect[i] = -1;
+ }
+
+ data.count = tree->selectCount;
+
+ event.type = EVENT_SELECTION;
+ event.detail = 0;
+ event.clientData = (ClientData) &data;
+
+ (void) QE_BindEvent(tree->bindingTable, &event);
+
+ if ((select != NULL) && (data.select != staticS))
+ ckfree((char *) data.select);
+ if ((deselect != NULL) && (data.deselect != staticD))
+ ckfree((char *) data.deselect);
+}
+
+void TreeNotify_ActiveItem(TreeCtrl *tree, TreeItem itemPrev, TreeItem itemCur)
+{
+ QE_Event event;
+ struct {
+ TreeCtrl *tree; /* Must be first*/
+ 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);
+}
+
+void TreeNotify_Scroll(TreeCtrl *tree, double fractions[2], int vertical)
+{
+ QE_Event event;
+ struct {
+ TreeCtrl *tree; /* Must be first*/
+ 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);
+}
+
+int TreeNotify_Init(TreeCtrl *tree)
+{
+ 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);
+
+ return TCL_OK;
+}
+
diff --git a/generic/tkTreeStyle.c b/generic/tkTreeStyle.c
new file mode 100644
index 0000000..08dbee4
--- /dev/null
+++ b/generic/tkTreeStyle.c
@@ -0,0 +1,3652 @@
+#include "tkTreeCtrl.h"
+#include "tkTreeElem.h"
+
+typedef struct Style Style;
+typedef struct ElementLink ElementLink;
+
+struct Style
+{
+ Tk_Uid name;
+ int numElements;
+ ElementLink *elements;
+ int neededWidth;
+ int neededHeight;
+ int minWidth;
+ int minHeight;
+ int layoutWidth;
+ int layoutHeight;
+ Style *master;
+ int vertical;
+};
+
+#define ELF_eEXPAND_W 0x0001 /* external expansion */
+#define ELF_eEXPAND_N 0x0002
+#define ELF_eEXPAND_E 0x0004
+#define ELF_eEXPAND_S 0x0008
+#define ELF_iEXPAND_W 0x0010 /* internal expansion */
+#define ELF_iEXPAND_N 0x0020
+#define ELF_iEXPAND_E 0x0040
+#define ELF_iEXPAND_S 0x0080
+#define ELF_SQUEEZE_X 0x0100 /* shrink if needed */
+#define ELF_SQUEEZE_Y 0x0200
+#define ELF_DETACH 0x0400
+
+#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)
+
+struct ElementLink
+{
+ Element *elem;
+ int neededWidth;
+ int neededHeight;
+ int layoutWidth;
+ int layoutHeight;
+ int ePad[4]; /* external padding */
+ int iPad[4]; /* internal padding */
+ int flags; /* ELF_xxx */
+ int *onion, onionCount; /* -union option info */
+};
+
+static ElementType *elementTypeList = NULL;
+
+static char *orientStringTable[] = { "horizontal", "vertical", (char *) NULL };
+
+static Tk_OptionSpec styleOptionSpecs[] = {
+ {TK_OPTION_STRING_TABLE, "-orient", (char *) NULL, (char *) NULL,
+ "horizontal", -1, Tk_Offset(Style, vertical),
+ 0, (ClientData) orientStringTable, 0},
+ {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, (ClientData) NULL, 0}
+};
+
+static Tk_OptionTable styleOptionTable = NULL;
+
+struct Layout
+{
+ ElementLink *eLink;
+ ElementLink *master;
+ int useWidth;
+ int useHeight;
+ 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 ePad[4]; /* external padding */
+ int iPad[4]; /* internal padding */
+ int uPad[4]; /* padding due to -union */
+};
+
+static void Style_DoExpandH(struct Layout *layout, int flags, int width)
+{
+ int extraWidth;
+ int *ePad, *iPad;
+ int eW, eE, iW, iE, eLeft, eRight, iLeft, iRight, eMax, iMax;
+
+ if (!(flags & ELF_EXPAND_WE))
+ return;
+
+ extraWidth = width - layout->eWidth;
+ if (extraWidth <= 0)
+ return;
+
+ /* External: can expand to left and right */
+ eW = 0;
+ eE = width;
+ eLeft = layout->x;
+ eRight = width - (layout->x + layout->eWidth);
+ eMax = eLeft + eRight;
+
+ /* Internal: can expand to max of ePad[] or uPad[] */
+ iW = MAX(layout->ePad[LEFT], layout->uPad[LEFT]);
+ iE = width - MAX(layout->ePad[RIGHT], layout->uPad[RIGHT]);
+ iLeft = layout->x + layout->ePad[LEFT] - iW;
+ iRight = iE - (layout->x + layout->eWidth - layout->ePad[RIGHT]);
+ iMax = iLeft + iRight;
+
+ ePad = layout->ePad;
+ iPad = layout->iPad;
+
+ /* Internal expansion */
+ if (flags & ELF_iEXPAND_WE)
+ {
+ if ((flags & ELF_iEXPAND_WE) == ELF_iEXPAND_WE)
+ {
+ iPad[LEFT] += MIN(iMax / 2, iLeft);
+ layout->x = iW - ePad[LEFT];
+ layout->iWidth += iMax;
+ layout->eWidth += iMax;
+ iPad[RIGHT] = layout->iWidth - layout->eLink->neededWidth - iPad[LEFT];
+ }
+ else if (flags & ELF_iEXPAND_W)
+ {
+ layout->x = iW - ePad[LEFT];
+ layout->iWidth += iMax;
+ layout->eWidth += iMax;
+ iPad[LEFT] = layout->iWidth - layout->eLink->neededWidth - iPad[RIGHT];
+ }
+ else
+ {
+ layout->x = iW - ePad[LEFT];
+ layout->iWidth += iMax;
+ layout->eWidth += iMax;
+ iPad[RIGHT] = layout->iWidth - layout->eLink->neededWidth - iPad[LEFT];
+ }
+ return;
+ }
+
+ /* External expansion */
+ if (flags & ELF_eEXPAND_WE)
+ {
+ if ((flags & ELF_eEXPAND_WE) == ELF_eEXPAND_WE)
+ {
+ int amt = extraWidth / 2;
+
+ layout->x = 0;
+ layout->eWidth = width;
+ if (ePad[LEFT] + amt + layout->iWidth > iE)
+ amt -= (ePad[LEFT] + amt + layout->iWidth) - iE;
+ ePad[LEFT] += amt;
+ ePad[RIGHT] += extraWidth - amt;
+ }
+ else if (flags & ELF_eEXPAND_W)
+ {
+ layout->x = 0;
+ layout->eWidth = iE + ePad[RIGHT];
+ ePad[LEFT] = layout->eWidth - layout->iWidth - ePad[RIGHT];
+ }
+ else
+ {
+ layout->x = iW - ePad[LEFT];
+ layout->eWidth = width - layout->x;
+ ePad[RIGHT] = layout->eWidth - layout->iWidth - ePad[LEFT];
+ }
+ }
+}
+
+static void Style_DoExpandV(struct Layout *layout, int flags, int height)
+{
+ int extraHeight;
+ int *ePad, *iPad;
+ int eN, eS, iN, iS, eAbove, eBelow, iAbove, iBelow, eMax, iMax;
+
+ if (!(flags & ELF_EXPAND_NS))
+ return;
+
+ extraHeight = height - layout->eHeight;
+ if (extraHeight <= 0)
+ return;
+
+ ePad = layout->ePad;
+ iPad = layout->iPad;
+
+ /* External: can expand to top and bottom */
+ eN = 0;
+ eS = height;
+ eAbove = layout->y;
+ eBelow = height - (layout->y + layout->eHeight);
+ eMax = eAbove + eBelow;
+
+ /* Internal: can expand to max of ePad[] or uPad[] */
+ iN = MAX(ePad[TOP], layout->uPad[TOP]);
+ iS = height - MAX(ePad[BOTTOM], layout->uPad[BOTTOM]);
+ iAbove = layout->y + ePad[TOP] - iN;
+ iBelow = iS - (layout->y + layout->eHeight - ePad[BOTTOM]);
+ iMax = iAbove + iBelow;
+
+ /* Internal expansion */
+ if (flags & ELF_iEXPAND_NS)
+ {
+ if ((flags & ELF_iEXPAND_NS) == ELF_iEXPAND_NS)
+ {
+ iPad[TOP] += MIN(iMax / 2, iAbove);
+ layout->y = iN - ePad[TOP];
+ layout->iHeight += iMax;
+ layout->eHeight += iMax;
+ iPad[BOTTOM] = layout->iHeight - layout->eLink->neededHeight - iPad[TOP];
+ }
+ else if (flags & ELF_iEXPAND_N)
+ {
+ layout->y = iN - ePad[TOP];
+ layout->iHeight += iMax;
+ layout->eHeight += iMax;
+ iPad[TOP] = layout->iHeight - layout->eLink->neededHeight - iPad[BOTTOM];
+ }
+ else
+ {
+ layout->y = iN - ePad[TOP];
+ layout->iHeight += iMax;
+ layout->eHeight += iMax;
+ iPad[BOTTOM] = layout->iHeight - layout->eLink->neededHeight - iPad[TOP];
+ }
+ return;
+ }
+
+ /* External expansion */
+ if (flags & ELF_eEXPAND_NS)
+ {
+ if ((flags & ELF_eEXPAND_NS) == ELF_eEXPAND_NS)
+ {
+ int amt = extraHeight / 2;
+
+ layout->y = 0;
+ layout->eHeight = height;
+ if (ePad[TOP] + amt + layout->iHeight > iS)
+ amt -= (ePad[TOP] + amt + layout->iHeight) - iS;
+ ePad[TOP] += amt;
+ ePad[BOTTOM] += extraHeight - amt;
+ }
+ else if (flags & ELF_eEXPAND_N)
+ {
+ layout->y = 0;
+ layout->eHeight = iS + ePad[BOTTOM];
+ ePad[TOP] = layout->eHeight - layout->iHeight - ePad[BOTTOM];
+ }
+ else
+ {
+ layout->y = iN - ePad[TOP];
+ layout->eHeight = height - layout->y;
+ ePad[BOTTOM] = layout->eHeight - layout->iHeight - ePad[TOP];
+ }
+ }
+}
+
+static int Style_DoLayoutH(StyleDrawArgs *drawArgs, struct Layout layouts[20])
+{
+ Style *style = (Style *) drawArgs->style;
+ Style *masterStyle = style->master;
+ ElementLink *eLinks1, *eLinks2, *eLink1, *eLink2;
+ int x = 0;
+ int w, e;
+ int *ePad, *iPad, *uPad;
+ int numExpandWE = 0;
+ int numSqueezeX = 0;
+ int i, j, k, eLinkCount = 0;
+
+ eLinks1 = masterStyle->elements;
+ eLinks2 = style->elements;
+ eLinkCount = style->numElements;
+
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ /* Width before squeezing */
+ layout->useWidth = eLink2->neededWidth;
+
+ /* No -union padding yet */
+ for (j = 0; j < 4; j++)
+ layout->uPad[j] = 0;
+
+ /* Count all non-union, non-detach squeezeable items */
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+ if (eLink1->flags & ELF_SQUEEZE_X)
+ numSqueezeX++;
+ }
+
+ /* Calculate the padding around elements surrounded by -union elements */
+ for (i = 0; i < eLinkCount; i++)
+ {
+ eLink1 = &eLinks1[i];
+
+ if (eLink1->onion == NULL)
+ continue;
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+
+ for (j = 0; j < eLink1->onionCount; j++)
+ {
+ struct Layout *layout = &layouts[eLink1->onion[j]];
+
+ uPad = layout->uPad;
+ for (k = 0; k < 4; k++)
+ uPad[k] = MAX(uPad[k], iPad[k] + ePad[k]);
+ }
+ }
+
+ /* Left-to-right layout. Make the width of some elements less than they
+ * need */
+ if (!masterStyle->vertical &&
+ (drawArgs->width < style->neededWidth) &&
+ (numSqueezeX > 0))
+ {
+ int extraWidth = (style->neededWidth - drawArgs->width) / numSqueezeX;
+ /* Possible extra pixels */
+ int fudge = (style->neededWidth - drawArgs->width) - extraWidth * numSqueezeX;
+ int seen = 0;
+
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ if (!(eLink1->flags & ELF_SQUEEZE_X))
+ continue;
+
+ /* Subtract extra pixels from right-most element */
+ if (++seen == numSqueezeX)
+ extraWidth += fudge;
+
+ layout->useWidth -= extraWidth;
+ }
+ }
+
+ /* Reduce the width of all non-union elements, except for the
+ * cases handled above. */
+ if (drawArgs->width < style->neededWidth)
+ {
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+
+ if (eLink1->onion != NULL)
+ continue;
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+ uPad = layout->uPad;
+
+ if ((eLink1->flags & ELF_SQUEEZE_X) &&
+ ((eLink1->flags & ELF_DETACH) ||
+ masterStyle->vertical))
+ {
+ int width =
+ MAX(ePad[LEFT], uPad[LEFT]) +
+ iPad[LEFT] + layout->useWidth + iPad[RIGHT] +
+ MAX(ePad[RIGHT], uPad[RIGHT]);
+ if (width > drawArgs->width)
+ layout->useWidth -= (width - drawArgs->width);
+ }
+ }
+ }
+
+ /* Layout elements left-to-right */
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+ uPad = layout->uPad;
+
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ layout->eLink = eLink2;
+ layout->master = eLink1;
+ layout->x = MAX(x, abs(ePad[LEFT] - MAX(ePad[LEFT], uPad[LEFT])));
+ layout->iWidth = iPad[LEFT] + layout->useWidth + iPad[RIGHT];
+ layout->eWidth = ePad[LEFT] + layout->iWidth + ePad[RIGHT];
+ for (j = 0; j < 4; j++)
+ {
+ layout->ePad[j] = ePad[j];
+ layout->iPad[j] = iPad[j];
+ }
+
+ if (!masterStyle->vertical)
+ x = layout->x + layout->eWidth;
+
+ /* Count number that want to expand */
+ if (eLink1->flags & ELF_EXPAND_WE)
+ numExpandWE++;
+ }
+
+ /* Left-to-right layout. Expand some elements horizontally if we have
+ * more space available horizontally than is needed by the Style. */
+ if (!masterStyle->vertical &&
+ (drawArgs->width > style->neededWidth) &&
+ (numExpandWE > 0))
+ {
+ int extraWidth = (drawArgs->width - style->neededWidth) / numExpandWE;
+ /* Possible extra pixels */
+ int fudge = (drawArgs->width - style->neededWidth) - extraWidth * numExpandWE;
+ int eExtra, iExtra, seen = 0;
+
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ if (!(eLink1->flags & ELF_EXPAND_WE))
+ continue;
+
+ /* Give extra pixels to right-most expander */
+ if (++seen == numExpandWE)
+ extraWidth += fudge;
+
+ /* Shift following elements to the right */
+ for (j = i + 1; j < eLinkCount; j++)
+ if (layouts[j].eLink != NULL)
+ layouts[j].x += extraWidth;
+
+ ePad = layout->ePad;
+ iPad = layout->iPad;
+
+ /* External and internal expansion */
+ if ((eLink1->flags & ELF_eEXPAND_WE) && (eLink1->flags & ELF_iEXPAND_WE))
+ {
+ eExtra = extraWidth / 2;
+ iExtra = extraWidth - extraWidth / 2;
+ }
+ else
+ {
+ eExtra = extraWidth;
+ iExtra = extraWidth;
+ }
+
+ /* External expansion */
+ if (eLink1->flags & ELF_eEXPAND_WE)
+ {
+ if ((eLink1->flags & ELF_eEXPAND_WE) == ELF_eEXPAND_WE)
+ {
+ ePad[LEFT] += eExtra / 2;
+ ePad[RIGHT] += eExtra - eExtra / 2;
+ }
+ else if (eLink1->flags & ELF_eEXPAND_W)
+ ePad[LEFT] += eExtra;
+ else
+ ePad[RIGHT] += eExtra;
+ }
+
+ /* Internal expansion */
+ if (eLink1->flags & ELF_iEXPAND_WE)
+ {
+ if ((eLink1->flags & ELF_iEXPAND_WE) == ELF_iEXPAND_WE)
+ {
+ iPad[LEFT] += iExtra / 2;
+ iPad[RIGHT] += iExtra - iExtra / 2;
+ }
+ else if (eLink1->flags & ELF_iEXPAND_W)
+ iPad[LEFT] += iExtra;
+ else
+ iPad[RIGHT] += iExtra;
+ layout->iWidth += iExtra;
+ }
+ layout->eWidth += extraWidth;
+ }
+ }
+
+ /* Top-to-bottom layout. Expand some elements horizontally */
+ if (masterStyle->vertical && (numExpandWE > 0))
+ {
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ Style_DoExpandH(layout, eLink1->flags, drawArgs->width);
+ }
+ }
+
+ /* Now handle column justification */
+ if (drawArgs->width > style->neededWidth)
+ {
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ switch (drawArgs->justify)
+ {
+ case TK_JUSTIFY_LEFT:
+ break;
+ case TK_JUSTIFY_RIGHT:
+ layout->x += drawArgs->width - style->neededWidth;
+ break;
+ case TK_JUSTIFY_CENTER:
+ layout->x += (drawArgs->width - style->neededWidth) / 2;
+ break;
+ }
+ }
+ }
+
+ /* Position and expand -detach elements */
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ if (!(eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+ uPad = layout->uPad;
+
+ layout->eLink = eLink2;
+ layout->master = eLink1;
+ layout->x = abs(ePad[LEFT] - MAX(ePad[LEFT], uPad[LEFT]));
+ layout->iWidth = iPad[LEFT] + layout->useWidth + iPad[RIGHT];
+ layout->eWidth = ePad[LEFT] + layout->iWidth + ePad[RIGHT];
+ for (j = 0; j < 4; j++)
+ {
+ layout->ePad[j] = ePad[j];
+ layout->iPad[j] = iPad[j];
+ }
+
+ Style_DoExpandH(layout, eLink1->flags, drawArgs->width);
+ }
+
+ /* Now calculate layout of -union elements. */
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ if (eLink1->onion == NULL)
+ continue;
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+
+ w = 10000, e = -10000;
+
+ for (j = 0; j < eLink1->onionCount; j++)
+ {
+ struct Layout *layout2 = &layouts[eLink1->onion[j]];
+
+ w = MIN(w, layout2->x + layout2->ePad[LEFT]);
+ e = MAX(e, layout2->x + layout2->ePad[LEFT] + layout2->iWidth);
+ }
+
+ layout->eLink = eLink2;
+ layout->master = eLink1;
+ layout->x = w - iPad[LEFT] - ePad[LEFT];
+ layout->iWidth = iPad[LEFT] + (e - w) + iPad[RIGHT];
+ layout->eWidth = ePad[LEFT] + layout->iWidth + ePad[RIGHT];
+ for (j = 0; j < 4; j++)
+ {
+ layout->ePad[j] = ePad[j];
+ layout->iPad[j] = iPad[j];
+ }
+ }
+
+ /* Expand -union elements if needed: horizontal */
+ /* Expansion of "-union" elements is different than non-"-union" elements */
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+ int extraWidth;
+
+ eLink1 = &eLinks1[i];
+
+ if ((eLink1->onion == NULL) || !(eLink1->flags & ELF_EXPAND_WE))
+ continue;
+
+ if (drawArgs->width - layout->eWidth <= 0)
+ continue;
+
+ /* External and internal expansion: W */
+ extraWidth = layout->x;
+ if ((extraWidth > 0) && (eLink1->flags & ELF_EXPAND_W))
+ {
+ if ((eLink1->flags & ELF_EXPAND_W) == ELF_EXPAND_W)
+ {
+ int eExtra = extraWidth / 2;
+ int iExtra = extraWidth - extraWidth / 2;
+
+ /* External expansion */
+ layout->ePad[LEFT] += eExtra;
+ layout->x = 0;
+ layout->eWidth += extraWidth;
+
+ /* Internal expansion */
+ layout->iPad[LEFT] += iExtra;
+ layout->iWidth += iExtra;
+ }
+
+ /* External expansion only: W */
+ else if (eLink1->flags & ELF_eEXPAND_W)
+ {
+ layout->ePad[LEFT] += extraWidth;
+ layout->x = 0;
+ layout->eWidth += extraWidth;
+ }
+
+ /* Internal expansion only: W */
+ else
+ {
+ layout->iPad[LEFT] += extraWidth;
+ layout->x = 0;
+ layout->iWidth += extraWidth;
+ layout->eWidth += extraWidth;
+ }
+ }
+
+ /* External and internal expansion: E */
+ extraWidth = drawArgs->width - (layout->x + layout->eWidth);
+ if ((extraWidth > 0) && (eLink1->flags & ELF_EXPAND_E))
+ {
+ if ((eLink1->flags & ELF_EXPAND_E) == ELF_EXPAND_E)
+ {
+ int eExtra = extraWidth / 2;
+ int iExtra = extraWidth - extraWidth / 2;
+
+ /* External expansion */
+ layout->ePad[RIGHT] += eExtra;
+ layout->eWidth += extraWidth; /* all the space */
+
+ /* Internal expansion */
+ layout->iPad[RIGHT] += iExtra;
+ layout->iWidth += iExtra;
+ }
+
+ /* External expansion only: E */
+ else if (eLink1->flags & ELF_eEXPAND_E)
+ {
+ layout->ePad[RIGHT] += extraWidth;
+ layout->eWidth += extraWidth;
+ }
+
+ /* Internal expansion only: E */
+ else
+ {
+ layout->iPad[RIGHT] += extraWidth;
+ layout->iWidth += extraWidth;
+ layout->eWidth += extraWidth;
+ }
+ }
+ }
+
+ return eLinkCount;
+}
+
+static int Style_DoLayoutV(StyleDrawArgs *drawArgs, struct Layout layouts[20])
+{
+ Style *style = (Style *) drawArgs->style;
+ Style *masterStyle = style->master;
+ ElementLink *eLinks1, *eLinks2, *eLink1, *eLink2;
+ int y = 0;
+ int n, s;
+ int *ePad, *iPad, *uPad;
+ int numExpandNS = 0;
+ int numSqueezeY = 0;
+ int i, j, eLinkCount = 0;
+
+ eLinks1 = masterStyle->elements;
+ eLinks2 = style->elements;
+ eLinkCount = style->numElements;
+
+ for (i = 0; i < eLinkCount; i++)
+ {
+ eLink1 = &eLinks1[i];
+
+ /* Count all non-union, non-detach squeezeable items */
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+ if (eLink1->flags & ELF_SQUEEZE_Y)
+ numSqueezeY++;
+ }
+
+ /* Top-top-bottom layout. Make the height of some elements less than they
+ * need */
+ if (masterStyle->vertical &&
+ (drawArgs->height < style->neededHeight) &&
+ (numSqueezeY > 0))
+ {
+ int extraHeight = (style->neededHeight - drawArgs->height) / numSqueezeY;
+ /* Possible extra pixels */
+ int fudge = (style->neededHeight - drawArgs->height) - extraHeight * numSqueezeY;
+ int seen = 0;
+
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ if (!(eLink1->flags & ELF_SQUEEZE_Y))
+ continue;
+
+ /* Subtract extra pixels from bottom-most element */
+ if (++seen == numSqueezeY)
+ extraHeight += fudge;
+
+ layout->useHeight -= extraHeight;
+ }
+ }
+
+ /* 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];
+
+ eLink1 = &eLinks1[i];
+
+ if (eLink1->onion != NULL)
+ continue;
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+ uPad = layout->uPad;
+
+ if ((eLink1->flags & ELF_SQUEEZE_Y) &&
+ ((eLink1->flags & ELF_DETACH) ||
+ !masterStyle->vertical))
+ {
+ int height =
+ MAX(ePad[TOP], uPad[TOP]) +
+ iPad[TOP] + layout->useHeight + iPad[BOTTOM] +
+ MAX(ePad[BOTTOM], uPad[BOTTOM]);
+ if (height > drawArgs->height)
+ layout->useHeight -= (height - drawArgs->height);
+ }
+ }
+ }
+
+ /* Layout elements top-to-bottom */
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+ uPad = layout->uPad;
+
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ layout->y = MAX(y, abs(ePad[TOP] - MAX(ePad[TOP], uPad[TOP])));
+ layout->iHeight = iPad[TOP] + layout->useHeight + iPad[BOTTOM];
+ layout->eHeight = ePad[TOP] + layout->iHeight + ePad[BOTTOM];
+
+ if (masterStyle->vertical)
+ y = layout->y + layout->eHeight;
+
+ /* Count number that want to expand */
+ if (eLink1->flags & ELF_EXPAND_NS)
+ numExpandNS++;
+ }
+
+ /* Top-to-bottom layout. Expand some elements vertically if we have
+ * more space available vertically than is needed by the Style. */
+ if (masterStyle->vertical &&
+ (drawArgs->height > style->neededHeight) &&
+ (numExpandNS > 0))
+ {
+ int extraHeight = (drawArgs->height - style->neededHeight) / numExpandNS;
+ /* Possible extra pixels */
+ int fudge = (drawArgs->height - style->neededHeight) - extraHeight * numExpandNS;
+ int eExtra, iExtra, seen = 0;
+
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ if (!(eLink1->flags & ELF_EXPAND_NS))
+ continue;
+
+ /* Give extra pixels to bottom-most expander */
+ if (++seen == numExpandNS)
+ extraHeight += fudge;
+
+ /* Shift following elements down */
+ for (j = i + 1; j < eLinkCount; j++)
+ if (layouts[j].eLink != NULL)
+ layouts[j].y += extraHeight;
+
+ ePad = layout->ePad;
+ iPad = layout->iPad;
+
+ /* External and internal expansion */
+ if ((eLink1->flags & ELF_eEXPAND_NS) && (eLink1->flags & ELF_iEXPAND_NS))
+ {
+ eExtra = extraHeight / 2;
+ iExtra = extraHeight - extraHeight / 2;
+ }
+ else
+ {
+ eExtra = extraHeight;
+ iExtra = extraHeight;
+ }
+
+ /* External expansion */
+ if (eLink1->flags & ELF_eEXPAND_NS)
+ {
+ if ((eLink1->flags & ELF_eEXPAND_NS) == ELF_eEXPAND_NS)
+ {
+ ePad[TOP] += eExtra / 2;
+ ePad[BOTTOM] += eExtra - eExtra / 2;
+ }
+ else if (eLink1->flags & ELF_eEXPAND_N)
+ ePad[TOP] += eExtra;
+ else
+ ePad[BOTTOM] += eExtra;
+ }
+
+ /* Internal expansion */
+ if (eLink1->flags & ELF_iEXPAND_NS)
+ {
+ if ((eLink1->flags & ELF_iEXPAND_NS) == ELF_iEXPAND_NS)
+ {
+ iPad[TOP] += iExtra / 2;
+ iPad[BOTTOM] += iExtra - iExtra / 2;
+ }
+ else if (eLink1->flags & ELF_iEXPAND_N)
+ iPad[TOP] += iExtra;
+ else
+ iPad[BOTTOM] += iExtra;
+ layout->iHeight += iExtra;
+ }
+ layout->eHeight += extraHeight;
+ }
+ }
+
+ /* Left-to-right layout. Expand some elements vertically */
+ if (!masterStyle->vertical && (numExpandNS > 0))
+ {
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+
+ if ((eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ Style_DoExpandV(layout, eLinks1[i].flags, drawArgs->height);
+ }
+ }
+
+ /* Position and expand -detach elements */
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ if (!(eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+ uPad = layout->uPad;
+
+ layout->y = abs(ePad[TOP] - MAX(ePad[TOP], uPad[TOP]));
+ layout->iHeight = iPad[TOP] + layout->useHeight + iPad[BOTTOM];
+ layout->eHeight = ePad[TOP] + layout->iHeight + ePad[BOTTOM];
+
+ Style_DoExpandV(layout, eLink1->flags, drawArgs->height);
+ }
+
+ /* Now calculate layout of -union elements. */
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ if (eLink1->onion == NULL)
+ continue;
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+
+ n = 10000, s = -10000;
+
+ for (j = 0; j < eLink1->onionCount; j++)
+ {
+ struct Layout *layout2 = &layouts[eLink1->onion[j]];
+
+ n = MIN(n, layout2->y + layout2->ePad[TOP]);
+ s = MAX(s, layout2->y + layout2->ePad[TOP] + layout2->iHeight);
+ }
+
+ layout->y = n - iPad[TOP] - ePad[TOP];
+ layout->iHeight = iPad[TOP] + (s - n) + iPad[BOTTOM];
+ layout->eHeight = ePad[TOP] + layout->iHeight + ePad[BOTTOM];
+ }
+
+ /* Expand -union elements if needed: vertical */
+ for (i = 0; i < eLinkCount; i++)
+ {
+ struct Layout *layout = &layouts[i];
+ int extraHeight;
+
+ eLink1 = &eLinks1[i];
+
+ if ((eLink1->onion == NULL) || !(eLink1->flags & ELF_EXPAND_NS))
+ continue;
+
+ if (drawArgs->height - layout->eHeight <= 0)
+ continue;
+
+ /* External and internal expansion: N */
+ extraHeight = layout->y;
+ if ((extraHeight > 0) && (eLink1->flags & ELF_EXPAND_N))
+ {
+ if ((eLink1->flags & ELF_EXPAND_N) == ELF_EXPAND_N)
+ {
+ int eExtra = extraHeight / 2;
+ int iExtra = extraHeight - extraHeight / 2;
+
+ /* External expansion */
+ layout->ePad[TOP] += eExtra;
+ layout->y = 0;
+ layout->eHeight += extraHeight;
+
+ /* Internal expansion */
+ layout->iPad[TOP] += iExtra;
+ layout->iHeight += iExtra;
+ }
+
+ /* External expansion only: N */
+ else if (eLink1->flags & ELF_eEXPAND_N)
+ {
+ layout->ePad[TOP] += extraHeight;
+ layout->y = 0;
+ layout->eHeight += extraHeight;
+ }
+
+ /* Internal expansion only: N */
+ else
+ {
+ layout->iPad[TOP] += extraHeight;
+ layout->y = 0;
+ layout->iHeight += extraHeight;
+ layout->eHeight += extraHeight;
+ }
+ }
+
+ /* External and internal expansion: S */
+ extraHeight = drawArgs->height - (layout->y + layout->eHeight);
+ if ((extraHeight > 0) && (eLink1->flags & ELF_EXPAND_S))
+ {
+ if ((eLink1->flags & ELF_EXPAND_S) == ELF_EXPAND_S)
+ {
+ int eExtra = extraHeight / 2;
+ int iExtra = extraHeight - extraHeight / 2;
+
+ /* External expansion */
+ layout->ePad[BOTTOM] += eExtra;
+ layout->eHeight += extraHeight; /* all the space */
+
+ /* Internal expansion */
+ layout->iPad[BOTTOM] += iExtra;
+ layout->iHeight += iExtra;
+ }
+
+ /* External expansion only: S */
+ else if (eLink1->flags & ELF_eEXPAND_S)
+ {
+ layout->ePad[BOTTOM] += extraHeight;
+ layout->eHeight += extraHeight;
+ }
+
+ /* Internal expansion only */
+ else
+ {
+ layout->iPad[BOTTOM] += extraHeight;
+ layout->iHeight += extraHeight;
+ layout->eHeight += extraHeight;
+ }
+ }
+ }
+
+ return eLinkCount;
+}
+
+/* Calculate the height and width of all the Elements */
+static void Layout_Size(int vertical, int numLayouts, struct Layout layouts[20], int *widthPtr, int *heightPtr)
+{
+ int i, W, N, E, S;
+ int width = 0, height = 0;
+
+ W = 10000, N = 10000, E = -10000, S = -10000;
+
+ for (i = 0; i < numLayouts; i++)
+ {
+ struct Layout *layout = &layouts[i];
+ int w, n, e, s;
+
+ w = layout->x + layout->ePad[LEFT] - MAX(layout->ePad[LEFT], layout->uPad[LEFT]);
+ n = layout->y + layout->ePad[TOP] - MAX(layout->ePad[TOP], layout->uPad[TOP]);
+ e = layout->x + layout->eWidth - layout->ePad[RIGHT] + MAX(layout->ePad[RIGHT], layout->uPad[RIGHT]);
+ s = layout->y + layout->eHeight - layout->ePad[BOTTOM] + MAX(layout->ePad[BOTTOM], layout->uPad[BOTTOM]);
+
+ 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;
+}
+
+/* */
+void Style_DoLayoutNeededV(StyleDrawArgs *drawArgs, struct Layout layouts[20])
+{
+ Style *style = (Style *) drawArgs->style;
+ Style *masterStyle = style->master;
+ ElementLink *eLinks1, *eLinks2, *eLink1, *eLink2;
+ int *ePad, *iPad, *uPad;
+ int i;
+ int y = 0;
+
+ eLinks1 = masterStyle->elements;
+ eLinks2 = style->elements;
+
+ /* Layout elements left-to-right, or top-to-bottom */
+ for (i = 0; i < style->numElements; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+ uPad = layout->uPad;
+
+ /* The size of a -union element is determined by the elements
+ * it surrounds */
+ if (eLink1->onion != NULL)
+ continue;
+
+ /* -detached items are positioned by themselves */
+ if (eLink1->flags & ELF_DETACH)
+ continue;
+
+ layout->y = MAX(y, abs(ePad[TOP] - MAX(ePad[TOP], uPad[TOP])));
+ layout->iHeight = iPad[TOP] + layout->useHeight + iPad[BOTTOM];
+ layout->eHeight = ePad[TOP] + layout->iHeight + ePad[BOTTOM];
+
+ if (masterStyle->vertical)
+ y = layout->y + layout->eHeight;
+ }
+
+ /* -detached elements */
+ for (i = 0; i < style->numElements; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ if (!(eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+ uPad = layout->uPad;
+
+ layout->y = abs(ePad[TOP] - MAX(ePad[TOP], uPad[TOP]));
+ layout->iHeight = iPad[TOP] + layout->useHeight + iPad[BOTTOM];
+ layout->eHeight = ePad[TOP] + layout->iHeight + ePad[BOTTOM];
+ }
+}
+
+/* Arrange all the Elements considering drawArgs.width but not drawArgs.height */
+static void Style_DoLayout2(StyleDrawArgs *drawArgs, struct Layout layouts[20])
+{
+ TreeCtrl *tree = drawArgs->tree;
+ Style *style = (Style *) drawArgs->style;
+ int state = drawArgs->state;
+ int i;
+
+ if (style->neededWidth == -1) panic("Style_DoLayout2: style.neededWidth == -1");
+ if (style->minWidth > drawArgs->width) panic("Style_DoLayout2: style.minWidth %d > drawArgs.width %d", style->minWidth, drawArgs->width);
+
+ Style_DoLayoutH(drawArgs, layouts);
+
+ for (i = 0; i < style->numElements; i++)
+ {
+ struct Layout *layout = &layouts[i];
+ ElementLink *eLink = &style->elements[i];
+
+ layout->useHeight = eLink->neededHeight;
+
+ if (eLink->elem->typePtr == &elemTypeText)
+ {
+ if (layout->iWidth != eLink->layoutWidth)
+ {
+ ElementArgs args;
+
+ args.tree = tree;
+ args.state = state;
+ args.elem = eLink->elem;
+ args.layout.width = layout->iWidth;
+ (*args.elem->typePtr->layoutProc)(&args);
+
+ eLink->layoutWidth = layout->iWidth;
+ eLink->layoutHeight = args.layout.height;
+ }
+ layout->useHeight = eLink->layoutHeight;
+ }
+ }
+
+ Style_DoLayoutNeededV(drawArgs, layouts);
+}
+
+/* Arrange all the Elements considering drawArgs.width and drawArgs.height */
+static void Style_DoLayout(StyleDrawArgs *drawArgs, struct Layout layouts[20], char *function)
+{
+ TreeCtrl *tree = drawArgs->tree;
+ Style *style = (Style *) drawArgs->style;
+ int state = drawArgs->state;
+ int i;
+
+ if (style->neededWidth == -1) panic("Style_DoLayout(from %s): style.neededWidth == -1", function);
+ if (style->minWidth > drawArgs->width) panic("Style_DoLayout: style.minWidth %d > drawArgs.width %d", style->minWidth, drawArgs->width);
+
+ Style_DoLayoutH(drawArgs, layouts);
+
+ for (i = 0; i < style->numElements; i++)
+ {
+ struct Layout *layout = &layouts[i];
+ ElementLink *eLink = &style->elements[i];
+
+ layout->useHeight = eLink->neededHeight;
+
+ if (eLink->elem->typePtr == &elemTypeText)
+ {
+ if (layout->iWidth != eLink->layoutWidth)
+ {
+ ElementArgs args;
+
+ args.tree = tree;
+ args.state = state;
+ args.elem = eLink->elem;
+ args.layout.width = layout->iWidth;
+ (*args.elem->typePtr->layoutProc)(&args);
+
+ eLink->layoutWidth = layout->iWidth;
+ eLink->layoutHeight = args.layout.height;
+ }
+ layout->useHeight = eLink->layoutHeight;
+ }
+ }
+
+ Style_DoLayoutV(drawArgs, layouts);
+}
+
+/* Arrange Elements to determine the needed height and width of the Style */
+static void Style_NeededSize(TreeCtrl *tree, Style *style, int state, int *widthPtr, int *heightPtr, int squeeze)
+{
+ Style *masterStyle = style->master;
+ ElementLink *eLinks1, *eLinks2, *eLink1, *eLink2;
+ struct Layout layouts[20];
+ int *ePad, *iPad, *uPad;
+ int i, j, k;
+ int x = 0, y = 0;
+
+ if (style->master != NULL)
+ {
+ eLinks1 = masterStyle->elements;
+ eLinks2 = style->elements;
+ }
+ else
+ {
+ eLinks1 = masterStyle->elements;
+ eLinks2 = masterStyle->elements;
+ }
+
+ for (i = 0; i < style->numElements; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ /* No -union padding yet */
+ for (j = 0; j < 4; j++)
+ layout->uPad[j] = 0;
+ }
+
+ /* Figure out the padding around elements surrounded by -union elements */
+ for (i = 0; i < style->numElements; i++)
+ {
+ eLink1 = &eLinks1[i];
+
+ if (eLink1->onion == NULL)
+ continue;
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+
+ for (j = 0; j < eLink1->onionCount; j++)
+ {
+ struct Layout *layout = &layouts[eLink1->onion[j]];
+
+ uPad = layout->uPad;
+ for (k = 0; k < 4; k++)
+ uPad[k] = MAX(uPad[k], iPad[k] + ePad[k]);
+ }
+ }
+
+ /* Layout elements left-to-right, or top-to-bottom */
+ for (i = 0; i < style->numElements; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+ uPad = layout->uPad;
+
+ /* The size of a -union element is determined by the elements
+ * it surrounds */
+ if (eLink1->onion != NULL)
+ {
+ layout->x = layout->y = layout->eWidth = layout->eHeight = 0;
+ for (j = 0; j < 4; j++)
+ layout->ePad[j] = layout->iPad[j] = 0;
+ continue;
+ }
+
+ if ((eLink2->neededWidth == -1) || (eLink2->neededHeight == -1))
+ {
+ ElementArgs args;
+
+ args.tree = tree;
+ args.state = state;
+ args.elem = eLink2->elem;
+ args.layout.width = -1;
+ (*args.elem->typePtr->layoutProc)(&args);
+ eLink2->neededWidth = args.layout.width;
+ eLink2->neededHeight = args.layout.height;
+
+ eLink2->layoutWidth = -1;
+ eLink2->layoutHeight = args.layout.height;
+ }
+
+ layout->useWidth = eLink2->neededWidth;
+ layout->useHeight = eLink2->neededHeight;
+ if (squeeze)
+ {
+ if (eLink1->flags & ELF_SQUEEZE_X)
+ layout->useWidth = 0;
+ if (eLink1->flags & ELF_SQUEEZE_Y)
+ layout->useHeight = 0;
+ }
+
+ /* -detached items are positioned by themselves */
+ if (eLink1->flags & ELF_DETACH)
+ continue;
+
+ layout->eLink = eLink2;
+ layout->x = MAX(x, abs(ePad[LEFT] - MAX(ePad[LEFT], uPad[LEFT])));
+ layout->y = MAX(y, abs(ePad[TOP] - MAX(ePad[TOP], uPad[TOP])));
+ layout->iWidth = iPad[LEFT] + layout->useWidth + iPad[RIGHT];
+ layout->iHeight = iPad[TOP] + layout->useHeight + iPad[BOTTOM];
+ layout->eWidth = ePad[LEFT] + layout->iWidth + ePad[RIGHT];
+ layout->eHeight = ePad[TOP] + layout->iHeight + ePad[BOTTOM];
+ for (j = 0; j < 4; j++)
+ {
+ layout->ePad[j] = ePad[j];
+ layout->iPad[j] = iPad[j];
+ }
+
+ if (masterStyle->vertical)
+ y = layout->y + layout->eHeight;
+ else
+ x = layout->x + layout->eWidth;
+ }
+
+ /* -detached elements */
+ for (i = 0; i < style->numElements; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ eLink1 = &eLinks1[i];
+ eLink2 = &eLinks2[i];
+
+ if (!(eLink1->flags & ELF_DETACH) || (eLink1->onion != NULL))
+ continue;
+
+ ePad = eLink1->ePad;
+ iPad = eLink1->iPad;
+ uPad = layout->uPad;
+
+ layout->eLink = eLink2;
+ layout->master = eLink1;
+ layout->x = abs(ePad[LEFT] - MAX(ePad[LEFT], uPad[LEFT]));
+ layout->y = abs(ePad[TOP] - MAX(ePad[TOP], uPad[TOP]));
+ layout->iWidth = iPad[LEFT] + layout->useWidth + iPad[RIGHT];
+ layout->iHeight = iPad[TOP] + layout->useHeight + iPad[BOTTOM];
+ layout->eWidth = ePad[LEFT] + layout->iWidth + ePad[RIGHT];
+ layout->eHeight = ePad[TOP] + layout->iHeight + ePad[BOTTOM];
+ for (j = 0; j < 4; j++)
+ {
+ layout->ePad[j] = ePad[j];
+ layout->iPad[j] = iPad[j];
+ }
+ }
+
+ Layout_Size(masterStyle->vertical, style->numElements, layouts,
+ widthPtr, heightPtr);
+
+ memset(layouts, 0xAA, sizeof(layouts)); /* debug */
+}
+
+int TreeStyle_NeededWidth(TreeCtrl *tree, TreeStyle style, int state)
+{
+ int width, height;
+
+ Style_NeededSize(tree, (Style *) style, state, &width, &height, FALSE);
+ return width;
+}
+
+int TreeStyle_NeededHeight(TreeCtrl *tree, TreeStyle style, int state)
+{
+ int width, height;
+
+ Style_NeededSize(tree, (Style *) style, state, &width, &height, FALSE);
+ return height;
+}
+
+/* Calculate height of Style considering drawArgs.width */
+int TreeStyle_UseHeight(StyleDrawArgs *drawArgs)
+{
+ TreeCtrl *tree = drawArgs->tree;
+ Style *style = (Style *) drawArgs->style;
+ int state = drawArgs->state;
+ int layoutWidth = drawArgs->width;
+ int height;
+
+ if (style->neededWidth == -1)
+ {
+ Style_NeededSize(tree, style, state, &style->neededWidth,
+ &style->neededHeight, FALSE);
+ Style_NeededSize(tree, style, state, &style->minWidth,
+ &style->minHeight, TRUE);
+
+ style->layoutWidth = -1;
+ }
+
+ if ((layoutWidth == -1) ||
+ (layoutWidth >= style->neededWidth) ||
+ (style->neededWidth == style->minWidth))
+ {
+ height = style->neededHeight;
+ }
+
+ else if (layoutWidth <= style->minWidth)
+ {
+ height = style->minHeight;
+ }
+
+ else if (layoutWidth == style->layoutWidth)
+ {
+ height = style->layoutHeight;
+ }
+
+ else
+ {
+ struct Layout layouts[20];
+ int width;
+
+ Style_DoLayout2(drawArgs, layouts);
+
+ Layout_Size(style->master->vertical, style->numElements, layouts,
+ &width, &height);
+
+ memset(layouts, 0xAA, sizeof(layouts)); /* debug */
+
+ style->layoutHeight = height;
+ }
+
+ return height;
+}
+
+void TreeStyle_Draw(StyleDrawArgs *drawArgs)
+{
+ Style *style = (Style *) drawArgs->style;
+ TreeCtrl *tree = drawArgs->tree;
+ ElementArgs args;
+ int i;
+ struct Layout layouts[20];
+ int debugDraw = FALSE;
+
+ if (drawArgs->width < style->minWidth)
+ drawArgs->width = style->minWidth;
+ if (drawArgs->height < style->minHeight)
+ drawArgs->height = style->minHeight;
+
+ Style_DoLayout(drawArgs, layouts, __FUNCTION__);
+
+ args.tree = tree;
+ args.state = drawArgs->state;
+ args.display.drawable = drawArgs->drawable;
+
+ for (i = 0; i < style->numElements; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ if (debugDraw && layout->master->onion != NULL)
+ continue;
+
+ if ((layout->iWidth > 0) && (layout->iHeight > 0))
+ {
+ args.elem = layout->eLink->elem;
+ args.display.x = drawArgs->x + layout->x + layout->ePad[LEFT];
+ args.display.y = drawArgs->y + layout->y + layout->ePad[TOP];
+ args.display.width = layout->iWidth;
+ args.display.height = layout->iHeight;
+ args.display.pad[LEFT] = layout->iPad[LEFT];
+ args.display.pad[TOP] = layout->iPad[TOP];
+ args.display.pad[RIGHT] = layout->iPad[RIGHT];
+ args.display.pad[BOTTOM] = layout->iPad[BOTTOM];
+ 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->ePad[LEFT],
+ args.display.y - layout->ePad[TOP],
+ 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->iPad[LEFT],
+ args.display.y + layout->iPad[TOP],
+ layout->eLink->neededWidth, layout->eLink->neededHeight);
+ }
+ else
+ (*args.elem->typePtr->displayProc)(&args);
+ }
+ }
+
+ if (debugDraw)
+ for (i = 0; i < style->numElements; i++)
+ {
+ struct Layout *layout = &layouts[i];
+
+ if (layout->master->onion == NULL)
+ continue;
+ if (layout->iWidth > 0 && layout->iHeight > 0)
+ {
+ args.elem = layout->eLink->elem;
+ args.display.x = drawArgs->x + layout->x + layout->ePad[LEFT];
+ args.display.y = drawArgs->y + layout->y + layout->ePad[TOP];
+ args.display.width = layout->iWidth;
+ args.display.height = layout->iHeight;
+ args.display.pad[LEFT] = layout->iPad[LEFT];
+ args.display.pad[TOP] = layout->iPad[TOP];
+ args.display.pad[RIGHT] = layout->iPad[RIGHT];
+ args.display.pad[BOTTOM] = layout->iPad[BOTTOM];
+ {
+ 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->ePad[LEFT],
+ args.display.y - layout->ePad[TOP],
+ 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);
+ }
+ }
+ }
+
+ memset(layouts, 0xAA, sizeof(layouts)); /* debug */
+}
+
+static void Element_FreeResources(TreeCtrl *tree, Element *elem)
+{
+ ElementArgs args;
+ Tcl_HashEntry *hPtr;
+
+ if (elem->master == NULL)
+ {
+ hPtr = Tcl_FindHashEntry(&tree->elementHash, elem->name);
+ Tcl_DeleteHashEntry(hPtr);
+ }
+ args.tree = tree;
+ args.elem = elem;
+ (*elem->typePtr->deleteProc)(&args);
+ Tk_FreeConfigOptions((char *) elem,
+ elem->typePtr->optionTable,
+ tree->tkwin);
+ WFREE(elem, Element);
+}
+
+static ElementLink *ElementLink_Init(ElementLink *eLink, Element *elem)
+{
+ memset(eLink, '\0', sizeof(ElementLink));
+ eLink->elem = elem;
+ return eLink;
+}
+
+static void ElementLink_FreeResources(TreeCtrl *tree, ElementLink *eLink)
+{
+ if (eLink->elem->master != NULL)
+ Element_FreeResources(tree, eLink->elem);
+ if (eLink->onion != NULL)
+ wipefree((char *) eLink->onion, sizeof(int) * eLink->onionCount);
+}
+
+void TreeStyle_FreeResources(TreeCtrl *tree, TreeStyle style_)
+{
+ Style *style = (Style *) style_;
+ int i;
+ Tcl_HashEntry *hPtr;
+
+ if (style->master == NULL)
+ {
+ hPtr = Tcl_FindHashEntry(&tree->styleHash, style->name);
+ Tcl_DeleteHashEntry(hPtr);
+ }
+ if (style->numElements > 0)
+ {
+ for (i = 0; i < style->numElements; i++)
+ ElementLink_FreeResources(tree, &style->elements[i]);
+ wipefree((char *) style->elements, sizeof(ElementLink) *
+ style->numElements);
+ }
+ WFREE(style, Style);
+}
+
+static ElementLink *Style_FindElem(TreeCtrl *tree, Style *style, Element *master, int *index)
+{
+ int i;
+
+ for (i = 0; i < style->numElements; i++)
+ {
+ if (style->elements[i].elem->name == master->name)
+ {
+ if (index != NULL) (*index) = i;
+ return &style->elements[i];
+ }
+ }
+
+ return NULL;
+}
+
+/* Create an instance Element if it doesn't exist in this Style */
+static ElementLink *Style_CreateElem(TreeCtrl *tree, Style *style, Element *masterElem, int *isNew)
+{
+ ElementLink *eLink = NULL;
+ Element *elem;
+ ElementArgs args;
+ int i;
+
+ if (masterElem->master != NULL)
+ panic("Style_CreateElem called with instance Element");
+
+ if (isNew != NULL) (*isNew) = FALSE;
+
+ for (i = 0; i < style->numElements; i++)
+ {
+ eLink = &style->elements[i];
+
+ if (eLink->elem == masterElem)
+ {
+ /* Master Styles use master Elements only */
+ if (style->master == NULL)
+ return eLink;
+
+ /* 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 == style->numElements)
+ return NULL;
+
+ elem = (Element *) ckalloc(masterElem->typePtr->size);
+ memset(elem, '\0', masterElem->typePtr->size);
+ elem->typePtr = masterElem->typePtr;
+ elem->name = masterElem->name;
+ elem->master = masterElem;
+ args.tree = tree;
+ args.elem = elem;
+
+ /* FIXME: free memory if these calls could actually fail */
+ if ((*elem->typePtr->createProc)(&args) != TCL_OK)
+ return NULL;
+
+ if (Tk_InitOptions(tree->interp, (char *) elem,
+ elem->typePtr->optionTable, tree->tkwin) != TCL_OK)
+ return NULL;
+
+ args.config.objc = 0;
+ args.config.flagSelf = 0;
+ if ((*elem->typePtr->configProc)(&args) != TCL_OK)
+ return NULL;
+
+ args.change.flagSelf = args.config.flagSelf;
+ args.change.flagTree = 0;
+ args.change.flagMaster = 0;
+ (*elem->typePtr->changeProc)(&args);
+
+ eLink->elem = elem;
+ if (isNew != NULL) (*isNew) = TRUE;
+ return eLink;
+}
+
+TreeStyle TreeStyle_NewInstance(TreeCtrl *tree, TreeStyle style_)
+{
+ Style *style = (Style *) style_;
+ Style *copy;
+ ElementLink *eLink;
+ int i;
+
+ copy = (Style *) ckalloc(sizeof(Style));
+ memset(copy, '\0', sizeof(Style));
+ copy->name = style->name;
+ copy->neededWidth = -1;
+ copy->neededHeight = -1;
+ copy->master = style;
+ copy->numElements = style->numElements;
+ if (style->numElements > 0)
+ {
+ copy->elements = (ElementLink *) ckalloc(sizeof(ElementLink) * style->numElements);
+ memset(copy->elements, '\0', sizeof(ElementLink) * style->numElements);
+ for (i = 0; i < style->numElements; i++)
+ {
+ eLink = &copy->elements[i];
+
+ /* The only fields needed by an instance */
+ eLink->elem = style->elements[i].elem;
+ eLink->neededWidth = -1;
+ eLink->neededHeight = -1;
+ }
+ }
+
+ return (TreeStyle) copy;
+}
+
+static int Element_FromObj(TreeCtrl *tree, Tcl_Obj *obj, Element **elemPtr)
+{
+ char *name;
+ Tcl_HashEntry *hPtr;
+
+ name = Tcl_GetString(obj);
+ hPtr = Tcl_FindHashEntry(&tree->elementHash, name);
+ if (hPtr == NULL)
+ {
+ Tcl_AppendResult(tree->interp, "element \"", name, "\" doesn't exist",
+ NULL);
+ return TCL_ERROR;
+ }
+ (*elemPtr) = (Element *) Tcl_GetHashValue(hPtr);
+ return TCL_OK;
+}
+
+int TreeStyle_FromObj(TreeCtrl *tree, Tcl_Obj *obj, TreeStyle *stylePtr)
+{
+ char *name;
+ Tcl_HashEntry *hPtr;
+
+ name = Tcl_GetString(obj);
+ hPtr = Tcl_FindHashEntry(&tree->styleHash, name);
+ if (hPtr == NULL)
+ {
+ Tcl_AppendResult(tree->interp, "style \"", name, "\" doesn't exist",
+ NULL);
+ return TCL_ERROR;
+ }
+ (*stylePtr) = (TreeStyle) Tcl_GetHashValue(hPtr);
+ return TCL_OK;
+}
+
+static Tcl_Obj *Element_ToObj(Element *elem)
+{
+ return Tcl_NewStringObj(elem->name, -1);
+}
+
+Tcl_Obj *TreeStyle_ToObj(TreeStyle style_)
+{
+ Style *style = (Style *) style_;
+
+ return Tcl_NewStringObj(style->name, -1);
+}
+
+static void Style_Changed(TreeCtrl *tree, Style *masterStyle)
+{
+ TreeItem item;
+ TreeItemColumn column;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ int columnIndex, layout;
+ int updateDInfo = FALSE;
+
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ column = TreeItem_GetFirstColumn(tree, item);
+ columnIndex = 0;
+ layout = FALSE;
+ while (column != NULL)
+ {
+ Style *style = (Style *) TreeItemColumn_GetStyle(tree, column);
+ if ((style != NULL) && (style->master == masterStyle))
+ {
+ style->neededWidth = style->neededHeight = -1;
+ Tree_InvalidateColumnWidth(tree, columnIndex);
+ TreeItemColumn_InvalidateSize(tree, column);
+ layout = TRUE;
+ }
+ columnIndex++;
+ column = TreeItemColumn_GetNext(tree, column);
+ }
+ if (layout)
+ {
+ TreeItem_InvalidateHeight(tree, item);
+ Tree_InvalidateItemDInfo(tree, item, NULL);
+ updateDInfo = TRUE;
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ if (updateDInfo)
+ Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
+}
+
+static void Style_ChangeElementsAux(TreeCtrl *tree, Style *style, int count, Element **elemList, int *map)
+{
+ ElementLink *eLink, *eLinks = NULL;
+ int i, keep[20];
+
+ if (count > 0)
+ eLinks = (ElementLink *) ckalloc(sizeof(ElementLink) * count);
+
+ /* 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 = ElementLink_Init(&eLinks[i], elemList[i]);
+ eLink->neededWidth = eLink->neededHeight = -1;
+ }
+ }
+
+ if (style->numElements > 0)
+ {
+ /* Free unused ElementLinks */
+ for (i = 0; i < style->numElements; i++)
+ {
+ if (!keep[i])
+ ElementLink_FreeResources(tree, &style->elements[i]);
+ }
+ wipefree((char *) style->elements, sizeof(ElementLink) *
+ style->numElements);
+ }
+
+ style->elements = eLinks;
+ style->numElements = count;
+}
+
+static void Style_ChangeElements(TreeCtrl *tree, Style *masterStyle, int count, Element **elemList, int *map)
+{
+ TreeItem item;
+ TreeItemColumn column;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ int columnIndex, layout;
+ int updateDInfo = FALSE;
+ int i, j, k;
+
+ /* Update -union lists */
+ for (i = 0; i < masterStyle->numElements; i++)
+ {
+ ElementLink *eLink = &masterStyle->elements[i];
+ int keep[20], onionCnt = 0, *onion = NULL;
+
+ if (eLink->onion == NULL)
+ continue;
+
+ /* Check every Element in this -union */
+ for (j = 0; j < eLink->onionCount; j++)
+ {
+ ElementLink *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];
+ }
+ }
+ if (onionCnt != eLink->onionCount)
+ {
+ wipefree((char *) eLink->onion, sizeof(int) * eLink->onionCount);
+ eLink->onion = onion;
+ eLink->onionCount = onionCnt;
+ }
+ }
+
+ Style_ChangeElementsAux(tree, masterStyle, count, elemList, map);
+
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ column = TreeItem_GetFirstColumn(tree, item);
+ columnIndex = 0;
+ layout = FALSE;
+ while (column != NULL)
+ {
+ Style *style = (Style *) TreeItemColumn_GetStyle(tree, column);
+ if ((style != NULL) && (style->master == masterStyle))
+ {
+ Style_ChangeElementsAux(tree, style, count, elemList, map);
+ style->neededWidth = style->neededHeight = -1;
+ Tree_InvalidateColumnWidth(tree, columnIndex);
+ TreeItemColumn_InvalidateSize(tree, column);
+ layout = TRUE;
+ }
+ columnIndex++;
+ column = TreeItemColumn_GetNext(tree, column);
+ }
+ if (layout)
+ {
+ TreeItem_InvalidateHeight(tree, item);
+ Tree_InvalidateItemDInfo(tree, item, NULL);
+ updateDInfo = TRUE;
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ if (updateDInfo)
+ Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
+}
+
+static void Style_ElemChanged(TreeCtrl *tree, Style *masterStyle,
+ Element *masterElem, int flagM, int flagT, int csM)
+{
+ TreeItem item;
+ TreeItemColumn column;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ ElementLink *eLink;
+ int i, columnIndex;
+ ElementArgs args;
+ int eMask, iMask;
+ int updateDInfo = FALSE;
+
+ args.tree = tree;
+ args.change.flagTree = flagT;
+ args.change.flagMaster = flagM;
+ args.change.flagSelf = 0;
+
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ column = TreeItem_GetFirstColumn(tree, item);
+ columnIndex = 0;
+ iMask = 0;
+ while (column != NULL)
+ {
+ Style *style = (Style *) TreeItemColumn_GetStyle(tree, column);
+ if ((style != NULL) && (style->master == masterStyle))
+ {
+ for (i = 0; i < style->numElements; i++)
+ {
+ eLink = &style->elements[i];
+ if (eLink->elem == masterElem)
+ {
+ if (csM & CS_LAYOUT)
+ eLink->neededWidth = eLink->neededHeight = -1;
+ break;
+ }
+ /* Instance element */
+ if (eLink->elem->master == masterElem)
+ {
+ args.elem = eLink->elem;
+ eMask = (*masterElem->typePtr->changeProc)(&args);
+ if (eMask & CS_LAYOUT)
+ eLink->neededWidth = eLink->neededHeight = -1;
+ iMask |= eMask;
+ break;
+ }
+ }
+ iMask |= csM;
+ if (iMask & CS_LAYOUT)
+ {
+ style->neededWidth = style->neededHeight = -1;
+ Tree_InvalidateColumnWidth(tree, columnIndex);
+ TreeItemColumn_InvalidateSize(tree, column);
+ }
+ }
+ columnIndex++;
+ column = TreeItemColumn_GetNext(tree, column);
+ }
+ if (iMask & CS_LAYOUT)
+ {
+ TreeItem_InvalidateHeight(tree, item);
+ updateDInfo = TRUE;
+ }
+ if (iMask & CS_DISPLAY)
+ Tree_InvalidateItemDInfo(tree, item, NULL);
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ if (updateDInfo)
+ Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
+}
+
+TreeStyle TreeStyle_GetMaster(TreeCtrl *tree, TreeStyle style_)
+{
+ return (TreeStyle) ((Style *) style_)->master;
+}
+
+static Tcl_Obj *confTextObj = NULL;
+
+Tcl_Obj *TreeStyle_GetText(TreeCtrl *tree, TreeStyle style_)
+{
+ Style *style = (Style *) style_;
+ ElementLink *eLink;
+ int i;
+
+ if (confTextObj == NULL)
+ {
+ confTextObj = Tcl_NewStringObj("-text", -1);
+ Tcl_IncrRefCount(confTextObj);
+ }
+
+ for (i = 0; i < style->numElements; i++)
+ {
+ eLink = &style->elements[i];
+ if (eLink->elem->typePtr == &elemTypeText)
+ {
+ Tcl_Obj *resultObjPtr;
+ resultObjPtr = Tk_GetOptionValue(tree->interp,
+ (char *) eLink->elem, eLink->elem->typePtr->optionTable,
+ confTextObj, tree->tkwin);
+ return resultObjPtr;
+ }
+ }
+
+ return NULL;
+}
+
+void TreeStyle_SetText(TreeCtrl *tree, TreeStyle style_, Tcl_Obj *textObj)
+{
+ Style *style = (Style *) style_;
+ Style *masterStyle = style->master;
+ ElementLink *eLink;
+ int i;
+
+ if (masterStyle == NULL)
+ panic("TreeStyle_SetText called with master Style");
+
+ if (confTextObj == NULL)
+ {
+ confTextObj = Tcl_NewStringObj("-text", -1);
+ Tcl_IncrRefCount(confTextObj);
+ }
+
+ for (i = 0; i < style->numElements; i++)
+ {
+ eLink = &masterStyle->elements[i];
+ if (eLink->elem->typePtr == &elemTypeText)
+ {
+ Tcl_Obj *objv[2];
+ ElementArgs args;
+
+ eLink = Style_CreateElem(tree, style, eLink->elem, NULL);
+ objv[0] = confTextObj;
+ objv[1] = textObj;
+ args.tree = tree;
+ args.elem = eLink->elem;
+ args.config.objc = 2;
+ args.config.objv = objv;
+ args.config.flagSelf = 0;
+ (void) (*eLink->elem->typePtr->configProc)(&args);
+
+ args.change.flagSelf = args.config.flagSelf;
+ args.change.flagTree = 0;
+ args.change.flagMaster = 0;
+ (*eLink->elem->typePtr->changeProc)(&args);
+
+ eLink->neededWidth = eLink->neededHeight = -1;
+ style->neededWidth = style->neededHeight = -1;
+ return;
+ }
+ }
+}
+
+static void Style_Deleted(TreeCtrl *tree, Style *masterStyle)
+{
+ TreeItem item;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ TreeItemColumn column;
+ int columnIndex;
+
+ if (masterStyle->master != NULL)
+ panic("Style_Deleted called with instance Style");
+
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ column = TreeItem_GetFirstColumn(tree, item);
+ columnIndex = 0;
+ while (column != NULL)
+ {
+ Style *style = (Style *) TreeItemColumn_GetStyle(tree, column);
+ if ((style != NULL) && ((style == masterStyle) || (style->master == masterStyle)))
+ {
+ Tree_InvalidateColumnWidth(tree, columnIndex);
+ TreeItemColumn_ForgetStyle(tree, column);
+ TreeItem_InvalidateHeight(tree, item);
+ Tree_FreeItemDInfo(tree, item, NULL);
+ }
+ columnIndex++;
+ column = TreeItemColumn_GetNext(tree, column);
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+}
+
+static void Element_Changed(TreeCtrl *tree, Element *masterElem, int flagM, int flagT, int csM)
+{
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ Style *masterStyle;
+ ElementLink *eLink;
+ int i;
+
+ hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search);
+ while (hPtr != NULL)
+ {
+ masterStyle = (Style *) Tcl_GetHashValue(hPtr);
+ for (i = 0; i < masterStyle->numElements; i++)
+ {
+ eLink = &masterStyle->elements[i];
+ if (eLink->elem == masterElem)
+ {
+ Style_ElemChanged(tree, masterStyle, masterElem, flagM, flagT, csM);
+ break;
+ }
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+}
+
+void TreeStyle_TreeChanged(TreeCtrl *tree, int flagT)
+{
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ Element *masterElem;
+ ElementArgs 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 = (Element *) Tcl_GetHashValue(hPtr);
+ args.elem = masterElem;
+ eMask = (*masterElem->typePtr->changeProc)(&args);
+ Element_Changed(tree, masterElem, 0, flagT, eMask);
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+}
+
+int TreeStyle_ElementCget(TreeCtrl *tree, TreeStyle style_, Tcl_Obj *elemObj, Tcl_Obj *obj)
+{
+ Style *style = (Style *) style_;
+ Tcl_Obj *resultObjPtr = NULL;
+ Element *elem;
+ ElementLink *eLink;
+
+ if (Element_FromObj(tree, elemObj, &elem) != TCL_OK)
+ return TCL_ERROR;
+
+ eLink = Style_FindElem(tree, style, elem, NULL);
+ if ((eLink != NULL) && (eLink->elem == elem) && (style->master != NULL))
+ eLink = NULL;
+ if (eLink == NULL)
+ {
+ FormatResult(tree->interp, "style %s does not use element %s",
+ style->name, elem->name);
+ return TCL_ERROR;
+ }
+
+ resultObjPtr = Tk_GetOptionValue(tree->interp, (char *) eLink->elem,
+ eLink->elem->typePtr->optionTable, obj, tree->tkwin);
+ if (resultObjPtr == NULL)
+ return TCL_ERROR;
+ Tcl_SetObjResult(tree->interp, resultObjPtr);
+ return TCL_OK;
+}
+
+int TreeStyle_ElementConfigure(TreeCtrl *tree, TreeStyle style_, Tcl_Obj *elemObj, int objc, Tcl_Obj **objv)
+{
+ Style *style = (Style *) style_;
+ Element *elem;
+ ElementLink *eLink;
+ ElementArgs args;
+
+ if (Element_FromObj(tree, elemObj, &elem) != TCL_OK)
+ return TCL_ERROR;
+
+ if (objc <= 1)
+ {
+ Tcl_Obj *resultObjPtr;
+
+ eLink = Style_FindElem(tree, style, elem, NULL);
+ if ((eLink != NULL) && (eLink->elem == elem) && (style->master != NULL))
+ eLink = NULL;
+ if (eLink == NULL)
+ {
+ FormatResult(tree->interp, "style %s does not use element %s",
+ style->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
+ {
+ eLink = Style_CreateElem(tree, style, elem, NULL);
+ if (eLink == NULL)
+ {
+ FormatResult(tree->interp, "style %s does not use element %s",
+ style->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 */
+ eLink->neededWidth = eLink->neededHeight = -1;
+ style->neededWidth = style->neededHeight = -1;
+
+ args.tree = tree;
+ args.elem = eLink->elem;
+ args.config.objc = objc;
+ args.config.objv = objv;
+ args.config.flagSelf = 0;
+ 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;
+ (*elem->typePtr->changeProc)(&args);
+ }
+ return TCL_OK;
+}
+
+int TreeStyle_ElementActual(TreeCtrl *tree, TreeStyle style_, int state, Tcl_Obj *elemObj, Tcl_Obj *obj)
+{
+ Style *style = (Style *) style_;
+ Element *masterElem;
+ ElementLink *eLink;
+ ElementArgs args;
+
+ if (Element_FromObj(tree, elemObj, &masterElem) != TCL_OK)
+ return TCL_ERROR;
+
+ eLink = Style_FindElem(tree, style, masterElem, NULL);
+ if (eLink == NULL)
+ {
+ FormatResult(tree->interp, "style %s does not use element %s",
+ style->name, masterElem->name);
+ return TCL_ERROR;
+ }
+\
+ args.tree = tree;
+ args.elem = eLink->elem;
+ args.state = state;
+ args.actual.obj = obj;
+ return (*masterElem->typePtr->actualProc)(&args);
+}
+
+static Element *Element_CreateAndConfig(TreeCtrl *tree, ElementType *type, char *name, int objc, Tcl_Obj *CONST objv[])
+{
+ Element *elem;
+ ElementArgs args;
+
+ elem = (Element *) ckalloc(type->size);
+ memset(elem, '\0', type->size);
+ elem->name = Tk_GetUid(name);
+ elem->typePtr = type;
+ args.tree = tree;
+ args.elem = elem;
+ if ((*type->createProc)(&args) != TCL_OK)
+ return NULL;
+
+ if (Tk_InitOptions(tree->interp, (char *) elem,
+ type->optionTable, tree->tkwin) != TCL_OK)
+ {
+ WFREE(elem, Element);
+ return NULL;
+ }
+ args.config.objc = objc;
+ args.config.objv = objv;
+ args.config.flagSelf = 0;
+ if ((*type->configProc)(&args) != TCL_OK)
+ {
+ (*type->deleteProc)(&args);
+ Tk_FreeConfigOptions((char *) elem,
+ elem->typePtr->optionTable,
+ tree->tkwin);
+ WFREE(elem, Element);
+ return NULL;
+ }
+
+ args.change.flagSelf = args.config.flagSelf;
+ args.change.flagTree = 0;
+ args.change.flagMaster = 0;
+ (*type->changeProc)(&args);
+
+ return elem;
+}
+
+int TreeElementCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ static CONST char *commandNames[] = { "cget", "configure", "create", "delete",
+ "names", "type", (char *) NULL };
+ enum { COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_CREATE, COMMAND_DELETE,
+ COMMAND_NAMES, 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;
+ Element *elem;
+
+ if (objc != 5)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "name option");
+ return TCL_ERROR;
+ }
+ if (Element_FromObj(tree, objv[3], &elem) != TCL_OK)
+ return TCL_ERROR;
+ 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;
+ Element *elem;
+ int eMask;
+
+ if (objc < 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "name ?option? ?value option value...?");
+ return TCL_ERROR;
+ }
+ if (Element_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
+ {
+ ElementArgs args;
+
+ args.tree = tree;
+ args.elem = elem;
+ args.config.objc = objc - 4;
+ args.config.objv = objv + 4;
+ args.config.flagSelf = 0;
+ 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, *typeStr;
+ int length;
+ int isNew;
+ Element *elem;
+ ElementType *typePtr, *matchPtr = NULL;
+ 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;
+ }
+ typeStr = Tcl_GetStringFromObj(objv[4], &length);
+ if (!length)
+ {
+ FormatResult(interp,
+ "invalid element type \"\"");
+ return TCL_ERROR;
+ }
+ for (typePtr = elementTypeList;
+ 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;
+ }
+ typePtr = matchPtr;
+ elem = Element_CreateAndConfig(tree, 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, Element_ToObj(elem));
+ break;
+ }
+
+ case COMMAND_DELETE:
+ {
+ Element *elem;
+ int i;
+
+ if (objc < 3)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "?name ...?");
+ return TCL_ERROR;
+ }
+ for (i = 3; i < objc; i++)
+ {
+ if (Element_FromObj(tree, objv[i], &elem) != TCL_OK)
+ return TCL_ERROR;
+ /* TODO: Mass changes to any Style using this Element */
+ Element_FreeResources(tree, elem);
+ }
+ break;
+ }
+
+ case COMMAND_NAMES:
+ {
+ Tcl_Obj *listObj;
+ Tcl_HashSearch search;
+ Tcl_HashEntry *hPtr;
+ Element *elem;
+
+ listObj = Tcl_NewListObj(0, NULL);
+ hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search);
+ while (hPtr != NULL)
+ {
+ elem = (Element *) Tcl_GetHashValue(hPtr);
+ Tcl_ListObjAppendElement(interp, listObj, Element_ToObj(elem));
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ Tcl_SetObjResult(interp, listObj);
+ break;
+ }
+
+ case COMMAND_TYPE:
+ {
+ Element *elem;
+
+ if (objc != 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "name");
+ return TCL_ERROR;
+ }
+ if (Element_FromObj(tree, objv[3], &elem) != TCL_OK)
+ return TCL_ERROR;
+ Tcl_SetResult(interp, elem->typePtr->name, TCL_STATIC); /* Tk_Uid */
+ break;
+ }
+ }
+ return TCL_OK;
+}
+
+static Style *Style_CreateAndConfig(TreeCtrl *tree, char *name, int objc, Tcl_Obj *CONST objv[])
+{
+ Style *style;
+
+ style = (Style *) ckalloc(sizeof(Style));
+ memset(style, '\0', sizeof(Style));
+ style->name = Tk_GetUid(name);
+
+ if (Tk_InitOptions(tree->interp, (char *) style,
+ styleOptionTable, tree->tkwin) != TCL_OK)
+ {
+ WFREE(style, Style);
+ return NULL;
+ }
+
+ if (Tk_SetOptions(tree->interp, (char *) style,
+ styleOptionTable, objc, objv, tree->tkwin,
+ NULL, NULL) != TCL_OK)
+ {
+ Tk_FreeConfigOptions((char *) style, styleOptionTable, tree->tkwin);
+ WFREE(style, Style);
+ return NULL;
+ }
+
+ return style;
+}
+
+void TreeStyle_ListElements(TreeCtrl *tree, TreeStyle style_)
+{
+ Style *style = (Style *) style_;
+ Tcl_Obj *listObj;
+ ElementLink *eLink;
+ int i;
+
+ if (style->numElements <= 0)
+ return;
+
+ listObj = Tcl_NewListObj(0, NULL);
+ for (i = 0; i < style->numElements; i++)
+ {
+ eLink = &style->elements[i];
+ if ((style->master != NULL) && (eLink->elem->master == NULL))
+ continue;
+ Tcl_ListObjAppendElement(tree->interp, listObj,
+ Element_ToObj(eLink->elem));
+ }
+ Tcl_SetObjResult(tree->interp, listObj);
+}
+
+static int StyleLayoutCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) clientData;
+ Style *style;
+ Element *elem;
+ ElementLink *eLink;
+ int i, index, pad;
+ static CONST char *optionNames[] = { "-padw", "-padn", "-pade",
+ "-pads", "-ipadw", "-ipadn", "-ipade",
+ "-ipads", "-expand", "-union", "-detach", "-iexpand",
+ "-squeeze", (char *) NULL };
+ enum { OPTION_PADLEFT, OPTION_PADTOP, OPTION_PADRIGHT,
+ OPTION_PADBOTTOM, OPTION_iPADLEFT, OPTION_iPADTOP,
+ OPTION_iPADRIGHT, OPTION_iPADBOTTOM, OPTION_EXPAND,
+ OPTION_UNION, OPTION_DETACH, OPTION_iEXPAND, OPTION_SQUEEZE };
+
+ if (objc < 5)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "name element ?option? ?value? ?option value ...?");
+ return TCL_ERROR;
+ }
+
+ if (TreeStyle_FromObj(tree, objv[3], (TreeStyle *) &style) != TCL_OK)
+ return TCL_ERROR;
+
+ if (Element_FromObj(tree, objv[4], &elem) != TCL_OK)
+ return TCL_ERROR;
+
+ eLink = Style_FindElem(tree, style, elem, NULL);
+ 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)
+ {
+ char flags[4];
+ int n;
+ Tcl_Obj *listObj = Tcl_NewListObj(0, NULL);
+ Tcl_Obj *unionObj = Tcl_NewListObj(0, NULL);
+
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-padw", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(eLink->ePad[LEFT]));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-padn", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(eLink->ePad[TOP]));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-pade", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(eLink->ePad[RIGHT]));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-pads", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(eLink->ePad[BOTTOM]));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-ipadw", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(eLink->iPad[LEFT]));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-ipadn", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(eLink->iPad[TOP]));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-ipade", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(eLink->iPad[RIGHT]));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-ipads", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewIntObj(eLink->iPad[BOTTOM]));
+
+ 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';
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-expand", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(flags, n));
+
+ n = 0;
+ 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';
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-iexpand", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(flags, n));
+
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-detach", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj((eLink->flags & ELF_DETACH) ? "yes" : "no", -1));
+
+ n = 0;
+ if (eLink->flags & ELF_SQUEEZE_X) flags[n++] = 'x';
+ if (eLink->flags & ELF_SQUEEZE_Y) flags[n++] = 'y';
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-squeeze", -1));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj(flags, n));
+
+ for (i = 0; i < eLink->onionCount; i++)
+ Tcl_ListObjAppendElement(interp, unionObj,
+ Element_ToObj(style->elements[eLink->onion[i]].elem));
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewStringObj("-union", -1));
+ Tcl_ListObjAppendElement(interp, listObj, unionObj);
+
+ Tcl_SetObjResult(interp, listObj);
+ return TCL_OK;
+ }
+
+ /* T style layout S E option */
+ if (objc == 6)
+ {
+ Tcl_Obj *objPtr = NULL;
+
+ if (Tcl_GetIndexFromObj(interp, objv[5], optionNames, "option",
+ 0, &index) != TCL_OK)
+ return TCL_ERROR;
+ switch (index)
+ {
+ case OPTION_PADLEFT:
+ case OPTION_PADTOP:
+ case OPTION_PADRIGHT:
+ case OPTION_PADBOTTOM:
+ {
+ objPtr = Tcl_NewIntObj(eLink->ePad[index - OPTION_PADLEFT]);
+ break;
+ }
+ case OPTION_iPADLEFT:
+ case OPTION_iPADTOP:
+ case OPTION_iPADRIGHT:
+ case OPTION_iPADBOTTOM:
+ {
+ objPtr = Tcl_NewIntObj(eLink->iPad[index - OPTION_iPADLEFT]);
+ break;
+ }
+ case OPTION_DETACH:
+ {
+ objPtr = Tcl_NewBooleanObj(eLink->flags & ELF_DETACH);
+ break;
+ }
+ 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)
+ objPtr = Tcl_NewStringObj(flags, n);
+ break;
+ }
+ case OPTION_iEXPAND:
+ {
+ char flags[4];
+ int n = 0;
+
+ 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)
+ objPtr = Tcl_NewStringObj(flags, n);
+ break;
+ }
+ 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)
+ objPtr = Tcl_NewStringObj(flags, n);
+ break;
+ }
+ case OPTION_UNION:
+ {
+ int i;
+
+ if (eLink->onionCount == 0)
+ break;
+ objPtr = Tcl_NewListObj(0, NULL);
+ for (i = 0; i < eLink->onionCount; i++)
+ Tcl_ListObjAppendElement(interp, objPtr,
+ Element_ToObj(style->elements[eLink->onion[i]].elem));
+ break;
+ }
+ }
+ if (objPtr != NULL)
+ Tcl_SetObjResult(interp, objPtr);
+ return TCL_OK;
+ }
+
+ for (i = 5; i < objc; i += 2)
+ {
+ if (i + 2 > objc)
+ {
+ FormatResult(interp, "value for \"%s\" missing",
+ Tcl_GetString(objv[i]));
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIndexFromObj(interp, objv[i], optionNames, "option",
+ 0, &index) != TCL_OK)
+ {
+ return TCL_ERROR;
+ }
+ switch (index)
+ {
+ case OPTION_PADLEFT:
+ case OPTION_PADTOP:
+ case OPTION_PADRIGHT:
+ case OPTION_PADBOTTOM:
+ {
+ if (Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], &pad) != TCL_OK)
+ return TCL_ERROR;
+ eLink->ePad[index - OPTION_PADLEFT] = pad;
+ break;
+ }
+ case OPTION_iPADLEFT:
+ case OPTION_iPADTOP:
+ case OPTION_iPADRIGHT:
+ case OPTION_iPADBOTTOM:
+ {
+ if (Tk_GetPixelsFromObj(interp, tree->tkwin, objv[i + 1], &pad) != TCL_OK)
+ return TCL_ERROR;
+ eLink->iPad[index - OPTION_iPADLEFT] = pad;
+ break;
+ }
+ case OPTION_DETACH:
+ {
+ int detach;
+ if (Tcl_GetBooleanFromObj(interp, objv[i + 1], &detach) != TCL_OK)
+ return TCL_ERROR;
+ if (detach)
+ eLink->flags |= ELF_DETACH;
+ else
+ eLink->flags &= ~ELF_DETACH;
+ break;
+ }
+ case OPTION_EXPAND:
+ {
+ char *expand;
+ int len, k;
+ expand = Tcl_GetStringFromObj(objv[i + 1], &len);
+ eLink->flags &= ~ELF_eEXPAND;
+ for (k = 0; k < len; k++)
+ {
+ switch (expand[k])
+ {
+ case 'w': eLink->flags |= ELF_eEXPAND_W; break;
+ case 'n': eLink->flags |= ELF_eEXPAND_N; break;
+ case 'e': eLink->flags |= ELF_eEXPAND_E; break;
+ case 's': eLink->flags |= ELF_eEXPAND_S; break;
+ }
+ }
+ break;
+ }
+ case OPTION_iEXPAND:
+ {
+ char *expand;
+ int len, k;
+ expand = Tcl_GetStringFromObj(objv[i + 1], &len);
+ eLink->flags &= ~ELF_iEXPAND;
+ for (k = 0; k < len; k++)
+ {
+ switch (expand[k])
+ {
+ case 'w': eLink->flags |= ELF_iEXPAND_W; break;
+ case 'n': eLink->flags |= ELF_iEXPAND_N; break;
+ case 'e': eLink->flags |= ELF_iEXPAND_E; break;
+ case 's': eLink->flags |= ELF_iEXPAND_S; break;
+ }
+ }
+ break;
+ }
+ case OPTION_SQUEEZE:
+ {
+ char *string;
+ int len, k;
+ string = Tcl_GetStringFromObj(objv[i + 1], &len);
+ eLink->flags &= ~(ELF_SQUEEZE_X | ELF_SQUEEZE_Y);
+ for (k = 0; k < len; k++)
+ {
+ switch (string[k])
+ {
+ case 'x': eLink->flags |= ELF_SQUEEZE_X; break;
+ case 'y': eLink->flags |= ELF_SQUEEZE_Y; break;
+ }
+ }
+ break;
+ }
+ case OPTION_UNION:
+ {
+ int objc1;
+ Tcl_Obj **objv1;
+ int j, k, n, *onion, count = 0;
+
+ if (Tcl_ListObjGetElements(interp, objv[i + 1],
+ &objc1, &objv1) != TCL_OK)
+ return TCL_ERROR;
+ if (objc1 == 0)
+ {
+ if (eLink->onion != NULL)
+ {
+ wipefree((char *) eLink->onion,
+ sizeof(int) * eLink->onionCount);
+ eLink->onionCount = 0;
+ eLink->onion = NULL;
+ }
+ break;
+ }
+ onion = (int *) ckalloc(sizeof(int) * objc1);
+ for (j = 0; j < objc1; j++)
+ {
+ Element *elem2;
+ ElementLink *eLink2;
+
+ if (Element_FromObj(tree, objv1[j], &elem2) != TCL_OK)
+ return TCL_ERROR;
+
+ eLink2 = Style_FindElem(tree, style, elem2, &n);
+ if (eLink2 == NULL)
+ {
+ ckfree((char *) onion);
+ FormatResult(interp,
+ "style %s does not use element %s",
+ style->name, elem2->name);
+ return TCL_ERROR;
+ }
+ if (eLink == eLink2)
+ {
+ ckfree((char *) onion);
+ FormatResult(interp,
+ "element %s can't form union with itself",
+ elem2->name);
+ return TCL_ERROR;
+ }
+ /* Silently ignore duplicates */
+ for (k = 0; k < count; k++)
+ {
+ if (onion[k] == n)
+ break;
+ }
+ if (k < count)
+ continue;
+ onion[count++] = n;
+ }
+ if (eLink->onion != NULL)
+ wipefree((char *) eLink->onion,
+ sizeof(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;
+ }
+ }
+ }
+ Style_Changed(tree, style);
+ return TCL_OK;
+}
+
+int TreeStyleCmd(ClientData clientData, Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[])
+{
+ TreeCtrl *tree = (TreeCtrl *) 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;
+
+ 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;
+ Style *style;
+
+ if (objc != 5)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "name option");
+ return TCL_ERROR;
+ }
+ if (TreeStyle_FromObj(tree, objv[3], (TreeStyle *) &style) != TCL_OK)
+ return TCL_ERROR;
+ resultObjPtr = Tk_GetOptionValue(interp, (char *) style,
+ styleOptionTable, objv[4], tree->tkwin);
+ if (resultObjPtr == NULL)
+ return TCL_ERROR;
+ Tcl_SetObjResult(interp, resultObjPtr);
+ break;
+ }
+
+ case COMMAND_CONFIGURE:
+ {
+ Tcl_Obj *resultObjPtr = NULL;
+ Style *style;
+
+ if (objc < 4)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "name ?option? ?value option value...?");
+ return TCL_ERROR;
+ }
+ if (TreeStyle_FromObj(tree, objv[3], (TreeStyle *) &style) != TCL_OK)
+ return TCL_ERROR;
+ if (objc <= 5)
+ {
+ resultObjPtr = Tk_GetOptionInfo(interp, (char *) style,
+ 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,
+ 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;
+ Style *style;
+
+ 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:
+ {
+ Style *style;
+ 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], (TreeStyle *) &style) != TCL_OK)
+ return TCL_ERROR;
+ Style_Deleted(tree, style);
+ TreeStyle_FreeResources(tree, (TreeStyle) style);
+ }
+ break;
+ }
+
+ /* T style elements S ?{E ...}? */
+ case COMMAND_ELEMENTS:
+ {
+ Style *style;
+ Element *elem, **elemList = NULL;
+ int i, j, count = 0, map[20];
+ int listObjc;
+ Tcl_Obj **listObjv;
+
+ if (objc < 4 || objc > 5)
+ {
+ Tcl_WrongNumArgs(interp, 3, objv, "name ?element element...?");
+ return TCL_ERROR;
+ }
+ if (TreeStyle_FromObj(tree, objv[3], (TreeStyle *) &style) != TCL_OK)
+ return TCL_ERROR;
+ if (objc == 5)
+ {
+ if (Tcl_ListObjGetElements(interp, objv[4], &listObjc, &listObjv) != TCL_OK)
+ return TCL_ERROR;
+ if (listObjc > 0)
+ elemList = (Element **) ckalloc(sizeof(Element *) * listObjc);
+ for (i = 0; i < listObjc; i++)
+ {
+ if (Element_FromObj(tree, listObjv[i], &elem) != TCL_OK)
+ {
+ 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;
+ }
+
+ 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);
+ 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;
+ TreeStyle style;
+
+ listObj = Tcl_NewListObj(0, NULL);
+ hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search);
+ while (hPtr != NULL)
+ {
+ style = (TreeStyle) Tcl_GetHashValue(hPtr);
+ Tcl_ListObjAppendElement(interp, listObj,
+ TreeStyle_ToObj(style));
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ Tcl_SetObjResult(interp, listObj);
+ break;
+ }
+ }
+ return TCL_OK;
+}
+
+char *TreeStyle_Identify(StyleDrawArgs *drawArgs, int x, int y)
+{
+ TreeCtrl *tree = drawArgs->tree;
+ Style *style = (Style *) drawArgs->style;
+ int state = drawArgs->state;
+ ElementLink *eLink;
+ int i;
+ struct Layout layouts[20];
+
+ if (style->neededWidth == -1)
+ {
+ Style_NeededSize(tree, style, state, &style->neededWidth,
+ &style->neededHeight, FALSE);
+ Style_NeededSize(tree, style, state, &style->minWidth,
+ &style->minHeight, TRUE);
+ }
+ if (drawArgs->width < style->minWidth)
+ drawArgs->width = style->minWidth;
+ if (drawArgs->height < style->minHeight)
+ drawArgs->height = style->minHeight;
+
+ x -= drawArgs->x;
+ Style_DoLayout(drawArgs, layouts, __FUNCTION__);
+
+ for (i = style->numElements - 1; i >= 0; i--)
+ {
+ struct Layout *layout = &layouts[i];
+ eLink = layout->eLink;
+ if ((x >= layout->x + layout->ePad[LEFT]) && (x < layout->x + layout->ePad[LEFT] + layout->iWidth) &&
+ (y >= layout->y + layout->ePad[TOP]) && (y < layout->y + layout->ePad[TOP] + layout->iHeight))
+ {
+ return (char *) eLink->elem->name;
+ }
+ }
+ return NULL;
+}
+
+void TreeStyle_Identify2(StyleDrawArgs *drawArgs,
+ int x1, int y1, int x2, int y2, Tcl_Obj *listObj)
+{
+ TreeCtrl *tree = drawArgs->tree;
+ Style *style = (Style *) drawArgs->style;
+ int state = drawArgs->state;
+ ElementLink *eLink;
+ int i;
+ struct Layout layouts[20];
+
+ if (style->neededWidth == -1)
+ {
+ Style_NeededSize(tree, style, state, &style->neededWidth,
+ &style->neededHeight, FALSE);
+ Style_NeededSize(tree, style, state, &style->minWidth,
+ &style->minHeight, TRUE);
+ }
+ if (drawArgs->width < style->minWidth)
+ drawArgs->width = style->minWidth;
+ if (drawArgs->height < style->minHeight)
+ drawArgs->height = style->minHeight;
+
+ Style_DoLayout(drawArgs, layouts, __FUNCTION__);
+
+ for (i = style->numElements - 1; i >= 0; i--)
+ {
+ struct Layout *layout = &layouts[i];
+ eLink = layout->eLink;
+ if ((drawArgs->x + layout->x + layout->ePad[LEFT] < x2) &&
+ (drawArgs->x + layout->x + layout->ePad[LEFT] + layout->iWidth > x1) &&
+ (drawArgs->y + layout->y + layout->ePad[TOP] < y2) &&
+ (drawArgs->y + layout->y + layout->ePad[TOP] + layout->iHeight > y1))
+ {
+ Tcl_ListObjAppendElement(drawArgs->tree->interp, listObj,
+ Tcl_NewStringObj(eLink->elem->name, -1));
+ }
+ }
+}
+
+int TreeStyle_Remap(TreeCtrl *tree, TreeStyle styleFrom_, TreeStyle styleTo_, int objc, Tcl_Obj *CONST objv[])
+{
+ Style *styleFrom = (Style *) styleFrom_;
+ Style *styleTo = (Style *) styleTo_;
+ int i, indexFrom, indexTo, map[20];
+ ElementLink *eLink;
+ Element *elemFrom, *elemTo, *elemMap[20];
+
+ /* 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;
+
+ for (i = 0; i < styleFrom->numElements; i++)
+ map[i] = -1;
+
+ for (i = 0; i < objc; i += 2)
+ {
+ /* Get the old-style element */
+ if (Element_FromObj(tree, objv[i], &elemFrom) != TCL_OK)
+ return TCL_ERROR;
+
+ /* Verify the old style uses the element */
+ eLink = Style_FindElem(tree, styleFrom->master, elemFrom, &indexFrom);
+ if (eLink == NULL)
+ {
+ FormatResult(tree->interp, "style %s does not use element %s",
+ styleFrom->name, elemFrom->name);
+ return TCL_ERROR;
+ }
+
+ /* Get the new-style element */
+ if (Element_FromObj(tree, objv[i + 1], &elemTo) != TCL_OK)
+ return TCL_ERROR;
+
+ /* Verify the new style uses the element */
+ eLink = Style_FindElem(tree, styleTo, elemTo, &indexTo);
+ if (eLink == NULL)
+ {
+ FormatResult(tree->interp, "style %s does not use element %s",
+ styleTo->name, elemTo->name);
+ return TCL_ERROR;
+ }
+
+ /* 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);
+ return TCL_ERROR;
+ }
+
+ /* 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 < styleFrom->numElements; 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 (styleFrom->numElements != styleTo->numElements)
+ {
+ if (styleFrom->numElements > 0)
+ wipefree((char *) styleFrom->elements, sizeof(ElementLink) *
+ styleFrom->numElements);
+ styleFrom->elements = (ElementLink *) ckalloc(sizeof(ElementLink) *
+ styleTo->numElements);
+ memset(styleFrom->elements, '\0', sizeof(ElementLink) * styleTo->numElements);
+ }
+ for (i = 0; i < styleTo->numElements; i++)
+ {
+ styleFrom->elements[i].elem = styleTo->elements[i].elem;
+ styleFrom->elements[i].neededWidth = -1;
+ styleFrom->elements[i].neededHeight = -1;
+ }
+ for (i = 0; i < styleFrom->numElements; i++)
+ {
+ indexTo = map[i];
+ if (indexTo != -1)
+ styleFrom->elements[indexTo].elem = elemMap[i];
+ }
+ styleFrom->name = styleTo->name;
+ styleFrom->master = styleTo;
+ styleFrom->neededWidth = styleFrom->neededHeight = -1;
+ styleFrom->numElements = styleTo->numElements;
+
+ return TCL_OK;
+}
+
+int TreeStyle_GetSortData(TreeCtrl *tree, TreeStyle style_, int type, long *lv, double *dv, char **sv)
+{
+ Style *style = (Style *) style_;
+ ElementLink *eLink;
+ int i;
+
+ for (i = 0; i < style->numElements; i++)
+ {
+ eLink = &style->elements[i];
+ if (eLink->elem->typePtr == &elemTypeText)
+ return Element_GetSortData(tree, eLink->elem, type, lv, dv, sv);
+ }
+
+ return TCL_ERROR;
+}
+
+int TreeStyle_GetElemRects(StyleDrawArgs *drawArgs, int objc,
+ Tcl_Obj *CONST objv[], XRectangle rects[20])
+{
+ Style *style = (Style *) drawArgs->style;
+ Style *master = style->master ? style->master : style;
+ int i, j, count = 0;
+ struct Layout layouts[20];
+ Element *elems[20];
+ ElementLink *eLink;
+
+ for (j = 0; j < objc; j++)
+ {
+ if (Element_FromObj(drawArgs->tree, objv[j], &elems[j]) != TCL_OK)
+ return -1;
+
+ eLink = Style_FindElem(drawArgs->tree, master, elems[j], NULL);
+ if (eLink == NULL)
+ {
+ FormatResult(drawArgs->tree->interp,
+ "style %s does not use element %s",
+ style->name, elems[j]->name);
+ return -1;
+ }
+ }
+
+ if (drawArgs->width < style->minWidth)
+ drawArgs->width = style->minWidth;
+ if (drawArgs->height < style->minHeight)
+ drawArgs->height = style->minHeight;
+
+ Style_DoLayout(drawArgs, layouts, __FUNCTION__);
+
+ for (i = style->numElements - 1; i >= 0; i--)
+ {
+ struct Layout *layout = &layouts[i];
+ 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->ePad[LEFT];
+ rects[count].y = drawArgs->y + layout->y + layout->ePad[TOP];
+ rects[count].width = layout->iWidth;
+ rects[count].height = layout->iHeight;
+ count++;
+ }
+ return count;
+}
+
+int TreeStyle_ChangeState(TreeCtrl *tree, TreeStyle style_, int state1, int state2)
+{
+ Style *style = (Style *) style_;
+ ElementLink *eLink;
+ ElementArgs args;
+ int i, eMask, mask = 0;
+
+ args.tree = tree;
+ args.states.state1 = state1;
+ args.states.state2 = state2;
+
+ for (i = 0; i < style->numElements; i++)
+ {
+ eLink = &style->elements[i];
+ args.elem = eLink->elem;
+ eMask = (*eLink->elem->typePtr->stateProc)(&args);
+ if (eMask)
+ {
+ if (eMask & CS_LAYOUT)
+ eLink->neededWidth = eLink->neededHeight = -1;
+ mask |= eMask;
+ }
+ }
+
+ if (mask & CS_LAYOUT)
+ style->neededWidth = style->neededHeight = -1;
+
+ return mask;
+}
+
+void TreeStyle_UndefineState(TreeCtrl *tree, int state)
+{
+ TreeItem item;
+ TreeItemColumn column;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ ElementLink *eLink;
+ int i, columnIndex;
+ ElementArgs args;
+ int eMask, cMask, iMask;
+ int updateDInfo = FALSE;
+
+ args.tree = tree;
+ args.state = state;
+
+ hPtr = Tcl_FirstHashEntry(&tree->itemHash, &search);
+ while (hPtr != NULL)
+ {
+ item = (TreeItem) Tcl_GetHashValue(hPtr);
+ column = TreeItem_GetFirstColumn(tree, item);
+ columnIndex = 0;
+ iMask = 0;
+ args.states.state1 = TreeItem_GetState(tree, item);
+ args.states.state2 = args.states.state1 & ~state;
+ while (column != NULL)
+ {
+ Style *style = (Style *) TreeItemColumn_GetStyle(tree, column);
+ if (style != NULL)
+ {
+ cMask = 0;
+ for (i = 0; i < style->numElements; i++)
+ {
+ eLink = &style->elements[i];
+ args.elem = eLink->elem;
+ eMask = (*args.elem->typePtr->stateProc)(&args);
+ if (eMask & CS_LAYOUT)
+ eLink->neededWidth = eLink->neededHeight = -1;
+ cMask |= eMask;
+ if (eLink->elem->master == NULL)
+ (*args.elem->typePtr->undefProc)(&args);
+ }
+ if (cMask & CS_LAYOUT)
+ {
+ style->neededWidth = style->neededHeight = -1;
+ Tree_InvalidateColumnWidth(tree, columnIndex);
+ TreeItemColumn_InvalidateSize(tree, column);
+ }
+ iMask |= cMask;
+ }
+ columnIndex++;
+ column = TreeItemColumn_GetNext(tree, column);
+ }
+ if (iMask & CS_LAYOUT)
+ {
+ TreeItem_InvalidateHeight(tree, item);
+ updateDInfo = TRUE;
+ }
+ if (iMask & CS_DISPLAY)
+ Tree_InvalidateItemDInfo(tree, item, NULL);
+ TreeItem_Undefine(tree, item, state);
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ if (updateDInfo)
+ Tree_DInfoChanged(tree, DINFO_REDO_RANGES);
+
+ hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search);
+ while (hPtr != NULL)
+ {
+ args.elem = (Element *) Tcl_GetHashValue(hPtr);
+ (*args.elem->typePtr->undefProc)(&args);
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+}
+
+int TreeStyle_Init(Tcl_Interp *interp)
+{
+ ElementType *typePtr;
+
+ styleOptionTable = Tk_CreateOptionTable(interp, styleOptionSpecs);
+
+ elementTypeList = &elemTypeBitmap;
+ elemTypeBitmap.next = &elemTypeBorder;
+ elemTypeBorder.next = &elemTypeImage;
+ elemTypeImage.next = &elemTypeRect;
+ elemTypeRect.next = &elemTypeText;
+ elemTypeText.next = NULL;
+
+ for (typePtr = elementTypeList;
+ typePtr != NULL;
+ typePtr = typePtr->next)
+ {
+ typePtr->optionTable = Tk_CreateOptionTable(interp,
+ typePtr->optionSpecs);
+ }
+
+ return TCL_OK;
+}
+
+void TreeStyle_Free(TreeCtrl *tree)
+{
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ Element *elem;
+ Style *style;
+
+ while (1)
+ {
+ hPtr = Tcl_FirstHashEntry(&tree->styleHash, &search);
+ if (hPtr == NULL)
+ break;
+ style = (Style *) Tcl_GetHashValue(hPtr);
+ TreeStyle_FreeResources(tree, (TreeStyle) style);
+ }
+
+ while (1)
+ {
+ hPtr = Tcl_FirstHashEntry(&tree->elementHash, &search);
+ if (hPtr == NULL)
+ break;
+ elem = (Element *) Tcl_GetHashValue(hPtr);
+ Element_FreeResources(tree, elem);
+ }
+
+ Tcl_DeleteHashTable(&tree->elementHash);
+ Tcl_DeleteHashTable(&tree->styleHash);
+}
+
+
diff --git a/generic/tkTreeUtils.c b/generic/tkTreeUtils.c
new file mode 100644
index 0000000..9c8b482
--- /dev/null
+++ b/generic/tkTreeUtils.c
@@ -0,0 +1,877 @@
+#include "tkTreeCtrl.h"
+#ifdef WIN32
+#include "tkWinInt.h"
+#endif
+
+void wipefree(char *memPtr, int size)
+{
+ memset(memPtr, 0xAA, size);
+ ckfree(memPtr);
+}
+
+void FormatResult(Tcl_Interp *interp, char *fmt, ...)
+{
+ va_list ap;
+ char buf[256];
+
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+}
+
+int Ellipsis(Tk_Font tkfont, char *string, int numBytes, int *maxPixels, char *ellipsis)
+{
+ char staticStr[256], *tmpStr = staticStr;
+ int pixels, pixelsTest, bytesThatFit, bytesTest;
+ int ellipsisNumBytes = strlen(ellipsis);
+
+ bytesThatFit = Tk_MeasureChars(tkfont, string, numBytes, *maxPixels, 0,
+ &pixels);
+
+ /* The whole string fits. No ellipsis needed */
+ if (bytesThatFit == numBytes)
+ {
+ (*maxPixels) = pixels;
+ return numBytes;
+ }
+
+ if (bytesThatFit <= 1)
+ {
+ (*maxPixels) = pixels;
+ return -bytesThatFit;
+ }
+
+ /* Strip off one character at a time, adding ellipsis, until it fits */
+ bytesTest = 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 = Tcl_UtfPrev(string + bytesTest, string) - string;
+ }
+
+ /* No single char + ellipsis fits. Return number of chars that fit */
+ /* Negative tells caller to not add ellipsis */
+ (*maxPixels) = pixels;
+ if (tmpStr != staticStr)
+ ckfree(tmpStr);
+ return -bytesThatFit;
+}
+
+/* Draws a horizontal 1-pixel tall dotted line */
+void HDotLine(TreeCtrl *tree, Drawable drawable, GC gc, int x1, int y1, int x2)
+{
+#ifdef WIN32
+ 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_NOT); */
+
+ pen = CreatePen(PS_SOLID, 1, gc->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);
+#else
+ int nw;
+ int wx = x1 + tree->drawableXOrigin;
+ int wy = y1 + tree->drawableYOrigin;
+
+ nw = !(wx & 1) == !(wy & 1);
+ for (x1 += !nw; x1 < x2; x1 += 2)
+ {
+ XDrawPoint(tree->display, drawable, gc, x1, y1);
+ }
+#endif
+}
+
+/* Draws a vertical 1-pixel wide dotted line */
+void VDotLine(TreeCtrl *tree, Drawable drawable, GC gc, int x1, int y1, int y2)
+{
+#ifdef WIN32
+ 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_NOT); */
+
+ pen = CreatePen(PS_SOLID, 1, gc->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);
+#else
+ int nw;
+ int wx = x1 + tree->drawableXOrigin;
+ int wy = y1 + tree->drawableYOrigin;
+
+ nw = !(wx & 1) == !(wy & 1);
+ for (y1 += !nw; y1 < y2; y1 += 2)
+ {
+ XDrawPoint(tree->display, drawable, gc, x1, y1);
+ }
+#endif
+}
+
+/* Draws 0 or more sides of a rectangle, dot-on dot-off, XOR style */
+void DrawActiveOutline(TreeCtrl *tree, Drawable drawable, int x, int y, int width, int height, int open)
+{
+#ifdef WIN32
+ int wx = x + tree->drawableXOrigin;
+ int wy = y + tree->drawableYOrigin;
+ int w = !(open & 0x01);
+ int n = !(open & 0x02);
+ int e = !(open & 0x04);
+ int s = !(open & 0x08);
+ 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);
+#else
+ int wx = x + tree->drawableXOrigin;
+ int wy = y + tree->drawableYOrigin;
+ int w = !(open & 0x01);
+ int n = !(open & 0x02);
+ int e = !(open & 0x04);
+ int s = !(open & 0x08);
+ 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 = GXinvert;
+ gcMask = GCFunction;
+ gc = Tk_GetGC(tree->tkwin, 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);
+ }
+ }
+
+ Tk_FreeGC(tree->display, gc);
+#endif
+}
+
+void DotRect(TreeCtrl *tree, Drawable drawable, int x, int y, int width, int height)
+{
+ DrawActiveOutline(tree, drawable, x, y, width, height, 0);
+}
+
+struct DotStatePriv
+{
+ TreeCtrl *tree;
+ Drawable drawable;
+#ifdef WIN32
+ HDC dc;
+ TkWinDCState dcState;
+ HRGN rgn;
+#else
+ GC gc;
+ TkRegion rgn;
+#endif
+};
+
+void DotRect_Setup(TreeCtrl *tree, Drawable drawable, DotState *p)
+{
+ struct DotStatePriv *dotState = (struct DotStatePriv *) p;
+#ifdef WIN32
+#else
+ XGCValues gcValues;
+ unsigned long mask;
+ XRectangle xrect;
+#endif
+
+ if (sizeof(*dotState) > sizeof(*p))
+ panic("DotRect_Setup: DotState hack is too small");
+
+ dotState->tree = tree;
+ dotState->drawable = drawable;
+#ifdef WIN32
+ dotState->dc = TkWinGetDrawableDC(tree->display, drawable, &dotState->dcState);
+
+ /* XOR drawing */
+ SetROP2(dotState->dc, R2_NOT);
+
+ /* Keep drawing inside the contentbox */
+ dotState->rgn = CreateRectRgn(
+ tree->inset,
+ tree->inset + Tree_HeaderHeight(tree),
+ Tk_Width(tree->tkwin) - tree->inset,
+ Tk_Height(tree->tkwin) - tree->inset);
+ SelectClipRgn(dotState->dc, dotState->rgn);
+#else
+ 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 = TkCreateRegion();
+ xrect.x = tree->inset;
+ xrect.y = tree->inset + Tree_HeaderHeight(tree);
+ xrect.width = Tk_Width(tree->tkwin) - tree->inset - xrect.x;
+ xrect.height = Tk_Height(tree->tkwin) - tree->inset - xrect.y;
+ TkUnionRectWithRegion(&xrect, dotState->rgn, dotState->rgn);
+ TkSetRegion(tree->display, dotState->gc, dotState->rgn);
+#endif
+}
+
+void DotRect_Draw(DotState *p, int x, int y, int width, int height)
+{
+ struct DotStatePriv *dotState = (struct DotStatePriv *) p;
+#ifdef WIN32
+#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
+#else
+ XDrawRectangle(dotState->tree->display, dotState->drawable, dotState->gc,
+ x, y, width - 1, height - 1);
+#endif
+}
+
+void DotRect_Restore(DotState *p)
+{
+ struct DotStatePriv *dotState = (struct DotStatePriv *) p;
+#ifdef WIN32
+ SelectClipRgn(dotState->dc, NULL);
+ DeleteObject(dotState->rgn);
+ TkWinReleaseDrawableDC(dotState->drawable, dotState->dc, &dotState->dcState);
+#else
+ XSetClipMask(dotState->tree->display, dotState->gc, None);
+ Tk_FreeGC(dotState->tree->display, dotState->gc);
+#endif
+}
+
+/*
+ * 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).
+ */
+
+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. */
+ int ellipsis; /* TRUE if adding "..." */
+} 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. */
+ LayoutChunk chunks[1]; /* Array of chunks. The actual size will
+ * * be maxChunks. THIS FIELD MUST BE THE LAST
+ * * IN THE STRUCTURE. */
+} LayoutInfo;
+
+static LayoutChunk *NewChunk(LayoutInfo **layoutPtrPtr, int *maxPtr,
+ CONST char *start, int numBytes, int curX, int newX, int y)
+{
+ LayoutInfo *layoutPtr;
+ LayoutChunk *chunkPtr;
+ int maxChunks, numChars;
+ size_t s;
+
+ layoutPtr = *layoutPtrPtr;
+ 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;
+ }
+ 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 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;
+
+ maxChunks = 1;
+
+ layoutPtr = (LayoutInfo *) ckalloc(sizeof(LayoutInfo) + (maxChunks -
+ 1) * sizeof(LayoutChunk));
+ layoutPtr->tkfont = tkfont;
+ layoutPtr->string = string;
+ layoutPtr->numChunks = 0;
+ layoutPtr->numLines = 0;
+
+ baseline = fm.ascent;
+ maxWidth = 0;
+
+ curX = 0;
+
+ 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, special - start,
+ wrapLength - curX, flags, &newX);
+ newX += curX;
+ flags &= ~TK_AT_LEAST_ONE;
+ if (bytesThisChunk > 0)
+ {
+ chunkPtr = NewChunk(&layoutPtr, &maxChunks, start,
+ bytesThisChunk, curX, newX, baseline);
+ start += bytesThisChunk;
+ curX = newX;
+ }
+ }
+
+ if ((start == special) && (special < end))
+ {
+ chunkPtr = NULL;
+ if (*special == '\t')
+ {
+ newX = curX + tabWidth;
+ newX -= newX % tabWidth;
+ NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX,
+ baseline)->numDisplayChars = -1;
+ start++;
+ if ((start < end) && ((wrapLength <= 0) ||
+ (newX <= wrapLength)))
+ {
+ curX = newX;
+ flags &= ~TK_AT_LEAST_ONE;
+ continue;
+ }
+ }
+ else
+ {
+ NewChunk(&layoutPtr, &maxChunks, start, 1, curX, curX,
+ 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 = 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));
+
+ curX = 0;
+ baseline += height;
+
+ if ((maxLines > 0) && (++layoutPtr->numLines >= maxLines))
+ break;
+ }
+
+ if (start >= end)
+ if ((layoutPtr->numChunks > 0) && !(flags & TK_IGNORE_NEWLINES))
+ {
+ if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == '\n')
+ {
+ chunkPtr =
+ NewChunk(&layoutPtr, &maxChunks, start, 0, curX, curX,
+ baseline);
+ chunkPtr->numDisplayChars = -1;
+ Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));
+ baseline += height;
+ }
+ }
+
+#if 1
+ /* Fiddle with chunks on the last line to add ellipsis if there is some
+ * text remaining */
+ if ((start < end) && (layoutPtr->numChunks > 0))
+ {
+ 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;
+
+ newX = chunkPtr->totalWidth - 1;
+ bytesThisChunk = Ellipsis(tkfont, (char *) chunkPtr->start,
+ chunkPtr->numBytes, &newX, "...");
+ if (bytesThisChunk > 0)
+ {
+ chunkPtr->numBytes = bytesThisChunk;
+ chunkPtr->numChars = Tcl_NumUtfChars(chunkPtr->start, bytesThisChunk);
+ chunkPtr->numDisplayChars = chunkPtr->numChars;
+ chunkPtr->ellipsis = TRUE;
+ chunkPtr->displayWidth = newX;
+ chunkPtr->totalWidth = newX;
+ lineLengths = (int *) Tcl_DStringValue(&lineBuffer);
+ lineLengths[layoutPtr->numLines - 1] = chunkPtr->x + newX;
+ if (chunkPtr->x + newX > maxWidth)
+ maxWidth = chunkPtr->x + newX;
+ break;
+ }
+ }
+ }
+ else
+ {
+ char staticStr[256], *buf = staticStr;
+ char *ellipsis = "...";
+ int ellipsisLen = strlen(ellipsis);
+
+ 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;
+ 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;
+ }
+ chunkPtr++;
+ }
+ }
+
+ Tcl_DStringFree(&lineBuffer);
+
+ return (TextLayout) layoutPtr;
+}
+
+void TextLayout_Free(TextLayout textLayout)
+{
+ LayoutInfo *layoutPtr = (LayoutInfo *) textLayout;
+
+ ckfree((char *) layoutPtr);
+}
+
+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;
+}
+
+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. */
+)
+{
+ 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,
+ firstByte - chunkPtr->start, -1, 0, &drawX);
+ }
+ if (lastChar < numDisplayChars)
+ numDisplayChars = lastChar;
+ lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars);
+#if 1
+ if (chunkPtr->ellipsis)
+ {
+ char staticStr[256], *buf = staticStr;
+ char *ellipsis = "...";
+ int ellipsisLen = strlen(ellipsis);
+
+ if ((lastByte - firstByte) + ellipsisLen > sizeof(staticStr))
+ buf = ckalloc((lastByte - firstByte) + ellipsisLen);
+ memcpy(buf, firstByte, (lastByte - firstByte));
+ memcpy(buf + (lastByte - firstByte), ellipsis, ellipsisLen);
+ Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont,
+ buf, (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, lastByte - firstByte, x + chunkPtr->x + drawX,
+ y + chunkPtr->y);
+ }
+ firstChar -= chunkPtr->numChars;
+ lastChar -= chunkPtr->numChars;
+ if (lastChar <= 0)
+ break;
+ chunkPtr++;
+ }
+}
diff --git a/library/filelist-bindings.tcl b/library/filelist-bindings.tcl
new file mode 100644
index 0000000..f58ef82
--- /dev/null
+++ b/library/filelist-bindings.tcl
@@ -0,0 +1,788 @@
+bind TreeCtrlFileList <Double-ButtonPress-1> {
+ TreeCtrl::FileListEditCancel %W
+ TreeCtrl::DoubleButton1 %W %x %y
+}
+bind TreeCtrlFileList <Control-ButtonPress-1> {
+ set TreeCtrl::Priv(selectMode) toggle
+ TreeCtrl::FileListButton1 %W %x %y
+ break
+}
+bind TreeCtrlFileList <Shift-ButtonPress-1> {
+ set TreeCtrl::Priv(selectMode) add
+ TreeCtrl::FileListButton1 %W %x %y
+ break
+}
+bind TreeCtrlFileList <ButtonPress-1> {
+ set TreeCtrl::Priv(selectMode) set
+ TreeCtrl::FileListButton1 %W %x %y
+ break
+}
+bind TreeCtrlFileList <Button1-Motion> {
+ TreeCtrl::FileListMotion1 %W %x %y
+ break
+}
+bind TreeCtrlFileList <Button1-Leave> {
+ TreeCtrl::FileListLeave1 %W %x %y
+ break
+}
+bind TreeCtrlFileList <ButtonRelease-1> {
+ TreeCtrl::FileListRelease1 %W %x %y
+ break
+}
+
+proc TreeCtrl::FileListButton1 {T x y} {
+ variable Priv
+ focus $T
+ set id [$T identify $x $y]
+ set marquee 0
+ set Priv(buttonMode) ""
+ FileListEditCancel $T
+ # Click outside any item
+ if {$id eq ""} {
+ set marquee 1
+
+ # Click in header
+ } elseif {[lindex $id 0] eq "header"} {
+ ButtonPress1 $T $x $y
+
+ # Click in item
+ } else {
+ foreach {where item arg1 arg2 arg3 arg4} $id {}
+ switch $arg1 {
+ button -
+ line {
+ ButtonPress1 $T $x $y
+ }
+ column {
+ # Clicked in column zero
+ if {$arg2 eq 0} {
+ set ok 0
+ # Clicked an element
+ if {[llength $id] == 6} {
+ set E [lindex $id 5]
+ if {[lsearch -exact $Priv(sensitive,$T) $E] != -1} {
+ set ok 1
+ }
+ }
+ if {$ok} {
+ set Priv(drag,motion) 0
+ set Priv(drag,x) [$T canvasx $x]
+ set Priv(drag,y) [$T canvasy $y]
+ set Priv(drop) ""
+ set Priv(drag,wasSel) [$T selection includes $item]
+ set Priv(drag,E) $E
+ $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 index $item] eq ""} return
+
+ # Click selected item to drag
+ if {[$T selection includes $item]} {
+ set Priv(buttonMode) drag
+ }
+ # Clicked inside item, but outside elements
+ } else {
+ set marquee 1
+ }
+ # Clicked column > 0
+ } else {
+ set marquee 1
+ }
+ }
+ }
+ }
+ if {$marquee} {
+ set Priv(buttonMode) marquee
+ if {$Priv(selectMode) ne "set"} {
+ set Priv(selection) [$T selection get]
+ } else {
+ $T selection clear
+ set Priv(selection) {}
+ }
+ MarqueeBegin $T $x $y
+ }
+ return
+}
+proc TreeCtrl::FileListMotion1 {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Motion1 $T $x $y
+ }
+ "drag" -
+ "marquee" {
+ FileListAutoScanCheck $T $x $y
+ FileListMotion $T $x $y
+ }
+ }
+}
+proc TreeCtrl::FileListMotion {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Motion1 $T $x $y
+ }
+ "marquee" {
+ MarqueeUpdate $T $x $y
+ set select $Priv(selection)
+ set deselect {}
+
+ # Check items covered by the marquee
+ foreach list [$T marque identify] {
+ set item [lindex $list 0]
+
+ # Check covered columns in this item
+ foreach sublist [lrange $list 1 end] {
+ set column [lindex $sublist 0]
+ set ok 0
+ foreach E [lrange $sublist 1 end] {
+ if {[lsearch -exact $Priv(sensitive,$T) $E] != -1} {
+ set ok 1
+ break
+ }
+ }
+ # Some elements in column zero are covered
+ if {($column == 0) && $ok} {
+
+ # 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
+ }
+ }
+ break
+ }
+ }
+ $T selection modify $select all
+ }
+ "drag" {
+ # Detect initial mouse movement
+ if {!$Priv(drag,motion)} {
+ 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 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
+ $T notify generate <Drag-begin> -T $T
+ }
+
+ # Find the element under the cursor
+ set drop ""
+ set id [$T identify $x $y]
+ set ok 0
+ if {($id ne "") && ([lindex $id 0] eq "item") && ([llength $id] == 6)} {
+ set E [lindex $id 5]
+ if {[lsearch -exact $Priv(sensitive,$T) $E] != -1} {
+ set ok 1
+ }
+ }
+ if {$ok} {
+ set item [lindex $id 1]
+ set column [lindex $id 3]
+ if {$column == 0} {
+ # 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 {[lindex [$T item index $item] 1] < $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
+ 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 visible yes
+ }
+ }
+ return
+}
+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) {
+ "header" {
+ Leave1 $T $x $y
+ }
+ }
+ return
+}
+proc TreeCtrl::FileListRelease1 {T x y} {
+ variable Priv
+ switch $Priv(buttonMode) {
+ "resize" -
+ "header" {
+ Release1 $T $x $y
+ }
+ "marquee" {
+ AutoScanCancel $T
+ MarqueeEnd $T $x $y
+ }
+ "drag" {
+ AutoScanCancel $T
+
+ # Some dragging occurred
+ if {$Priv(drag,motion)} {
+ $T dragimage visible no
+ if {$Priv(drop) ne ""} {
+ $T selection modify {} $Priv(drop)
+ $T notify generate <Drag-receive> -T $T -I $Priv(drop) \
+ -l $Priv(selection)
+ }
+ $T notify generate <Drag-end> -T $T
+
+ } elseif {$Priv(selectMode) eq "toggle"} {
+ # don't rename
+
+ # Clicked/released a selected item, but didn't drag
+ } elseif {$Priv(drag,wasSel)} {
+ set I [$T index active]
+ set E $Priv(drag,E)
+ set S [$T item style set $I 0]
+ if {[lsearch -exact $Priv(edit,$T) $E] != -1} {
+ FileListEditCancel $T
+ set Priv(editId,$T) [after 900 [list ::TreeCtrl::FileListEdit $T $I $S $E]]
+ }
+ }
+ }
+ }
+ set Priv(buttonMode) ""
+ return
+}
+proc TreeCtrl::FileListEdit {T I S E} {
+ variable Priv
+ array unset Priv editId,$T
+ set lines [$T item element cget $I 0 $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 0] "%d %d %d %d" x1 y1 x2 y2
+ set padw [$T style layout $S $E -padw]
+ set pade [$T style layout $S $E -pade]
+ TextExpanderOpen $T $I 0 $E [expr {$x2 - $x1 - $padw - $pade}]
+
+ # Single-line edit
+ } else {
+ EntryExpanderOpen $T $I 0 $E
+ }
+ return
+}
+proc TreeCtrl::FileListEditCancel {T} {
+ variable Priv
+ if {[info exists Priv(editId,$T)]} {
+ after cancel $Priv(editId,$T)
+ array unset Priv editId,$T
+ }
+ return
+}
+
+# Same as TreeCtrl::AutoScanCheck, but calls FileListMotion and
+# FileListAutoScanCheckAux
+proc TreeCtrl::FileListAutoScanCheck {T x y} {
+ variable Priv
+ scan [$T contentbox] "%d %d %d %d" x1 y1 x2 y2
+ set margin [winfo pixels $T [$T cget -scrollmargin]]
+ if {($x < $x1 + $margin) || ($x >= $x2 - $margin) ||
+ ($y < $y1 + $margin) || ($y >= $y2 - $margin)} {
+ if {![info exists Priv(autoscan,afterId,$T)]} {
+ if {$y >= $y2 - $margin} {
+ $T yview scroll 1 units
+ set delay [$T cget -yscrolldelay]
+ } elseif {$y < $y1 + $margin} {
+ $T yview scroll -1 units
+ set delay [$T cget -yscrolldelay]
+ } elseif {$x >= $x2 - $margin} {
+ $T xview scroll 1 units
+ set delay [$T cget -xscrolldelay]
+ } elseif {$x < $x1 + $margin} {
+ $T xview scroll -1 units
+ set delay [$T cget -xscrolldelay]
+ }
+ set count [scan $delay "%d %d" d1 d2]
+ if {[info exists Priv(autoscan,scanning,$T)]} {
+ if {$count == 2} {
+ set delay $d2
+ }
+ } else {
+ if {$count == 2} {
+ set delay $d1
+ }
+ set Priv(autoscan,scanning,$T) 1
+ }
+ switch $Priv(buttonMode) {
+ "drag" -
+ "marquee" {
+ FileListMotion $T $x $y
+ }
+ }
+ set Priv(autoscan,afterId,$T) [after $delay [list TreeCtrl::FileListAutoScanCheckAux $T]]
+ }
+ return
+ }
+ AutoScanCancel $T
+ return
+}
+
+proc ::TreeCtrl::FileListAutoScanCheckAux {T} {
+ variable Priv
+ unset Priv(autoscan,afterId,$T)
+ set x [winfo pointerx $T]
+ set y [winfo pointery $T]
+ set x [expr {$x - [winfo rootx $T]}]
+ set y [expr {$y - [winfo rooty $T]}]
+ FileListAutoScanCheck $T $x $y
+ return
+}
+
+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 actual $item $column $element -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
+ if {[winfo exists $T.entry]} {
+ $T.entry delete 0 end
+ } else {
+ entry $T.entry -borderwidth 1 -highlightthickness 0 -relief solid
+
+ # Accept edit when we lose the focus
+ bind $T.entry <FocusOut> {
+ if {[winfo ismapped %W]} {
+ TreeCtrl::EntryClose [winfo parent %W] 1
+ }
+ }
+
+ # Accept edit on <Return>
+ bind $T.entry <KeyPress-Return> {
+ TreeCtrl::EntryClose [winfo parent %W] 1
+ focus $TreeCtrl::Priv(entry,[winfo parent %W],focus)
+ }
+
+ # Cancel edit on <Escape>
+ bind $T.entry <KeyPress-Escape> {
+ TreeCtrl::EntryClose [winfo parent %W] 0
+ focus $TreeCtrl::Priv(entry,[winfo parent %W],focus)
+ }
+ }
+
+ # Pesky MouseWheel
+ $T notify bind $T.entry <Scroll> {
+ TreeCtrl::EntryClose %T 0
+ focus $TreeCtrl::Priv(entry,%T,focus)
+ }
+
+ $T.entry configure -font $font
+ $T.entry insert end $text
+ $T.entry selection range 0 end
+
+ set ebw [$T.entry cget -borderwidth]
+ if 1 {
+ set ex [expr {$x - $ebw - 1}]
+ place $T.entry -x $ex -y [expr {$y - $ebw - 1}] \
+ -bordermode outside
+ } else {
+ set hw [$T cget -highlightthickness]
+ set bw [$T cget -borderwidth]
+ set ex [expr {$x - $bw - $hw - $ebw - 1}]
+ place $T.entry -x $ex -y [expr {$y - $bw - $hw - $ebw - 1}]
+ }
+
+ # 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 $T.entry -width $width
+
+ focus $T.entry
+
+ return
+}
+
+# Like EntryOpen, but Entry widget expands/shrinks during typing
+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 actual $item $column $element -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
+ if {[winfo exists $T.entry]} {
+ $T.entry delete 0 end
+ } else {
+ entry $T.entry -borderwidth 1 -highlightthickness 0 \
+ -selectborderwidth 0 -relief solid
+
+ # Accept edit when we lose the focus
+ bind $T.entry <FocusOut> {
+ if {[winfo ismapped %W]} {
+ TreeCtrl::EntryClose [winfo parent %W] 1
+ }
+ }
+
+ # Accept edit on <Return>
+ bind $T.entry <KeyPress-Return> {
+ TreeCtrl::EntryClose [winfo parent %W] 1
+ focus $TreeCtrl::Priv(entry,[winfo parent %W],focus)
+ }
+
+ # Cancel edit on <Escape>
+ bind $T.entry <KeyPress-Escape> {
+ TreeCtrl::EntryClose [winfo parent %W] 0
+ focus $TreeCtrl::Priv(entry,[winfo parent %W],focus)
+ }
+
+ # Resize as user types
+ bind $T.entry <KeyPress> {
+ after idle TreeCtrl::EntryExpanderKeypress [winfo parent %W]
+ }
+ }
+
+ # Pesky MouseWheel
+ $T notify bind $T.entry <Scroll> {
+ TreeCtrl::EntryClose %T 0
+ focus $TreeCtrl::Priv(entry,%T,focus)
+ }
+
+ $T.entry configure -font $font -background [$T cget -background]
+ $T.entry insert end $text
+ $T.entry selection range 0 end
+
+ set ebw [$T.entry cget -borderwidth]
+ set ex [expr {$x - $ebw - 1}]
+ place $T.entry -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 $T.entry -width $width
+
+ focus $T.entry
+
+ return
+}
+
+proc ::TreeCtrl::EntryClose {T accept} {
+
+ variable Priv
+
+ place forget $T.entry
+ update
+
+ if {$accept} {
+ $T notify generate <Edit-accept> -T $T -I $Priv(entry,$T,item) \
+ -C $Priv(entry,$T,column) -E $Priv(entry,$T,element) \
+ -t [$T.entry get]
+ }
+
+ $T notify bind $T.entry <Scroll> {}
+
+ return
+}
+
+proc ::TreeCtrl::EntryExpanderKeypress {T} {
+
+ variable Priv
+
+ 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
+}
+
+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 actual $item $column $element -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 Text widget if needed
+ if {[winfo exists $T.text]} {
+ $T.text delete 1.0 end
+ } else {
+ text $T.text -borderwidth 1 -highlightthickness 0 -relief solid
+
+ # Accept edit when we lose the focus
+ bind $T.text <FocusOut> {
+ if {[winfo ismapped %W]} {
+ TreeCtrl::TextClose [winfo parent %W] 1
+ }
+ }
+
+ # Accept edit on <Return>
+ bind $T.text <KeyPress-Return> {
+ TreeCtrl::TextClose [winfo parent %W] 1
+ focus $TreeCtrl::Priv(text,[winfo parent %W],focus)
+ break
+ }
+
+ # Cancel edit on <Escape>
+ bind $T.text <KeyPress-Escape> {
+ TreeCtrl::TextClose [winfo parent %W] 0
+ focus $TreeCtrl::Priv(text,[winfo parent %W],focus)
+ }
+ }
+
+ # Pesky MouseWheel
+ $T notify bind $T.text <Scroll> {
+ TreeCtrl::TextClose %T 0
+ focus $TreeCtrl::Priv(text,%T,focus)
+ }
+
+ $T.text tag configure TAG -justify [$T element cget $element -justify]
+ $T.text configure -font $font
+ $T.text insert end $text
+ $T.text tag add sel 1.0 end
+ $T.text tag add TAG 1.0 end
+
+ set tbw [$T.text cget -borderwidth]
+ set tx [expr {$x1 - $tbw - 1}]
+ place $T.text -x $tx -y [expr {$y1 - $tbw - 1}] \
+ -width [expr {$x2 - $x1 + ($tbw + 1) * 2}] \
+ -height [expr {$y2 - $y1 + ($tbw + 1) * 2}] \
+ -bordermode outside
+
+ focus $T.text
+
+ return
+}
+
+# Like TextOpen, but Text widget expands/shrinks during typing
+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 actual $item $column $element -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]
+
+ # Create the Text widget if needed
+ if {[winfo exists $T.text]} {
+ $T.text delete 1.0 end
+ } else {
+ text $T.text -borderwidth 1 -highlightthickness 0 \
+ -selectborderwidth 0 -relief solid
+
+ # Accept edit when we lose the focus
+ bind $T.text <FocusOut> {
+ if {[winfo ismapped %W]} {
+ TreeCtrl::TextClose [winfo parent %W] 1
+ }
+ }
+
+ # Accept edit on <Return>
+ bind $T.text <KeyPress-Return> {
+ TreeCtrl::TextClose [winfo parent %W] 1
+ focus $TreeCtrl::Priv(text,[winfo parent %W],focus)
+ break
+ }
+
+ # Cancel edit on <Escape>
+ bind $T.text <KeyPress-Escape> {
+ TreeCtrl::TextClose [winfo parent %W] 0
+ focus $TreeCtrl::Priv(text,[winfo parent %W],focus)
+ }
+
+ # Resize as user types
+ bind $T.text <KeyPress> {
+ after idle TreeCtrl::TextExpanderKeypress [winfo parent %W]
+ }
+ }
+
+ # Pesky MouseWheel
+ $T notify bind $T.text <Scroll> {
+ TreeCtrl::TextClose %T 0
+ focus $TreeCtrl::Priv(text,%T,focus)
+ }
+
+ $T.text tag configure TAG -justify $justify
+ $T.text configure -font $font -background [$T cget -background]
+ $T.text insert end $text
+ $T.text tag add sel 1.0 end
+ $T.text 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 [$T.text cget -borderwidth]
+ set tx [expr {$x1 - $tbw - 1}]
+ place $T.text -x $tx -y [expr {$y1 - $tbw - 1}] \
+ -width [expr {$width + ($tbw + 1) * 2}] \
+ -height [expr {$height + ($tbw + 1) * 2}] \
+ -bordermode outside
+
+ focus $T.text
+
+ return
+}
+
+proc ::TreeCtrl::TextClose {T accept} {
+
+ variable Priv
+
+ place forget $T.text
+ update
+
+ if {$accept} {
+ $T notify generate <Edit-accept> -T $T -I $Priv(text,$T,item) \
+ -C $Priv(text,$T,column) -E $Priv(text,$T,element) \
+ -t [$T.text get 1.0 end-1c]
+ }
+
+ $T notify bind $T.text <Scroll> {}
+
+ return
+}
+
+proc ::TreeCtrl::TextExpanderKeypress {T} {
+
+ variable Priv
+
+ 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]
+ place configure $T.text \
+ -x [expr {$center - $width / 2 - $tbw - 1}] \
+ -width [expr {$width + ($tbw + 1) * 2}] \
+ -height [expr {$height + ($tbw + 1) * 2}]
+
+ $T.text tag add TAG 1.0 end
+
+ return
+}
+
diff --git a/library/treectrl.tcl b/library/treectrl.tcl
new file mode 100644
index 0000000..c973410
--- /dev/null
+++ b/library/treectrl.tcl
@@ -0,0 +1,825 @@
+bind TreeCtrl <Motion> {
+ TreeCtrl::CursorCheck %W %x %y
+}
+bind TreeCtrl <Leave> {
+ TreeCtrl::CursorCancel %W
+}
+
+bind TreeCtrl <ButtonPress-1> {
+ TreeCtrl::ButtonPress1 %W %x %y
+}
+
+bind TreeCtrl <Double-ButtonPress-1> {
+ TreeCtrl::DoubleButton1 %W %x %y
+}
+
+bind TreeCtrl <Button1-Motion> {
+ TreeCtrl::Motion1 %W %x %y
+}
+bind TreeCtrl <ButtonRelease-1> {
+ TreeCtrl::Release1 %W %x %y
+}
+bind TreeCtrl <Shift-ButtonPress-1> {
+ set TreeCtrl::Priv(buttonMode) normal
+ TreeCtrl::BeginExtend %W [%W index {nearest %x %y}]
+}
+bind TreeCtrl <Control-ButtonPress-1> {
+ set TreeCtrl::Priv(buttonMode) normal
+ TreeCtrl::BeginToggle %W [%W index {nearest %x %y}]
+}
+bind TreeCtrl <Button1-Leave> {
+ TreeCtrl::Leave1 %W %x %y
+}
+bind TreeCtrl <Button1-Enter> {}
+
+bind TreeCtrl <KeyPress-Up> {
+ TreeCtrl::SetActiveItem %W [TreeCtrl::UpDown %W -1]
+}
+bind TreeCtrl <Shift-KeyPress-Up> {
+ TreeCtrl::ExtendUpDown %W above
+}
+bind TreeCtrl <KeyPress-Down> {
+ TreeCtrl::SetActiveItem %W [TreeCtrl::UpDown %W 1]
+}
+bind TreeCtrl <Shift-KeyPress-Down> {
+ TreeCtrl::ExtendUpDown %W below
+}
+bind TreeCtrl <KeyPress-Left> {
+ TreeCtrl::SetActiveItem %W [TreeCtrl::LeftRight %W -1]
+}
+bind TreeCtrl <Shift-KeyPress-Left> {
+ TreeCtrl::ExtendUpDown %W left
+}
+bind TreeCtrl <Control-KeyPress-Left> {
+ %W xview scroll -1 pages
+}
+bind TreeCtrl <KeyPress-Right> {
+ TreeCtrl::SetActiveItem %W [TreeCtrl::LeftRight %W 1]
+}
+bind TreeCtrl <Shift-KeyPress-Right> {
+ TreeCtrl::ExtendUpDown %W right
+}
+bind TreeCtrl <Control-KeyPress-Right> {
+ %W xview scroll 1 pages
+}
+bind TreeCtrl <KeyPress-Prior> {
+ %W yview scroll -1 pages
+ %W activate {nearest 0 0}
+}
+bind TreeCtrl <KeyPress-Next> {
+ %W yview scroll 1 pages
+ %W activate {nearest 0 0}
+}
+bind TreeCtrl <Control-KeyPress-Prior> {
+ %W xview scroll -1 pages
+}
+bind TreeCtrl <Control-KeyPress-Next> {
+ %W xview scroll 1 pages
+}
+bind TreeCtrl <KeyPress-Home> {
+ %W xview moveto 0
+}
+bind TreeCtrl <KeyPress-End> {
+ %W xview moveto 1
+}
+bind TreeCtrl <Control-KeyPress-Home> {
+ %W activate {first visible}
+ %W see active
+ %W selection modify active all
+}
+bind TreeCtrl <Shift-Control-KeyPress-Home> {
+ TreeCtrl::DataExtend %W 0
+}
+bind TreeCtrl <Control-KeyPress-End> {
+ %W activate {last visible}
+ %W see active
+ %W selection modify active all
+}
+bind TreeCtrl <Shift-Control-KeyPress-End> {
+ TreeCtrl::DataExtend %W [%W index {last visible}]
+}
+bind TreeCtrl <<Copy>> {
+ if {[string equal [selection own -displayof %W] "%W"]} {
+ clipboard clear -displayof %W
+ clipboard append -displayof %W [selection get -displayof %W]
+ }
+}
+bind TreeCtrl <KeyPress-space> {
+ TreeCtrl::BeginSelect %W [%W index active]
+}
+bind TreeCtrl <KeyPress-Select> {
+ TreeCtrl::BeginSelect %W [%W index active]
+}
+bind TreeCtrl <Control-Shift-KeyPress-space> {
+ TreeCtrl::BeginExtend %W [%W index active]
+}
+bind TreeCtrl <Shift-KeyPress-Select> {
+ TreeCtrl::BeginExtend %W [%W index active]
+}
+bind TreeCtrl <KeyPress-Escape> {
+ TreeCtrl::Cancel %W
+}
+bind TreeCtrl <Control-KeyPress-slash> {
+ TreeCtrl::SelectAll %W
+}
+bind TreeCtrl <Control-KeyPress-backslash> {
+ if {[string compare [%W cget -selectmode] "browse"]} {
+ %W selection clear
+ }
+}
+
+bind TreeCtrl <KeyPress-plus> {
+ %W expand [%W index active]
+}
+bind TreeCtrl <KeyPress-minus> {
+ %W collapse [%W index active]
+}
+bind TreeCtrl <KeyPress-Return> {
+ %W toggle [%W index active]
+}
+
+
+# Additional Tk bindings that aren't part of the Motif look and feel:
+
+bind TreeCtrl <KeyPress-2> {
+ %W scan mark %x %y
+}
+bind TreeCtrl <Button2-Motion> {
+ %W scan dragto %x %y
+}
+
+# The MouseWheel will typically only fire on Windows. However,
+# someone could use the "event generate" command to produce one
+# on other platforms.
+
+bind TreeCtrl <MouseWheel> {
+ %W yview scroll [expr {- (%D / 120) * 4}] units
+}
+
+if {[string equal "unix" $tcl_platform(platform)]} {
+ # 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
+ }
+ }
+}
+
+namespace eval ::TreeCtrl {
+ variable Priv
+ array set Priv {
+ prev {}
+ rnc {}
+ }
+}
+
+proc ::TreeCtrl::CursorCheck {w x y} {
+ variable Priv
+ set id [$w identify $x $y]
+ if {([llength $id] == 3) && ([lindex $id 0] eq "header")} {
+ set column [lindex $id 1]
+ set side [lindex $id 2]
+ set visCount 0
+ for {set i 0} {$i < [$w numcolumns]} {incr i} {
+ if {[$w column cget $i -visible]} {
+ lappend visColumns $i
+ if {$i eq $column} {
+ set columnIndex $visCount
+ }
+ incr visCount
+ }
+ }
+ lappend visColumns tail
+ if {$column eq "tail"} {
+ set columnIndex $visCount
+ }
+ if {$side eq "left"} {
+ if {$column eq [lindex $visColumns 0]} {
+ return
+ }
+ set column [lindex $visColumns [expr {$columnIndex - 1}]]
+ }
+ if {![info exists Priv(cursor,$w)]} {
+ set Priv(cursor,$w) [$w cget -cursor]
+ $w configure -cursor sb_h_double_arrow
+ 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
+ }
+ CursorCancel $w
+ return
+}
+
+proc ::TreeCtrl::CursorCheckAux {w} {
+ variable Priv
+ 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
+}
+
+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
+}
+
+proc ::TreeCtrl::ButtonPress1 {w x y} {
+ variable Priv
+ focus $w
+ set id [$w identify $x $y]
+ if {$id eq ""} {
+ return
+ }
+ if {[lindex $id 0] eq "item"} {
+ foreach {where item arg1 arg2} $id {}
+ if {$arg1 eq "button"} {
+ $w toggle $item
+ return
+ } elseif {$arg1 eq "line"} {
+ $w toggle $arg2
+ return
+ }
+ }
+ set Priv(buttonMode) ""
+ if {[lindex $id 0] eq "header"} {
+ set column [lindex $id 1]
+ set visCount 0
+ for {set i 0} {$i < [$w numcolumns]} {incr i} {
+ if {[$w column cget $i -visible]} {
+ lappend visColumns $i
+ if {$i eq $column} {
+ set columnIndex $visCount
+ }
+ incr visCount
+ }
+ }
+ lappend visColumns tail
+ if {$column eq "tail"} {
+ set columnIndex $visCount
+ }
+ if {[llength $id] == 3} {
+ set side [lindex $id 2]
+ if {$side == "left"} {
+ if {$column eq [lindex $visColumns 0]} {
+ return
+ }
+ set column [lindex $visColumns [expr {$columnIndex - 1}]]
+ }
+ set Priv(buttonMode) resize
+ set Priv(column) $column
+ set Priv(x) $x
+ set Priv(y) $y
+ set Priv(width) [$w column width $column]
+ return
+ }
+ if {$column eq "tail"} return
+ if {![$w column cget $column -button]} return
+ set Priv(buttonMode) header
+ set Priv(column) $column
+ $w column configure $column -sunken yes
+ return
+ }
+ set Priv(buttonMode) normal
+ BeginSelect $w [lindex $id 1]
+ return
+}
+
+# Double-click between columns to set default column width
+proc ::TreeCtrl::DoubleButton1 {w x y} {
+ set id [$w identify $x $y]
+ if {$id eq ""} {
+ return
+ }
+ if {[lindex $id 0] eq "header"} {
+ set column [lindex $id 1]
+ set visCount 0
+ for {set i 0} {$i < [$w numcolumns]} {incr i} {
+ if {[$w column cget $i -visible]} {
+ lappend visColumns $i
+ if {$i eq $column} {
+ set columnIndex $visCount
+ }
+ incr visCount
+ }
+ }
+ lappend visColumns tail
+ if {$column eq "tail"} {
+ set columnIndex $visCount
+ }
+ if {[llength $id] == 3} {
+ set side [lindex $id 2]
+ if {$side == "left"} {
+ if {$column eq [lindex $visColumns 0]} {
+ return
+ }
+ set column [lindex $visColumns [expr {$columnIndex - 1}]]
+ }
+ if {$column eq "tail"} return
+ $w column configure $column -width ""
+ }
+ }
+ return
+}
+
+proc ::TreeCtrl::Motion1 {w x y} {
+ variable Priv
+ if {![info exists Priv(buttonMode)]} return
+ switch $Priv(buttonMode) {
+ header {
+ set id [$w identify $x $y]
+ if {![string match "header $Priv(column)*" $id]} {
+ if {[$w column cget $Priv(column) -sunken]} {
+ $w column configure $Priv(column) -sunken no
+ }
+ } else {
+ if {![$w column cget $Priv(column) -sunken]} {
+ $w column configure $Priv(column) -sunken yes
+ }
+ }
+ }
+ normal {
+ set Priv(x) $x
+ set Priv(y) $y
+ Motion $w [$w index [list nearest $x $y]]
+ AutoScanCheck $w $x $y
+ }
+ resize {
+ set width [expr {$Priv(width) + $x - $Priv(x)}]
+ set minWidth [$w column cget $Priv(column) -minwidth]
+ if {$minWidth eq ""} {
+ set minWidth 0
+ }
+ if {$width < $minWidth} {
+ set width $minWidth
+ }
+ if {$width == 0} {
+ incr width
+ }
+ scan [$w column bbox $Priv(column)] "%d %d %d %d" x1 y1 x2 y2
+ # Use "ne" because -columnproxy could be ""
+ if {($x1 + $width - 1) ne [$w cget -columnproxy]} {
+ $w configure -columnproxy [expr {$x1 + $width - 1}]
+ }
+ }
+ }
+ return
+}
+
+proc ::TreeCtrl::Leave1 {w x y} {
+ variable Priv
+ if {![info exists Priv(buttonMode)]} return
+ switch $Priv(buttonMode) {
+ header {
+ if {[$w column cget $Priv(column) -sunken]} {
+ $w column configure $Priv(column) -sunken no
+ }
+ }
+ normal {
+ }
+ resize {}
+ }
+ return
+}
+
+proc ::TreeCtrl::Release1 {w x y} {
+ variable Priv
+ if {![info exists Priv(buttonMode)]} return
+ switch $Priv(buttonMode) {
+ header {
+ if {[$w column cget $Priv(column) -sunken]} {
+ $w column configure $Priv(column) -sunken no
+ $w notify generate <Header-invoke> -T $w -C $Priv(column)
+ }
+ }
+ normal {
+ AutoScanCancel $w
+ $w activate [$w index [list nearest $x $y]]
+ }
+ resize {
+ if {[$w cget -columnproxy] ne ""} {
+ scan [$w column bbox $Priv(column)] "%d %d %d %d" x1 y1 x2 y2
+ set width [expr {[$w cget -columnproxy] - $x1 + 1}]
+ $w configure -columnproxy {}
+ $w column configure $Priv(column) -width $width
+ CursorCheck $w $x $y
+ }
+ }
+ }
+ 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 listbox. Its exact behavior
+# depends on the selection mode currently in effect for the listbox;
+# see the Motif documentation for details.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element for the selection operation (typically the
+# one under the pointer). Must be in numerical form.
+
+proc ::TreeCtrl::BeginSelect {w el} {
+ variable Priv
+ if {$el eq ""} return
+ if {[string equal [$w cget -selectmode] "multiple"]} {
+ if {[$w selection includes $el]} {
+ $w selection clear $el
+ } else {
+ $w selection add $el
+ }
+ } else {
+ $w selection anchor $el
+ $w selection modify $el all
+ set Priv(selection) {}
+ set Priv(prev) $el
+ }
+}
+
+# ::TreeCtrl::Motion --
+#
+# This procedure is called to process mouse motion events while
+# button 1 is down. It may move or extend the selection, depending
+# on the listbox's selection mode.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element under the pointer (must be a number).
+
+proc ::TreeCtrl::Motion {w el} {
+ variable Priv
+ if {$el eq $Priv(prev)} {
+ return
+ }
+ switch [$w cget -selectmode] {
+ browse {
+ $w selection modify $el all
+ set Priv(prev) $el
+ }
+ extended {
+ set i $Priv(prev)
+ if {$i eq ""} {
+ set i $el
+ $w selection add $el
+ }
+ if {[$w selection includes anchor]} {
+ $w selection clear $i $el
+ $w selection add anchor $el
+ } else {
+ $w selection clear $i $el
+ $w selection clear anchor $el
+ }
+ if {![info exists Priv(selection)]} {
+ set Priv(selection) [$w selection get]
+ }
+ while {[$w compare $i < $el] && [$w compare $i < anchor]} {
+ if {[lsearch $Priv(selection) $i] >= 0} {
+ $w selection add $i
+ }
+ set i [$w index "$i next visible"]
+ }
+ while {[$w compare $i > $el] && [$w compare $i > anchor]} {
+ if {[lsearch $Priv(selection) $i] >= 0} {
+ $w selection add $i
+ }
+ set i [$w index "$i prev visible"]
+ }
+ set Priv(prev) $el
+ }
+ }
+}
+
+# ::TreeCtrl::BeginExtend --
+#
+# This procedure is typically invoked on shift-button-1 presses. It
+# begins the process of extending a selection in the listbox. Its
+# exact behavior depends on the selection mode currently in effect
+# for the listbox; see the Motif documentation for details.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element for the selection operation (typically the
+# one under the pointer). Must be in numerical form.
+
+proc ::TreeCtrl::BeginExtend {w el} {
+ if {[string equal [$w cget -selectmode] "extended"]} {
+ if {[$w selection includes anchor]} {
+ Motion $w $el
+ } else {
+ # No selection yet; simulate the begin-select operation.
+ BeginSelect $w $el
+ }
+ }
+}
+
+# ::TreeCtrl::BeginToggle --
+#
+# This procedure is typically invoked on control-button-1 presses. It
+# begins the process of toggling a selection in the listbox. Its
+# exact behavior depends on the selection mode currently in effect
+# for the listbox; see the Motif documentation for details.
+#
+# Arguments:
+# w - The listbox widget.
+# el - The element for the selection operation (typically the
+# one under the pointer). Must be in numerical form.
+
+proc ::TreeCtrl::BeginToggle {w el} {
+ variable Priv
+ if {[string equal [$w cget -selectmode] "extended"]} {
+ set Priv(selection) [$w selection get]
+ set Priv(prev) $el
+ $w selection anchor $el
+ if {[$w selection includes $el]} {
+ $w selection clear $el
+ } else {
+ $w selection add $el
+ }
+ }
+}
+
+proc ::TreeCtrl::CancelRepeat {} {
+ variable Priv
+ if {[info exists Priv(afterId)]} {
+ after cancel $Priv(afterId)
+ unset Priv(afterId)
+ }
+}
+
+proc ::TreeCtrl::AutoScanCheck {w x y} {
+ variable Priv
+ scan [$w contentbox] "%d %d %d %d" x1 y1 x2 y2
+ set margin [winfo pixels $w [$w cget -scrollmargin]]
+ if {($x < $x1 + $margin) || ($x >= $x2 - $margin) ||
+ ($y < $y1 + $margin) || ($y >= $y2 - $margin)} {
+ if {![info exists Priv(autoscan,afterId,$w)]} {
+ if {$y >= $y2 - $margin} {
+ $w yview scroll 1 units
+ set delay [$w cget -yscrolldelay]
+ } elseif {$y < $y1 + $margin} {
+ $w yview scroll -1 units
+ set delay [$w cget -yscrolldelay]
+ } elseif {$x >= $x2 - $margin} {
+ $w xview scroll 1 units
+ set delay [$w cget -xscrolldelay]
+ } elseif {$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
+ }
+ Motion $w [$w index "nearest $x $y"]
+ set Priv(autoscan,afterId,$w) [after $delay [list TreeCtrl::AutoScanCheckAux $w]]
+ }
+ return
+ }
+ AutoScanCancel $w
+ return
+}
+
+proc ::TreeCtrl::AutoScanCheckAux {w} {
+ variable Priv
+ 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
+}
+
+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::UpDown --
+#
+# Moves the location cursor (active element) up or down by one element,
+# and changes the selection if we're in browse or extended selection
+# mode.
+#
+# Arguments:
+# w - The listbox widget.
+# amount - +1 to move down one item, -1 to move back one item.
+
+proc ::TreeCtrl::UpDown {w n} {
+ variable Priv
+ set rnc [$w item rnc active]
+ # active item isn't visible
+ if {$rnc eq ""} {
+ set rnc [$w item rnc first]
+ if {$rnc eq ""} return
+ }
+ scan $rnc "%d %d" row col
+ set Priv(row) [expr {$row + $n}]
+ if {$rnc ne $Priv(rnc)} {
+ set Priv(col) $col
+ }
+ set index [$w index "rnc $Priv(row) $Priv(col)"]
+ if {[$w compare active == $index]} {
+ set Priv(row) $row
+ } else {
+ set Priv(rnc) [$w item rnc $index]
+ }
+ return $index
+}
+
+proc ::TreeCtrl::LeftRight {w n} {
+ variable Priv
+ set rnc [$w item rnc active]
+ if {$rnc eq ""} {
+ set rnc [$w item rnc first]
+ if {$rnc eq ""} return
+ }
+ scan $rnc "%d %d" row col
+ set Priv(col) [expr {$col + $n}]
+ if {$rnc ne $Priv(rnc)} {
+ set Priv(row) $row
+ }
+ set index [$w index "rnc $Priv(row) $Priv(col)"]
+ if {[$w compare active == $index]} {
+ set Priv(col) $col
+ } else {
+ set Priv(rnc) [$w item rnc $index]
+ }
+ return $index
+}
+
+proc ::TreeCtrl::SetActiveItem {w index} {
+ if {$index eq ""} return
+ $w activate $index
+ $w see active
+ $w selection modify active all
+ switch [$w cget -selectmode] {
+ extended {
+ $w selection anchor active
+ set Priv(prev) [$w index active]
+ set Priv(selection) {}
+ }
+ }
+}
+
+# ::TreeCtrl::ExtendUpDown --
+#
+# Does nothing unless we're in extended selection mode; in this
+# case it moves the location cursor (active element) up or down by
+# one element, and extends the selection to that point.
+#
+# Arguments:
+# w - The listbox widget.
+# amount - +1 to move down one item, -1 to move back one item.
+
+proc ::TreeCtrl::ExtendUpDown {w amount} {
+ variable Priv
+ if {[string compare [$w cget -selectmode] "extended"]} {
+ return
+ }
+ set active [$w index active]
+ if {![info exists Priv(selection)]} {
+ $w selection add $active
+ set Priv(selection) [$w selection get]
+ }
+ set index [$w index "active $amount"]
+ if {$index eq ""} return
+ $w activate $index
+ $w see active
+ Motion $w [$w index active]
+}
+
+# ::TreeCtrl::DataExtend
+#
+# This procedure is called for key-presses such as Shift-KEndData.
+# If the selection mode isn't multiple or extend then it does nothing.
+# Otherwise it moves the active element to el and, if we're in
+# extended mode, extends the selection to that point.
+#
+# Arguments:
+# w - The listbox widget.
+# el - An integer element number.
+
+proc ::TreeCtrl::DataExtend {w el} {
+ set mode [$w cget -selectmode]
+ if {[string equal $mode "extended"]} {
+ $w activate $el
+ $w see $el
+ if {[$w selection includes anchor]} {
+ Motion $w $el
+ }
+ } elseif {[string equal $mode "multiple"]} {
+ $w activate $el
+ $w see $el
+ }
+}
+
+# ::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 listbox widget.
+
+proc ::TreeCtrl::Cancel w {
+ variable Priv
+ if {[string compare [$w cget -selectmode] "extended"]} {
+ return
+ }
+ set first [$w index anchor]
+ set last $Priv(prev)
+ if { [string equal $last ""] } {
+ # Not actually doing any selection right now
+ return
+ }
+ if {[$w compare $first > $last]} {
+ set tmp $first
+ set first $last
+ set last $tmp
+ }
+ $w selection clear $first $last
+ while {[$w compare $first <= $last]} {
+ if {[lsearch $Priv(selection) $first] >= 0} {
+ $w selection add $first
+ }
+ set first [$w index "$first next visible"]
+ }
+}
+
+# ::TreeCtrl::SelectAll
+#
+# This procedure is invoked to handle the "select all" operation.
+# For single and browse mode, it just selects the active element.
+# Otherwise it selects everything in the widget.
+#
+# Arguments:
+# w - The listbox 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
+ }
+}
+
+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 visible yes
+ return
+}
+
+proc ::TreeCtrl::MarqueeUpdate {w x y} {
+ set x [$w canvasx $x]
+ set y [$w canvasy $y]
+ $w marquee corner $x $y
+ return
+}
+proc ::TreeCtrl::MarqueeEnd {w x y} {
+ $w marquee visible no
+ return
+}
+
diff --git a/pics/big-dll.gif b/pics/big-dll.gif
new file mode 100644
index 0000000..09170c0
--- /dev/null
+++ b/pics/big-dll.gif
Binary files differ
diff --git a/pics/big-exe.gif b/pics/big-exe.gif
new file mode 100644
index 0000000..e19aac1
--- /dev/null
+++ b/pics/big-exe.gif
Binary files differ
diff --git a/pics/big-file.gif b/pics/big-file.gif
new file mode 100644
index 0000000..6c75231
--- /dev/null
+++ b/pics/big-file.gif
Binary files differ
diff --git a/pics/big-folder.gif b/pics/big-folder.gif
new file mode 100644
index 0000000..186c974
--- /dev/null
+++ b/pics/big-folder.gif
Binary files differ
diff --git a/pics/big-txt.gif b/pics/big-txt.gif
new file mode 100644
index 0000000..a934925
--- /dev/null
+++ b/pics/big-txt.gif
Binary files differ
diff --git a/pics/checked.gif b/pics/checked.gif
new file mode 100644
index 0000000..3b9b176
--- /dev/null
+++ b/pics/checked.gif
Binary files differ
diff --git a/pics/file.gif b/pics/file.gif
new file mode 100644
index 0000000..a64c2a0
--- /dev/null
+++ b/pics/file.gif
Binary files differ
diff --git a/pics/folder-closed.gif b/pics/folder-closed.gif
new file mode 100644
index 0000000..0a06437
--- /dev/null
+++ b/pics/folder-closed.gif
Binary files differ
diff --git a/pics/folder-open.gif b/pics/folder-open.gif
new file mode 100644
index 0000000..3fac27f
--- /dev/null
+++ b/pics/folder-open.gif
Binary files differ
diff --git a/pics/help-book-closed.gif b/pics/help-book-closed.gif
new file mode 100644
index 0000000..0a0497b
--- /dev/null
+++ b/pics/help-book-closed.gif
Binary files differ
diff --git a/pics/help-book-open.gif b/pics/help-book-open.gif
new file mode 100644
index 0000000..40656c5
--- /dev/null
+++ b/pics/help-book-open.gif
Binary files differ
diff --git a/pics/help-page.gif b/pics/help-page.gif
new file mode 100644
index 0000000..e1ce1d7
--- /dev/null
+++ b/pics/help-page.gif
Binary files differ
diff --git a/pics/imovie-01.gif b/pics/imovie-01.gif
new file mode 100644
index 0000000..5fd9215
--- /dev/null
+++ b/pics/imovie-01.gif
Binary files differ
diff --git a/pics/imovie-02.gif b/pics/imovie-02.gif
new file mode 100644
index 0000000..3d2d1c1
--- /dev/null
+++ b/pics/imovie-02.gif
Binary files differ
diff --git a/pics/imovie-03.gif b/pics/imovie-03.gif
new file mode 100644
index 0000000..9fccf12
--- /dev/null
+++ b/pics/imovie-03.gif
Binary files differ
diff --git a/pics/imovie-04.gif b/pics/imovie-04.gif
new file mode 100644
index 0000000..eff851c
--- /dev/null
+++ b/pics/imovie-04.gif
Binary files differ
diff --git a/pics/imovie-05.gif b/pics/imovie-05.gif
new file mode 100644
index 0000000..ad00c82
--- /dev/null
+++ b/pics/imovie-05.gif
Binary files differ
diff --git a/pics/imovie-06.gif b/pics/imovie-06.gif
new file mode 100644
index 0000000..238bf16
--- /dev/null
+++ b/pics/imovie-06.gif
Binary files differ
diff --git a/pics/imovie-07.gif b/pics/imovie-07.gif
new file mode 100644
index 0000000..a9287e1
--- /dev/null
+++ b/pics/imovie-07.gif
Binary files differ
diff --git a/pics/internet-check-off.gif b/pics/internet-check-off.gif
new file mode 100644
index 0000000..e64866a
--- /dev/null
+++ b/pics/internet-check-off.gif
Binary files differ
diff --git a/pics/internet-check-on.gif b/pics/internet-check-on.gif
new file mode 100644
index 0000000..cf652be
--- /dev/null
+++ b/pics/internet-check-on.gif
Binary files differ
diff --git a/pics/internet-print.gif b/pics/internet-print.gif
new file mode 100644
index 0000000..7ac25b1
--- /dev/null
+++ b/pics/internet-print.gif
Binary files differ
diff --git a/pics/internet-radio-off.gif b/pics/internet-radio-off.gif
new file mode 100644
index 0000000..90ef629
--- /dev/null
+++ b/pics/internet-radio-off.gif
Binary files differ
diff --git a/pics/internet-radio-on.gif b/pics/internet-radio-on.gif
new file mode 100644
index 0000000..9de742c
--- /dev/null
+++ b/pics/internet-radio-on.gif
Binary files differ
diff --git a/pics/internet-search.gif b/pics/internet-search.gif
new file mode 100644
index 0000000..1f9a047
--- /dev/null
+++ b/pics/internet-search.gif
Binary files differ
diff --git a/pics/internet-security.gif b/pics/internet-security.gif
new file mode 100644
index 0000000..86d3943
--- /dev/null
+++ b/pics/internet-security.gif
Binary files differ
diff --git a/pics/mac-collapse.gif b/pics/mac-collapse.gif
new file mode 100644
index 0000000..81302c8
--- /dev/null
+++ b/pics/mac-collapse.gif
Binary files differ
diff --git a/pics/mac-expand.gif b/pics/mac-expand.gif
new file mode 100644
index 0000000..0a2cd80
--- /dev/null
+++ b/pics/mac-expand.gif
Binary files differ
diff --git a/pics/outlook-arrow.gif b/pics/outlook-arrow.gif
new file mode 100644
index 0000000..b1c2afd
--- /dev/null
+++ b/pics/outlook-arrow.gif
Binary files differ
diff --git a/pics/outlook-clip.gif b/pics/outlook-clip.gif
new file mode 100644
index 0000000..8578132
--- /dev/null
+++ b/pics/outlook-clip.gif
Binary files differ
diff --git a/pics/outlook-deleted.gif b/pics/outlook-deleted.gif
new file mode 100644
index 0000000..7cc8369
--- /dev/null
+++ b/pics/outlook-deleted.gif
Binary files differ
diff --git a/pics/outlook-draft.gif b/pics/outlook-draft.gif
new file mode 100644
index 0000000..f195850
--- /dev/null
+++ b/pics/outlook-draft.gif
Binary files differ
diff --git a/pics/outlook-folder.gif b/pics/outlook-folder.gif
new file mode 100644
index 0000000..b3f7335
--- /dev/null
+++ b/pics/outlook-folder.gif
Binary files differ
diff --git a/pics/outlook-group.gif b/pics/outlook-group.gif
new file mode 100644
index 0000000..29ad9b4
--- /dev/null
+++ b/pics/outlook-group.gif
Binary files differ
diff --git a/pics/outlook-inbox.gif b/pics/outlook-inbox.gif
new file mode 100644
index 0000000..f41d804
--- /dev/null
+++ b/pics/outlook-inbox.gif
Binary files differ
diff --git a/pics/outlook-local.gif b/pics/outlook-local.gif
new file mode 100644
index 0000000..0c74970
--- /dev/null
+++ b/pics/outlook-local.gif
Binary files differ
diff --git a/pics/outlook-main.gif b/pics/outlook-main.gif
new file mode 100644
index 0000000..92325fa
--- /dev/null
+++ b/pics/outlook-main.gif
Binary files differ
diff --git a/pics/outlook-outbox.gif b/pics/outlook-outbox.gif
new file mode 100644
index 0000000..c7e8052
--- /dev/null
+++ b/pics/outlook-outbox.gif
Binary files differ
diff --git a/pics/outlook-read-2.gif b/pics/outlook-read-2.gif
new file mode 100644
index 0000000..2f15a3a
--- /dev/null
+++ b/pics/outlook-read-2.gif
Binary files differ
diff --git a/pics/outlook-read.gif b/pics/outlook-read.gif
new file mode 100644
index 0000000..a6f9562
--- /dev/null
+++ b/pics/outlook-read.gif
Binary files differ
diff --git a/pics/outlook-sent.gif b/pics/outlook-sent.gif
new file mode 100644
index 0000000..963b56c
--- /dev/null
+++ b/pics/outlook-sent.gif
Binary files differ
diff --git a/pics/outlook-server.gif b/pics/outlook-server.gif
new file mode 100644
index 0000000..c950845
--- /dev/null
+++ b/pics/outlook-server.gif
Binary files differ
diff --git a/pics/outlook-unread.gif b/pics/outlook-unread.gif
new file mode 100644
index 0000000..3df4b99
--- /dev/null
+++ b/pics/outlook-unread.gif
Binary files differ
diff --git a/pics/outlook-watch.gif b/pics/outlook-watch.gif
new file mode 100644
index 0000000..87ec861
--- /dev/null
+++ b/pics/outlook-watch.gif
Binary files differ
diff --git a/pics/small-dll.gif b/pics/small-dll.gif
new file mode 100644
index 0000000..d8875ec
--- /dev/null
+++ b/pics/small-dll.gif
Binary files differ
diff --git a/pics/small-exe.gif b/pics/small-exe.gif
new file mode 100644
index 0000000..69d30be
--- /dev/null
+++ b/pics/small-exe.gif
Binary files differ
diff --git a/pics/small-file.gif b/pics/small-file.gif
new file mode 100644
index 0000000..f340662
--- /dev/null
+++ b/pics/small-file.gif
Binary files differ
diff --git a/pics/small-folder.gif b/pics/small-folder.gif
new file mode 100644
index 0000000..ad1b24d
--- /dev/null
+++ b/pics/small-folder.gif
Binary files differ
diff --git a/pics/small-txt.gif b/pics/small-txt.gif
new file mode 100644
index 0000000..cdc7cbf
--- /dev/null
+++ b/pics/small-txt.gif
Binary files differ
diff --git a/pics/unchecked.gif b/pics/unchecked.gif
new file mode 100644
index 0000000..833e482
--- /dev/null
+++ b/pics/unchecked.gif
Binary files differ
diff --git a/pkgIndex.tcl.in b/pkgIndex.tcl.in
new file mode 100644
index 0000000..f372c53
--- /dev/null
+++ b/pkgIndex.tcl.in
@@ -0,0 +1,9 @@
+proc ::TreeCtrlLoad {dir} {
+ uplevel #0 source [file join $dir treectrl.tcl]
+ uplevel #0 source [file join $dir filelist-bindings.tcl]
+ tclPkgSetup $dir treectrl @VERSION@ {
+ {@treectrl_LIB_FILE@ load {treectrl imagetint textlayout}}
+ }
+}
+package ifneeded treectrl @VERSION@ [list ::TreeCtrlLoad $dir]
+
diff --git a/tclconfig/ChangeLog b/tclconfig/ChangeLog
new file mode 100644
index 0000000..758276f
--- /dev/null
+++ b/tclconfig/ChangeLog
@@ -0,0 +1,161 @@
+2002-10-15 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4: move the CFLAGS definition from TEA_ENABLE_SHARED to
+ TEA_MAKE_LIB because setting too early confuses other AC_* macros.
+ Correct the HP-11 SHLIB_LD_LIBS setting.
+
+ * tcl.m4: add the CFLAGS definition into TEA_ENABLE_SHARED and
+ make it pick up the env CFLAGS at configure time.
+
+2002-10-09 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4: add --enable-symbols=mem option to enable TCL_MEM_DEBUG.
+ Improved AIX 64-bit build support, allow it on AIX-4 as well.
+ Enable 64-bit HP-11 compilation with gcc.
+ Enable 64-bit IRIX64-6 cc build support.
+ Correct FreeBSD thread library linkage.
+ Add OSF1 static build support.
+ Improve SunOS-5 shared build SHLIB_LD macro.
+
+2002-07-20 Zoran Vasiljevic <zoran@archiware.com>
+
+ * tcl.m4: Added MINGW32 to list of systems checked for Windows build.
+ Also, fixes some indentation issues with "--with-XXX" options.
+
+2002-04-23 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4 (TEA_ENABLE_THREADS): added USE_THREAD_ALLOC define to
+ use new threaded allocatory by default on Unix for Tcl 8.4.
+ (TEA_CONFIG_CFLAGS): corrected LD_SEARCH_FLAGS for FreeBSD-3+.
+
+2002-04-22 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4 (TEA_SETUP_COMPILER): removed call to AC_CYGWIN so that
+ we can use autoconf 2.5x as well as 2.13. This prevents us from
+ being able to warn against the use of cygwin gcc at configure
+ time, but allows autoconf 2.5x, which is what is shipped with most
+ newer systems.
+
+2002-04-11 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4: Enabled COFF as well as CV style debug info with
+ --enable-symbols to allow Dr. Watson users to see function info.
+ More info on debugging levels can be obtained at:
+ http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp
+
+2002-04-03 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4: change all SC_* macros to TEA_*. The SC_ was for
+ Scriptics, which is no more. TEA represents a better, independent
+ prefix that won't need changing.
+ Added preliminary mingw gcc support. [Patch #538772]
+ Added TEA_PREFIX macro that handles defaulting the prefix and
+ exec_prefix vars to those used by Tcl if none were specified.
+ Added TEA_SETUP_COMPILER macro that encompasses the AC_PROG_CC
+ check and several other basic AC_PROG checks needed for making
+ executables. This greatly simplifies user's configure.in files.
+ Collapsed AIX-5 defines into AIX-* with extra checks for doing the
+ ELF stuff on AIX-5-ia64.
+ Updated TEA_ENABLE_THREADS to take an optional arg to allow
+ switching it on by default (for Thread) and add sanity checking to
+ warn the user if configuring threads incompatibly.
+
+2002-03-29 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4: made sure that SHLIB_LDFLAGS was set to LDFLAGS_DEFAULT.
+ Removed --enable-64bit support for AIX-4 because it wasn't correct.
+ Added -MT or -MD Windows linker switches to properly support
+ symbols-enabled builds.
+
+2002-03-28 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4: called AC_MSG_ERROR when SC_TEA_INIT wasn't called first
+ instead of calling it as that inlines it each time in shell code.
+ Changed Windows CFLAGS_OPTIMIZE to use -O2 instead of -Oti.
+ Noted TCL_LIB_VERSIONS_OK=nodots for Windows builds.
+ A few changes to support itcl (and perhaps others):
+ Added support for making your own stub libraries to SC_MAKE_LIB.
+ New SC_PATH_CONFIG and SC_LOAD_CONFIG that take a package name arg
+ and find that ${pkg}Config.sh file. itk uses this for itcl.
+
+2002-03-27 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4: made SC_LOAD_TKCONFIG recognize when working with a Tk
+ build dir setup.
+ Added EXTRA_CFLAGS and SHLIB_LD_LIBS substs to SC_CONFIG_CFLAGS.
+ Added XLIBSW onto LIBS when it is defined.
+ Remove TCL_LIBS from MAKE_LIB and correctly use SHLIB_LD_LIBS
+ instead to not rely as much on tclConfig.sh cached info.
+ Add TK_BIN_DIR to paths to find wish in SC_PROG_WISH.
+ These move towards making TEA much more independent of *Config.sh.
+
+2002-03-19 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4: corrected forgotten (UN)SHARED_LIB_SUFFIX and
+ SHLIB_SUFFIX defines for Win.
+ (SC_PATH_X): made this only do the check on unix platforms.
+
+2002-03-12 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * README.txt: updated to reflect fewer files
+
+2002-03-06 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * config.guess (removed):
+ * config.sub (removed): removed unnecessary files
+
+ * installFile.tcl (removed):
+ * mkinstalldirs (removed): these aren't really necessary for
+ making TEA work
+
+ * tcl.m4 (SC_PUBLIC_TCL_HEADERS, SC_PUBLIC_TK_HEADERS): don't
+ check /usr(/local)/include for includes on Windows when not using
+ gcc
+
+2002-03-05 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * tcl.m4: added warnings on Windows, removed RELPATH define and
+ added TCL_LIBS to MAKE_LIB macro.
+
+ This import represents 2.0.0, or a new start at attempting to
+ make TEA much easier for C extension developers.
+
+ **** moved from tclpro project to core tcl project, ****
+ **** renamed to 'tclconfig' ****
+
+2001-03-15 Karl Lehenbauer <karl@procplace.com>
+
+ * installFile.tcl: Added updating of the modification time of
+ the target file whether we overwrote it or decided that it
+ hadn't changed. This was necessary for us to be able to
+ determine whether or not a module install touched the file.
+
+2001-03-08 Karl Lehenbauer <karl@procplace.com>
+
+ * installFile.tcl: Added support for converting new-style (1.1+)
+ Cygnus drive paths to Tcl-style.
+
+2001-01-15 <brent.welch@interwoven.com>
+
+ * tcl.m4: Added FreeBSD clause.
+
+2001-01-03 <brent.welch@interwoven.com>
+
+ * tcl.m4: Fixed typo in SC_LIB_SPEC where it is checking
+ for exec-prefix.
+
+2000-12-01 <brent.welch@interwoven.com>
+
+ * tcl.m4: Concatenated most of the Ajuba acsite.m4 file
+ so we don't need to modify the autoconf installation.
+ * config.guess:
+ * config.sub:
+ * installFile.tcl:
+ Added files from the itcl config subdirectory,
+ which should go away.
+
+2000-7-29 <welch@ajubasolutions.com>
+
+ * Fixed the use of TCL_SRC_DIR and TK_SRC_DIR within
+ TCL_PRIVATE_INCLUDES and TK_PRIVATE_INCLUDES to match their recent
+ change from $(srcdir) to $(srcdir)/..
diff --git a/tclconfig/README.txt b/tclconfig/README.txt
new file mode 100644
index 0000000..9055a58
--- /dev/null
+++ b/tclconfig/README.txt
@@ -0,0 +1,26 @@
+These 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.
diff --git a/tclconfig/install-sh b/tclconfig/install-sh
new file mode 100644
index 0000000..0ff4b6a
--- /dev/null
+++ b/tclconfig/install-sh
@@ -0,0 +1,119 @@
+#!/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
diff --git a/tclconfig/tcl.m4 b/tclconfig/tcl.m4
new file mode 100644
index 0000000..d2421cf
--- /dev/null
+++ b/tclconfig/tcl.m4
@@ -0,0 +1,3171 @@
+# 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 ActiveState Corporation.
+#
+# See the file "license.terms" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+
+#------------------------------------------------------------------------
+# 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, [
+ if test x"${TEA_INITED}" = x ; then
+ # Can't refer to exact macro name or it will be substituted
+ AC_MSG_ERROR([Must call TEA INIT before PATH_TCLCONFIG])
+ fi
+ #
+ # 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, [ --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
+ 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]]* 2>/dev/null` \
+ ../../tcl \
+ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
+ ../../../tcl \
+ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do
+ if test -f "$i/unix/tclConfig.sh" ; then
+ ac_cv_c_tclconfig=`(cd $i/unix; 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 ${exec_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` \
+ ; 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]]* 2>/dev/null` ; do
+ 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_WARN("Cannot find Tcl configuration definitions")
+ exit 0
+ 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, [ --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
+ 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]]* 2>/dev/null` \
+ ../../tk \
+ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \
+ ../../../tk \
+ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do
+ if test -f "$i/unix/tkConfig.sh" ; then
+ ac_cv_c_tkconfig=`(cd $i/unix; 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 ${exec_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` \
+ ; 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]]* 2>/dev/null` ; do
+ 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_WARN("Cannot find Tk configuration definitions")
+ exit 0
+ 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([file not found])
+ fi
+
+ #
+ # 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}
+ fi
+
+ #
+ # eval is required to do the TCL_DBGX substitution
+ #
+
+ eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
+ eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
+ eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
+
+ eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
+ 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_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)
+
+ #AC_SUBST(TCL_DBGX)
+ AC_SUBST(TCL_LIBS)
+ AC_SUBST(TCL_DEFS)
+ AC_SUBST(TCL_EXTRA_CFLAGS)
+ AC_SUBST(TCL_LD_FLAGS)
+ AC_SUBST(TCL_SHLIB_LD_LIBS)
+ #AC_SUBST(TCL_BUILD_LIB_SPEC)
+ #AC_SUBST(TCL_BUILD_STUB_LIB_SPEC)
+])
+
+#------------------------------------------------------------------------
+# 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
+
+ #
+ # 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}
+ fi
+
+ #
+ # eval is required to do the TK_DBGX substitution
+ #
+
+ eval "TK_LIB_FILE=\"${TK_LIB_FILE}\""
+ eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\""
+ eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\""
+
+ eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\""
+ eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\""
+ eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\""
+
+ 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)
+
+ AC_SUBST(TK_LIBS)
+ AC_SUBST(TK_XINCLUDES)
+])
+
+#------------------------------------------------------------------------
+# 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,
+ [ --enable-shared build and link with shared libraries [--enable-shared]],
+ [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)
+ 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.
+#
+# 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
+#
+#------------------------------------------------------------------------
+
+AC_DEFUN(TEA_ENABLE_THREADS, [
+ AC_ARG_ENABLE(threads, [ --enable-threads build with threads],
+ [tcl_ok=$enableval], [tcl_ok=$1])
+
+ if test "$tcl_ok" = "yes"; then
+ TCL_THREADS=1
+
+ if test "${TEA_PLATFORM}" != "windows" ; then
+ # We are always OK on Windows, so check what this platform wants.
+ AC_DEFINE(USE_THREAD_ALLOC)
+ AC_DEFINE(_REENTRANT)
+ AC_DEFINE(_THREAD_SAFE)
+ 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("Don t know how to find pthread lib on your system - thread support disabled")
+ fi
+ fi
+ fi
+ fi
+
+ # Does the pthread-implementation provide
+ # 'pthread_attr_setstacksize' ?
+ AC_CHECK_FUNCS(pthread_attr_setstacksize)
+ 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)
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no (default)])
+ 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} without threads enabled, but building against a Tcl
+ that IS thread-enabled.])
+ fi
+ ;;
+ *)
+ if test "${TCL_THREADS}" = "1"; then
+ AC_MSG_WARN([
+ --enable-threads requested, but attempting building against a Tcl
+ that is NOT thread-enabled.])
+ 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
+#
+# Requires the following vars to be set:
+# CFLAGS_DEBUG
+# CFLAGS_OPTIMIZE
+# LDFLAGS_DEBUG
+# LDFLAGS_OPTIMIZE
+#
+# 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 Debug library extension
+#
+#------------------------------------------------------------------------
+
+AC_DEFUN(TEA_ENABLE_SYMBOLS, [
+ if test x"${TEA_INITED}" = x ; then
+ # Can't refer to exact macro name or it will be substituted
+ AC_MSG_ERROR([Must call TEA INIT before ENABLE_SYMBOLS])
+ fi
+
+ if test "${TEA_PLATFORM}" = "windows" ; then
+ tcl_dbgx=d
+ else
+ tcl_dbgx=g
+ fi
+
+ AC_MSG_CHECKING([for build with symbols])
+ AC_ARG_ENABLE(symbols, [ --enable-symbols build with debugging symbols [--disable-symbols]], [tcl_ok=$enableval], [tcl_ok=no])
+ if test "$tcl_ok" = "no"; then
+ CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)'
+ LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)'
+ DBGX=""
+ TCL_DBGX=""
+ AC_MSG_RESULT([no])
+ else
+ CFLAGS_DEFAULT='$(CFLAGS_DEBUG)'
+ LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)'
+ DBGX=${tcl_dbgx}
+ TCL_DBGX=${tcl_dbgx}
+ if test "$tcl_ok" = "yes"; then
+ AC_MSG_RESULT([yes (standard debugging)])
+ fi
+ fi
+
+ AC_SUBST(TCL_DBGX)
+ AC_SUBST(CFLAGS_DEFAULT)
+ AC_SUBST(LDFLAGS_DEFAULT)
+
+ if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then
+ AC_DEFINE(TCL_MEM_DEBUG)
+ 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,
+ [ --enable-langinfo use nl_langinfo if possible to determine
+ encoding at startup, otherwise use old heuristic],
+ [langinfo_ok=$enableval], [langinfo_ok=yes])
+
+ HAVE_LANGINFO=0
+ if test "$langinfo_ok" = "yes"; then
+ if test "$langinfo_ok" = "yes"; then
+ AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no])
+ fi
+ fi
+ AC_MSG_CHECKING([whether to use nl_langinfo])
+ if test "$langinfo_ok" = "yes"; then
+ AC_TRY_COMPILE([#include <langinfo.h>],
+ [nl_langinfo(CODESET);],[langinfo_ok=yes],[langinfo_ok=no])
+ if test "$langinfo_ok" = "no"; then
+ langinfo_ok="no (could not compile with nl_langinfo)";
+ fi
+ if test "$langinfo_ok" = "yes"; then
+ AC_DEFINE(HAVE_LANGINFO)
+ fi
+ fi
+ AC_MSG_RESULT([$langinfo_ok])
+])
+
+#--------------------------------------------------------------------
+# 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 the following vars:
+#
+# DL_OBJS - Name of the object file that implements dynamic
+# loading for Tcl on this system.
+# DL_LIBS - Library file(s) to include in tclsh and other base
+# applications in order for the "load" command to work.
+# 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.
+# 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 is
+# "${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.
+# TCL_LIB_FILE - Name of the file that contains the Tcl library, such
+# as libtcl7.8.so or libtcl7.8.a.
+# TCL_LIB_SUFFIX -Specifies everything that comes after the "libtcl"
+# in the 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 the Tcl shared library needs to have
+# a .a extension whereas shared objects for loadable
+# extensions have a .so extension. Defaults to
+# ${VERSION}${SHLIB_SUFFIX}.
+# TCL_NEEDS_EXP_FILE -
+# 1 means that an export file is needed to link to a
+# shared library.
+# TCL_EXP_FILE - The name of the installed export / import file which
+# should be used to link to the Tcl shared library.
+# Empty if Tcl is unshared.
+# TCL_BUILD_EXP_FILE -
+# The name of the built export / import file which
+# should be used to link to the Tcl shared library.
+# Empty if Tcl is unshared.
+# CFLAGS_DEBUG -
+# Flags used when running the compiler in debug mode
+# CFLAGS_OPTIMIZE -
+# Flags used when running the compiler in optimize mode
+# EXTRA_CFLAGS -
+# Extra CFLAGS to pass to the compiler
+#
+# Subst's the following vars:
+# DL_LIBS
+# CFLAGS_DEBUG
+# CFLAGS_OPTIMIZE
+# CFLAGS_WARNING
+#
+# STLIB_LD
+# SHLIB_LD
+# SHLIB_CFLAGS
+# SHLIB_LDFLAGS
+# LDFLAGS_DEBUG
+# LDFLAGS_OPTIMIZE
+#--------------------------------------------------------------------
+
+AC_DEFUN(TEA_CONFIG_CFLAGS, [
+ if test x"${TEA_INITED}" = x ; then
+ # Can't refer to exact macro name or it will be substituted
+ AC_MSG_ERROR([Must call TEA INIT before CONFIG_CFLAGS])
+ fi
+
+ # Step 0: Enable 64 bit support?
+
+ AC_MSG_CHECKING([if 64bit support is enabled])
+ AC_ARG_ENABLE(64bit,[ --enable-64bit enable 64bit support (where applicable)], [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,[ --enable-64bit-vis enable 64bit Sparc VIS support], [do64bitVIS=$enableval], [do64bitVIS=no])
+ AC_MSG_RESULT([$do64bitVIS])
+
+ if test "$do64bitVIS" = "yes"; then
+ # Force 64bit on with VIS
+ do64bit=yes
+ fi
+
+ # Step 1: set the variable "system" to hold the name and version number
+ # for the system. This can usually be done via the "uname" command, but
+ # there are a few systems, like Next, where this doesn't work.
+
+ AC_MSG_CHECKING([system version (for dynamic loading)])
+ if test -f /usr/lib/NextStep/software_version; then
+ system=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version`
+ else
+ system=`uname -s`-`uname -r`
+ if test "$?" -ne 0 ; then
+ AC_MSG_RESULT([unknown (can't find uname command)])
+ system=unknown
+ else
+ # Special check for weird MP-RAS system (uname returns weird
+ # results, and the version is kept in special file).
+
+ if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then
+ system=MP-RAS-`awk '{print $3}' /etc/.relid'`
+ fi
+ if test "`uname -s`" = "AIX" ; then
+ system=AIX-`uname -v`.`uname -r`
+ fi
+ if test "${TEA_PLATFORM}" = "windows" ; then
+ system=windows
+ fi
+ AC_MSG_RESULT([$system])
+ fi
+ fi
+
+ # Step 2: check for existence of -ldl library. This is needed because
+ # Linux can use either -ldl or -ldld for dynamic loading.
+
+ AC_CHECK_LIB(dl, dlopen, have_dl=yes, have_dl=no)
+
+ # Step 3: set configuration options based on system name and version.
+
+ do64bit_ok=no
+ EXTRA_CFLAGS=""
+ TCL_EXPORT_FILE_SUFFIX=""
+ UNSHARED_LIB_SUFFIX=""
+ TCL_TRIM_DOTS='`echo ${VERSION} | tr -d .`'
+ ECHO_VERSION='`echo ${VERSION}`'
+ TCL_LIB_VERSIONS_OK=ok
+ CFLAGS_DEBUG=-g
+ CFLAGS_OPTIMIZE=-O
+ if test "$GCC" = "yes" ; then
+ CFLAGS_WARNING="-Wall -Wconversion -Wno-implicit-int"
+ else
+ CFLAGS_WARNING=""
+ fi
+ TCL_NEEDS_EXP_FILE=0
+ TCL_BUILD_EXP_FILE=""
+ TCL_EXP_FILE=""
+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'
+ case $system in
+ 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.
+ if test "$do64bit" = "yes" ; then
+ if test "x${MSSDK}x" = "xx" ; then
+ MSSDK="C:/Progra~1/Microsoft SDK"
+ fi
+ # In order to work in the tortured autoconf environment,
+ # we need to ensure that this path has no spaces
+ MSSDK=`cygpath -w -s "$MSSDK" | sed -e 's!\\\!/!g'`
+ if test ! -d "${MSSDK}/bin/win64" ; then
+ AC_MSG_WARN("could not find 64-bit SDK to enable 64bit mode")
+ do64bit="no"
+ else
+ do64bit_ok="yes"
+ fi
+ fi
+
+ if test "${SHARED_BUILD}" = "0" ; then
+ runtime=-MT
+ else
+ runtime=-MD
+ fi
+
+ if test "$do64bit" = "yes" ; then
+ # All this magic is necessary for the Win64 SDK RC1 - hobbs
+ export CC="${MSSDK}/Bin/Win64/cl.exe \
+ -I${MSSDK}/Include/prerelease -I${MSSDK}/Include/Win64/crt \
+ -I${MSSDK}/Include"
+ export RC="${MSSDK}/bin/rc.exe"
+ export lflags="-MACHINE:IA64 -LIBPATH:${MSSDK}/Lib/IA64 \
+ -LIBPATH:${MSSDK}/Lib/Prerelease/IA64"
+ export STLIB_LD="${MSSDK}/bin/win64/lib.exe -nologo ${lflags}"
+ export LINKBIN="${MSSDK}/bin/win64/link.exe ${lflags}"
+ CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d"
+ CFLAGS_OPTIMIZE="-nologo -O2 -Gs -W2 ${runtime}"
+ else
+ RC="rc"
+ STLIB_LD="lib -nologo"
+ LINKBIN="link -link50compat"
+ CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d"
+ CFLAGS_OPTIMIZE="-nologo -O2 -Gs -GD -W2 ${runtime}"
+ fi
+
+ if test "$MINGW32" = "yes"; then
+ # mingw gcc mode
+ CFLAGS_DEBUG="-g"
+ CFLAGS_OPTIMIZE="-O2"
+ SHLIB_LD="gcc -shared"
+ STLIB_LD='${AR} cr'
+ UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
+ LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}"
+ LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}"
+ else
+ SHLIB_LD="${LINKBIN} -dll -nologo"
+ UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.lib'
+ EXTRA_CFLAGS="-YX"
+ # For information on what debugtype is most useful, see:
+ # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp
+ # This essentially turns it all on.
+ LDFLAGS_DEBUG="-debug:full -debugtype:both -warn:2"
+ LDFLAGS_OPTIMIZE="-release"
+ LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}"
+ LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}"
+ PATHTYPE=-w
+ fi
+
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".dll"
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.dll'
+
+ TCL_LIB_VERSIONS_OK=nodots
+ # Bogus to avoid getting this turned off
+ DL_OBJS="tclLoadNone.obj"
+ ;;
+ AIX-*)
+ if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then
+ # AIX requires the _r compiler when gcc isn't being used
+ if test "${CC}" != "cc_r" ; then
+ CC=${CC}_r
+ fi
+ AC_MSG_RESULT([Using $CC for compiling with threads])
+ fi
+ LIBS="$LIBS -lc"
+ SHLIB_CFLAGS=""
+ SHLIB_SUFFIX=".so"
+ SHLIB_LD_LIBS='${LIBS}'
+ 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"
+ # AIX-5 has dl* in libc.so
+ DL_LIBS=""
+ if test "$GCC" = "yes" ; then
+ LD_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ else
+ LD_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}'
+ fi
+ else
+ SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry"
+ DL_LIBS="-ldl"
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ TCL_NEEDS_EXP_FILE=1
+ TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp'
+ fi
+ DL_OBJS="tclLoadDl.o"
+ LDFLAGS=""
+
+ # AIX v<=4.1 has some different flags than 4.2+
+ if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then
+ LIBOBJS="$LIBOBJS tclLoadAix.o"
+ DL_LIBS="-lld"
+ fi
+
+ # On AIX <=v4 systems, libbsd.a has to be linked in to support
+ # non-blocking file IO. This library has to be linked in after
+ # the MATH_LIBS or it breaks the pow() function. The way to
+ # insure proper sequencing, is to add it to the tail of MATH_LIBS.
+ # This library also supplies gettimeofday.
+ #
+ # AIX does not have a timezone field in struct tm. When the AIX
+ # bsd library is used, the timezone global and the gettimeofday
+ # methods are to be avoided for timezone deduction instead, we
+ # deduce the timezone by comparing the localtime result on a
+ # known GMT value.
+
+ AC_CHECK_LIB(bsd, gettimeofday, libbsd=yes, libbsd=no)
+ if test $libbsd = yes; then
+ MATH_LIBS="$MATH_LIBS -lbsd"
+ AC_DEFINE(USE_DELTA_FOR_TZ)
+ fi
+
+ # Check to enable 64-bit flags for compiler/linker on AIX 4+
+ if test "$do64bit" = "yes" -a "`uname -v`" -gt "3" ; then
+ if test "$GCC" = "yes" ; then
+ AC_MSG_WARN("64bit mode not supported with GCC on $system")
+ else
+ do64bit_ok=yes
+ EXTRA_CFLAGS="-q64"
+ LDFLAGS="-q64"
+ RANLIB="${RANLIB} -X64"
+ AR="${AR} -X64"
+ SHLIB_LDFLAGS="-b64"
+ fi
+ fi
+ ;;
+ BSD/OS-2.1*|BSD/OS-3*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="shlicc -r"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ BSD/OS-4.*)
+ SHLIB_CFLAGS="-export-dynamic -fPIC"
+ SHLIB_LD="cc -shared"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS="-export-dynamic"
+ LD_SEARCH_FLAGS=""
+ ;;
+ dgux*)
+ SHLIB_CFLAGS="-K PIC"
+ SHLIB_LD="cc -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ HP-UX-*.11.*)
+ # Use updated header definitions where possible
+ AC_DEFINE(_XOPEN_SOURCE_EXTENDED)
+
+ SHLIB_SUFFIX=".sl"
+ AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no)
+ if test "$tcl_ok" = yes; then
+ SHLIB_CFLAGS="+z"
+ SHLIB_LD="ld -b"
+ SHLIB_LD_LIBS='${LIBS}'
+ DL_OBJS="tclLoadShl.o"
+ DL_LIBS="-ldld"
+ LDFLAGS="-Wl,-E"
+ LD_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.'
+ fi
+
+ # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc
+ #EXTRA_CFLAGS="+DAportable"
+
+ # Check to enable 64-bit flags for compiler/linker
+ if test "$do64bit" = "yes" ; then
+ if test "$GCC" = "yes" ; then
+ hpux_arch=`gcc -dumpmachine`
+ case $hpux_arch in
+ hppa64*)
+ # 64-bit gcc in use. Fix flags for GNU ld.
+ do64bit_ok=yes
+ SHLIB_LD="gcc -shared"
+ SHLIB_LD_LIBS=""
+ LD_SEARCH_FLAGS=''
+ ;;
+ *)
+ AC_MSG_WARN("64bit mode not supported with GCC on $system")
+ ;;
+ esac
+ else
+ do64bit_ok=yes
+ EXTRA_CFLAGS="+DA2.0W"
+ LDFLAGS="+DA2.0W $LDFLAGS"
+ fi
+ fi
+ ;;
+ HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*)
+ SHLIB_SUFFIX=".sl"
+ AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no)
+ if test "$tcl_ok" = yes; then
+ SHLIB_CFLAGS="+z"
+ SHLIB_LD="ld -b"
+ SHLIB_LD_LIBS=""
+ DL_OBJS="tclLoadShl.o"
+ DL_LIBS="-ldld"
+ LDFLAGS="-Wl,-E"
+ LD_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.'
+ fi
+ ;;
+ IRIX-4.*)
+ SHLIB_CFLAGS="-G 0"
+ SHLIB_SUFFIX=".a"
+ SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0"
+ SHLIB_LD_LIBS='${LIBS}'
+ DL_OBJS="tclLoadAout.o"
+ DL_LIBS=""
+ LDFLAGS="-Wl,-D,08000000"
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ SHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}.a'
+ ;;
+ IRIX-5.*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="ld -shared -rdata_shared"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ EXTRA_CFLAGS=""
+ LDFLAGS=""
+ ;;
+ IRIX-6.*|IRIX64-6.5*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="ld -n32 -shared -rdata_shared"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ if test "$GCC" = "yes" ; then
+ EXTRA_CFLAGS="-mabi=n32"
+ LDFLAGS="-mabi=n32"
+ else
+ case $system in
+ IRIX-6.3)
+ # Use to build 6.2 compatible binaries on 6.3.
+ EXTRA_CFLAGS="-n32 -D_OLD_TERMIOS"
+ ;;
+ *)
+ EXTRA_CFLAGS="-n32"
+ ;;
+ esac
+ LDFLAGS="-n32"
+ fi
+ ;;
+ IRIX64-6.*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="ld -n32 -shared -rdata_shared"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+
+ # Check to enable 64-bit flags for compiler/linker
+
+ if test "$do64bit" = "yes" ; then
+ if test "$GCC" = "yes" ; then
+ AC_MSG_WARN([64bit mode not supported by gcc])
+ else
+ do64bit_ok=yes
+ SHLIB_LD="ld -64 -shared -rdata_shared"
+ EXTRA_CFLAGS="-64"
+ LDFLAGS="-64"
+ fi
+ fi
+ ;;
+ Linux*)
+ SHLIB_CFLAGS="-fPIC"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+
+ # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings
+ # when you inline the string and math operations. Turn this off to
+ # get rid of the warnings.
+
+ CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES"
+
+ if test "$have_dl" = yes; then
+ SHLIB_LD="${CC} -shared"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS="-rdynamic"
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ else
+ AC_CHECK_HEADER(dld.h, [
+ SHLIB_LD="ld -shared"
+ DL_OBJS="tclLoadDld.o"
+ DL_LIBS="-ldld"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""])
+ fi
+ if test "`uname -m`" = "alpha" ; then
+ EXTRA_CFLAGS="-mieee"
+ 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"${LIBOBJS}" != x ; then
+ EXTRA_CFLAGS="${EXTRA_CFLAGS} -fno-inline"
+ fi
+
+ ;;
+ GNU*)
+ SHLIB_CFLAGS="-fPIC"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+
+ if test "$have_dl" = yes; then
+ SHLIB_LD="${CC} -shared"
+ DL_OBJS=""
+ DL_LIBS="-ldl"
+ LDFLAGS="-rdynamic"
+ LD_SEARCH_FLAGS=""
+ else
+ AC_CHECK_HEADER(dld.h, [
+ SHLIB_LD="ld -shared"
+ DL_OBJS=""
+ DL_LIBS="-ldld"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""])
+ fi
+ if test "`uname -m`" = "alpha" ; then
+ EXTRA_CFLAGS="-mieee"
+ fi
+ ;;
+ MP-RAS-02*)
+ SHLIB_CFLAGS="-K PIC"
+ SHLIB_LD="cc -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ MP-RAS-*)
+ SHLIB_CFLAGS="-K PIC"
+ SHLIB_LD="cc -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS="-Wl,-Bexport"
+ LD_SEARCH_FLAGS=""
+ ;;
+ NetBSD-*|FreeBSD-[[1-2]].*|OpenBSD-*)
+ # Not available on all versions: check for include file.
+ AC_CHECK_HEADER(dlfcn.h, [
+ # NetBSD/SPARC needs -fPIC, -fpic will not do.
+ SHLIB_CFLAGS="-fPIC"
+ SHLIB_LD="ld -Bshareable -x"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ AC_MSG_CHECKING([for ELF])
+ AC_EGREP_CPP(yes, [
+#ifdef __ELF__
+ yes
+#endif
+ ],
+ AC_MSG_RESULT([yes])
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so',
+ AC_MSG_RESULT([no])
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0'
+ )
+ ], [
+ SHLIB_CFLAGS=""
+ SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".a"
+ DL_OBJS="tclLoadAout.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
+ ])
+
+ # FreeBSD doesn't handle version numbers with dots.
+
+ UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
+ TCL_LIB_VERSIONS_OK=nodots
+ ;;
+ FreeBSD-*)
+ # FreeBSD 3.* and greater have ELF.
+ SHLIB_CFLAGS="-fPIC"
+ SHLIB_LD="ld -Bshareable -x"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LDFLAGS="-export-dynamic"
+ LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
+ if test "${TCL_THREADS}" = "1" ; then
+ # The -pthread needs to go in the CFLAGS, not LIBS
+ LIBS=`echo $LIBS | sed s/-pthread//`
+ EXTRA_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}\$\{DBGX\}.a'
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so'
+ TCL_LIB_VERSIONS_OK=nodots
+ ;;
+ esac
+ ;;
+ Rhapsody-*|Darwin-*)
+ SHLIB_CFLAGS="-fno-common"
+ SHLIB_LD="cc -dynamiclib \${LDFLAGS}"
+ TCL_SHLIB_LD_EXTRAS="-compatibility_version ${TCL_MAJOR_VERSION} -current_version \${VERSION} -install_name \${LIB_RUNTIME_DIR}/\${TCL_LIB_FILE} -prebind -seg1addr 0xa000000"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".dylib"
+ DL_OBJS="tclLoadDyld.o"
+ DL_LIBS=""
+ LDFLAGS="-prebind"
+ LD_SEARCH_FLAGS=""
+ CFLAGS_OPTIMIZE="-O3"
+ EXTRA_CFLAGS="-arch ppc -pipe"
+ ;;
+ NEXTSTEP-*)
+ SHLIB_CFLAGS=""
+ SHLIB_LD="cc -nostdlib -r"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadNext.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ OS/390-*)
+ CFLAGS_OPTIMIZE="" # Optimizer is buggy
+ AC_DEFINE(_OE_SOCKETS) # needed in sys/socket.h
+ ;;
+ OSF1-1.0|OSF1-1.1|OSF1-1.2)
+ # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1
+ SHLIB_CFLAGS=""
+ # Hack: make package name same as library name
+ SHLIB_LD='ld -R -export $@:'
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadOSF.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ OSF1-1.*)
+ # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2
+ SHLIB_CFLAGS="-fPIC"
+ if test "$SHARED_BUILD" = "1" ; then
+ SHLIB_LD="ld -shared"
+ else
+ SHLIB_LD="ld -non_shared"
+ fi
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ 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_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}'
+ if test "$GCC" != "yes" ; then
+ EXTRA_CFLAGS="-DHAVE_TZSET -std1"
+ fi
+ # see pthread_intro(3) for pthread support on osf1, k.furukawa
+ if test "${TCL_THREADS}" = "1" ; then
+ EXTRA_CFLAGS="${EXTRA_CFLAGS} -DHAVE_PTHREAD_ATTR_SETSTACKSIZE"
+ EXTRA_CFLAGS="${EXTRA_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
+ EXTRA_CFLAGS="${EXTRA_CFLAGS} -pthread"
+ 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"
+ DL_OBJS="tclLoadDl.o"
+ # dlopen is in -lc on QNX
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ RISCos-*)
+ SHLIB_CFLAGS="-G 0"
+ SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0"
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".a"
+ DL_OBJS="tclLoadAout.o"
+ DL_LIBS=""
+ LDFLAGS="-Wl,-D,08000000"
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ ;;
+ SCO_SV-3.2*)
+ # Note, dlopen is available only on SCO 3.2.5 and greater. However,
+ # this test works, since "uname -s" was non-standard in 3.2.4 and
+ # below.
+ if test "$GCC" = "yes" ; then
+ SHLIB_CFLAGS="-fPIC -melf"
+ LDFLAGS="-melf -Wl,-Bexport"
+ else
+ SHLIB_CFLAGS="-Kpic -belf"
+ LDFLAGS="-belf -Wl,-Bexport"
+ fi
+ SHLIB_LD="ld -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ SINIX*5.4*)
+ SHLIB_CFLAGS="-K PIC"
+ SHLIB_LD="cc -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ ;;
+ SunOS-4*)
+ SHLIB_CFLAGS="-PIC"
+ SHLIB_LD="ld"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+
+ # SunOS can't handle version numbers with dots in them in library
+ # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it
+ # requires an extra version number at the end of .so file names.
+ # So, the library has to have a name like libtcl75.so.1.0
+
+ SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0'
+ UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
+ TCL_LIB_VERSIONS_OK=nodots
+ ;;
+ SunOS-5.[[0-6]]*)
+
+ # Note: If _REENTRANT isn't defined, then Solaris
+ # won't define thread-safe library routines.
+
+ AC_DEFINE(_REENTRANT)
+ AC_DEFINE(_POSIX_PTHREAD_SEMANTICS)
+
+ SHLIB_CFLAGS="-KPIC"
+
+ # Note: need the LIBS below, otherwise Tk won't find Tcl's
+ # symbols when dynamically loaded into tclsh.
+
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ LDFLAGS=""
+ if test "$GCC" = "yes" ; then
+ SHLIB_LD="$CC -shared"
+ LD_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ else
+ SHLIB_LD="/usr/ccs/bin/ld -G -z text"
+ LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
+ fi
+ ;;
+ SunOS-5*)
+
+ # Note: If _REENTRANT isn't defined, then Solaris
+ # won't define thread-safe library routines.
+
+ AC_DEFINE(_REENTRANT)
+ AC_DEFINE(_POSIX_PTHREAD_SEMANTICS)
+
+ SHLIB_CFLAGS="-KPIC"
+ LDFLAGS=""
+
+ # 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
+ AC_MSG_WARN("64bit mode not supported with GCC on $system")
+ else
+ do64bit_ok=yes
+ if test "$do64bitVIS" = "yes" ; then
+ EXTRA_CFLAGS="-xarch=v9a"
+ LDFLAGS="-xarch=v9a"
+ else
+ EXTRA_CFLAGS="-xarch=v9"
+ LDFLAGS="-xarch=v9"
+ fi
+ fi
+ else
+ AC_MSG_WARN("64bit mode only supported sparcv9 system")
+ fi
+ fi
+
+ # Note: need the LIBS below, otherwise Tk won't find Tcl's
+ # symbols when dynamically loaded into tclsh.
+
+ SHLIB_LD_LIBS='${LIBS}'
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ if test "$GCC" = "yes" ; then
+ SHLIB_LD="$CC -shared"
+ LD_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
+ else
+ SHLIB_LD="/usr/ccs/bin/ld -G -z text"
+ LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
+ fi
+ ;;
+ ULTRIX-4.*)
+ SHLIB_CFLAGS="-G 0"
+ SHLIB_SUFFIX=".a"
+ SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0"
+ SHLIB_LD_LIBS='${LIBS}'
+ DL_OBJS="tclLoadAout.o"
+ DL_LIBS=""
+ LDFLAGS="-Wl,-D,08000000"
+ LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
+ if test "$GCC" != "yes" ; then
+ EXTRA_CFLAGS="-DHAVE_TZSET -std1"
+ fi
+ ;;
+ UNIX_SV* | UnixWare-5*)
+ SHLIB_CFLAGS="-KPIC"
+ SHLIB_LD="cc -G"
+ SHLIB_LD_LIBS=""
+ SHLIB_SUFFIX=".so"
+ DL_OBJS="tclLoadDl.o"
+ DL_LIBS="-ldl"
+ # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers
+ # that don't grok the -Bexport option. Test that it does.
+ hold_ldflags=$LDFLAGS
+ AC_MSG_CHECKING([for ld accepts -Bexport flag])
+ LDFLAGS="${LDFLAGS} -Wl,-Bexport"
+ AC_TRY_LINK(, [int i;], found=yes, found=no)
+ LDFLAGS=$hold_ldflags
+ AC_MSG_RESULT([$found])
+ if test $found = yes; then
+ LDFLAGS="-Wl,-Bexport"
+ else
+ LDFLAGS=""
+ fi
+ LD_SEARCH_FLAGS=""
+ ;;
+ esac
+
+ if test "$do64bit" = "yes" -a "$do64bit_ok" = "no" ; then
+ AC_MSG_WARN("64bit support being disabled -- don\'t know magic for this platform")
+ fi
+
+ # Step 4: If pseudo-static linking is in use (see K. B. Kenny, "Dynamic
+ # Loading for Tcl -- What Became of It?". Proc. 2nd Tcl/Tk Workshop,
+ # New Orleans, LA, Computerized Processes Unlimited, 1994), then we need
+ # to determine which of several header files defines the a.out file
+ # format (a.out.h, sys/exec.h, or sys/exec_aout.h). At present, we
+ # support only a file format that is more or less version-7-compatible.
+ # In particular,
+ # - a.out files must begin with `struct exec'.
+ # - the N_TXTOFF on the `struct exec' must compute the seek address
+ # of the text segment
+ # - The `struct exec' must contain a_magic, a_text, a_data, a_bss
+ # and a_entry fields.
+ # The following compilation should succeed if and only if either sys/exec.h
+ # or a.out.h is usable for the purpose.
+ #
+ # Note that the modified COFF format used on MIPS Ultrix 4.x is usable; the
+ # `struct exec' includes a second header that contains information that
+ # duplicates the v7 fields that are needed.
+
+ if test "x$DL_OBJS" = "xtclLoadAout.o" ; then
+ AC_MSG_CHECKING([sys/exec.h])
+ AC_TRY_COMPILE([#include <sys/exec.h>],[
+ struct exec foo;
+ unsigned long seek;
+ int flag;
+#if defined(__mips) || defined(mips)
+ seek = N_TXTOFF (foo.ex_f, foo.ex_o);
+#else
+ seek = N_TXTOFF (foo);
+#endif
+ flag = (foo.a_magic == OMAGIC);
+ return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry;
+ ], tcl_ok=usable, tcl_ok=unusable)
+ AC_MSG_RESULT([$tcl_ok])
+ if test $tcl_ok = usable; then
+ AC_DEFINE(USE_SYS_EXEC_H)
+ else
+ AC_MSG_CHECKING([a.out.h])
+ AC_TRY_COMPILE([#include <a.out.h>],[
+ struct exec foo;
+ unsigned long seek;
+ int flag;
+#if defined(__mips) || defined(mips)
+ seek = N_TXTOFF (foo.ex_f, foo.ex_o);
+#else
+ seek = N_TXTOFF (foo);
+#endif
+ flag = (foo.a_magic == OMAGIC);
+ return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry;
+ ], tcl_ok=usable, tcl_ok=unusable)
+ AC_MSG_RESULT([$tcl_ok])
+ if test $tcl_ok = usable; then
+ AC_DEFINE(USE_A_OUT_H)
+ else
+ AC_MSG_CHECKING([sys/exec_aout.h])
+ AC_TRY_COMPILE([#include <sys/exec_aout.h>],[
+ struct exec foo;
+ unsigned long seek;
+ int flag;
+#if defined(__mips) || defined(mips)
+ seek = N_TXTOFF (foo.ex_f, foo.ex_o);
+#else
+ seek = N_TXTOFF (foo);
+#endif
+ flag = (foo.a_midmag == OMAGIC);
+ return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry;
+ ], tcl_ok=usable, tcl_ok=unusable)
+ AC_MSG_RESULT([$tcl_ok])
+ if test $tcl_ok = usable; then
+ AC_DEFINE(USE_SYS_EXEC_AOUT_H)
+ else
+ DL_OBJS=""
+ fi
+ fi
+ fi
+ fi
+
+ # Step 5: disable dynamic loading if requested via a command-line switch.
+
+ AC_ARG_ENABLE(load, [ --disable-load disallow dynamic loading and "load" command],
+ [tcl_ok=$enableval], [tcl_ok=yes])
+ if test "$tcl_ok" = "no"; then
+ DL_OBJS=""
+ fi
+
+ if test "x$DL_OBJS" != "x" ; then
+ BUILD_DLTEST="\$(DLTEST_TARGETS)"
+ else
+ echo "Can't figure out how to do dynamic loading or shared libraries"
+ echo "on this system."
+ SHLIB_CFLAGS=""
+ SHLIB_LD=""
+ SHLIB_SUFFIX=""
+ DL_OBJS="tclLoadNone.o"
+ DL_LIBS=""
+ LDFLAGS=""
+ LD_SEARCH_FLAGS=""
+ BUILD_DLTEST=""
+ fi
+
+ # 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 "$DL_OBJS" != "tclLoadNone.o" ; then
+ if test "$GCC" = "yes" ; then
+ case $system in
+ AIX-*)
+ ;;
+ BSD/OS*)
+ ;;
+ IRIX*)
+ ;;
+ NetBSD-*|FreeBSD-*|OpenBSD-*)
+ ;;
+ Rhapsody-*|Darwin-*)
+ ;;
+ RISCos-*)
+ ;;
+ SCO_SV-3.2*)
+ ;;
+ ULTRIX-4.*)
+ ;;
+ windows)
+ if test "$MINGW32" != "yes"; then
+ SHLIB_CFLAGS="-fPIC"
+ fi
+ ;;
+ *)
+ SHLIB_CFLAGS="-fPIC"
+ ;;
+ esac
+ fi
+ fi
+
+ if test "$SHARED_LIB_SUFFIX" = "" ; then
+ SHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}${SHLIB_SUFFIX}'
+ fi
+ if test "$UNSHARED_LIB_SUFFIX" = "" ; then
+ UNSHARED_LIB_SUFFIX='${VERSION}\$\{DBGX\}.a'
+ fi
+
+ AC_SUBST(DL_LIBS)
+ AC_SUBST(CFLAGS_DEBUG)
+ AC_SUBST(CFLAGS_OPTIMIZE)
+ AC_SUBST(CFLAGS_WARNING)
+ AC_SUBST(EXTRA_CFLAGS)
+
+ SHLIB_LDFLAGS='$(LDFLAGS_DEFAULT)'
+ AC_SUBST(STLIB_LD)
+ AC_SUBST(SHLIB_LD)
+ AC_SUBST(SHLIB_CFLAGS)
+ AC_SUBST(SHLIB_LDFLAGS)
+ AC_SUBST(SHLIB_LD_LIBS)
+ AC_SUBST(LDFLAGS_DEBUG)
+ AC_SUBST(LDFLAGS_OPTIMIZE)
+])
+
+#--------------------------------------------------------------------
+# 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_MSG_CHECKING([termios vs. termio vs. sgtty])
+ AC_CACHE_VAL(tcl_cv_api_serial, [
+ AC_TRY_RUN([
+#include <termios.h>
+
+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 <termio.h>
+
+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 <sgtty.h>
+
+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=none, tcl_cv_api_serial=none)
+ fi
+ if test $tcl_cv_api_serial = no ; then
+ AC_TRY_RUN([
+#include <termios.h>
+#include <errno.h>
+
+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 <termio.h>
+#include <errno.h>
+
+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 <sgtty.h>
+#include <errno.h>
+
+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);;
+ termio) AC_DEFINE(USE_TERMIO);;
+ sgtty) AC_DEFINE(USE_SGTTY);;
+ esac
+ AC_MSG_RESULT([$tcl_cv_api_serial])
+])
+
+#--------------------------------------------------------------------
+# TEA_MISSING_POSIX_HEADERS
+#
+# Supply substitutes for missing POSIX header files. Special
+# notes:
+# - stdlib.h doesn't define strtol, strtoul, or
+# strtod insome 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
+# NO_LIMITS_H
+# NO_STDLIB_H
+# NO_STRING_H
+# NO_SYS_WAIT_H
+# NO_DLFCN_H
+# HAVE_UNISTD_H
+# HAVE_SYS_PARAM_H
+#
+# HAVE_STRING_H ?
+#
+#--------------------------------------------------------------------
+
+AC_DEFUN(TEA_MISSING_POSIX_HEADERS, [
+ AC_MSG_CHECKING([dirent.h])
+ AC_TRY_LINK([#include <sys/types.h>
+#include <dirent.h>], [
+#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_ok=yes, tcl_ok=no)
+
+ if test $tcl_ok = no; then
+ AC_DEFINE(NO_DIRENT_H)
+ fi
+
+ AC_MSG_RESULT([$tcl_ok])
+ AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H)])
+ AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H)])
+ AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H)])
+ AC_CHECK_HEADER(limits.h, , [AC_DEFINE(NO_LIMITS_H)])
+ 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)
+ 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)
+ fi
+
+ AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H)])
+ AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H)])
+
+ # OS/390 lacks sys/param.h (and doesn't need it, by chance).
+
+ AC_HAVE_HEADERS(unistd.h 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
+# LIBS (appends to)
+#
+#--------------------------------------------------------------------
+
+AC_DEFUN(TEA_PATH_X, [
+ if test "${TEA_PLATFORM}" = "unix" ; 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 <X11/XIntrinsic.h>], , 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])
+ XINCLUDES="# no special path needed"
+ AC_TRY_CPP([#include <X11/Intrinsic.h>], , XINCLUDES="nope")
+ if test "$XINCLUDES" = nope; 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"
+ break
+ fi
+ done
+ fi
+ else
+ if test "$x_includes" != ""; then
+ XINCLUDES=-I$x_includes
+ else
+ XINCLUDES="# no special path needed"
+ fi
+ fi
+ if test "$XINCLUDES" = nope; then
+ AC_MSG_RESULT([could not find any!])
+ XINCLUDES="# no include files found"
+ 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; 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
+ if test x"${XLIBSW}" != x ; then
+ LIBS="${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)
+ AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O])
+ if test -f /usr/lib/NextStep/software_version; then
+ system=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version`
+ else
+ system=`uname -s`-`uname -r`
+ if test "$?" -ne 0 ; then
+ system=unknown
+ else
+ # Special check for weird MP-RAS system (uname returns weird
+ # results, and the version is kept in special file).
+
+ if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then
+ system=MP-RAS-`awk '{print $3}' /etc/.relid'`
+ fi
+ if test "`uname -s`" = "AIX" ; then
+ system=AIX-`uname -v`.`uname -r`
+ fi
+ fi
+ fi
+ case $system in
+ # There used to be code here to use FIONBIO under AIX. However, it
+ # was reported that FIONBIO doesn't work under AIX 3.2.5. Since
+ # using O_NONBLOCK seems fine under AIX 4.*, I removed the FIONBIO
+ # code (JO, 5/31/97).
+
+ OSF*)
+ AC_DEFINE(USE_FIONBIO)
+ AC_MSG_RESULT([FIONBIO])
+ ;;
+ SunOS-4*)
+ AC_DEFINE(USE_FIONBIO)
+ AC_MSG_RESULT([FIONBIO])
+ ;;
+ ULTRIX-4.*)
+ AC_DEFINE(USE_FIONBIO)
+ AC_MSG_RESULT([FIONBIO])
+ ;;
+ *)
+ AC_MSG_RESULT([O_NONBLOCK])
+ ;;
+ esac
+])
+
+#--------------------------------------------------------------------
+# TEA_TIME_HANLDER
+#
+# 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_MSG_CHECKING([tm_tzadj in struct tm])
+ AC_CACHE_VAL(tcl_cv_member_tm_tzadj,
+ AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_tzadj;],
+ tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no))
+ AC_MSG_RESULT([$tcl_cv_member_tm_tzadj])
+ if test $tcl_cv_member_tm_tzadj = yes ; then
+ AC_DEFINE(HAVE_TM_TZADJ)
+ fi
+
+ AC_MSG_CHECKING([tm_gmtoff in struct tm])
+ AC_CACHE_VAL(tcl_cv_member_tm_gmtoff,
+ AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_gmtoff;],
+ tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no))
+ AC_MSG_RESULT([$tcl_cv_member_tm_gmtoff])
+ if test $tcl_cv_member_tm_gmtoff = yes ; then
+ AC_DEFINE(HAVE_TM_GMTOFF)
+ fi
+
+ #
+ # Its important to include time.h in this check, as some systems
+ # (like convex) have timezone functions, etc.
+ #
+ AC_MSG_CHECKING([long timezone variable])
+ AC_CACHE_VAL(tcl_cv_var_timezone,
+ AC_TRY_COMPILE([#include <time.h>],
+ [extern long timezone;
+ timezone += 1;
+ exit (0);],
+ tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no))
+ AC_MSG_RESULT([$tcl_cv_timezone_long])
+ if test $tcl_cv_timezone_long = yes ; then
+ AC_DEFINE(HAVE_TIMEZONE_VAR)
+ else
+ #
+ # On some systems (eg IRIX 6.2), timezone is a time_t and not a long.
+ #
+ AC_MSG_CHECKING([time_t timezone variable])
+ AC_CACHE_VAL(tcl_cv_timezone_time,
+ AC_TRY_COMPILE([#include <time.h>],
+ [extern time_t timezone;
+ timezone += 1;
+ exit (0);],
+ tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no))
+ AC_MSG_RESULT([$tcl_cv_timezone_time])
+ if test $tcl_cv_timezone_time = yes ; then
+ AC_DEFINE(HAVE_TIMEZONE_VAR)
+ 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_MSG_CHECKING([for Solaris2.4/Tru64 strtod bugs])
+ AC_TRY_RUN([
+ extern double strtod();
+ int main()
+ {
+ char *string = "NaN", *spaceString = " ";
+ char *term;
+ double value;
+ value = strtod(string, &term);
+ if ((term != string) && (term[-1] == 0)) {
+ exit(1);
+ }
+ value = strtod(spaceString, &term);
+ if (term == (spaceString+1)) {
+ exit(1);
+ }
+ exit(0);
+ }], tcl_ok=1, tcl_ok=0, tcl_ok=0)
+ if test "$tcl_ok" = 1; then
+ AC_MSG_RESULT([ok])
+ else
+ AC_MSG_RESULT([buggy])
+ LIBOBJS="$LIBOBJS fixstrtod.o"
+ AC_DEFINE(strtod, fixstrtod)
+ 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
+# 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))
+
+ #--------------------------------------------------------------------
+ # 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"])])
+
+ # 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
+#
+#--------------------------------------------------------------------
+
+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)
+ 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 <stdlib.h>],
+ [char *p = (char *)strtoll; char *q = (char *)strtoull;])
+ TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include <sys/stat.h>],
+ [struct stat64 buf; int i = stat64("/", &buf);])
+ 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,[
+ AC_TRY_COMPILE(,[__int64 value = (__int64) 0;],
+ tcl_cv_type_64bit=__int64,tcl_cv_type_64bit=none
+ AC_TRY_RUN([#include <unistd.h>
+ int main() {exit(!(sizeof(long long) > sizeof(long)));}
+ ], tcl_cv_type_64bit="long long"))])
+ if test "${tcl_cv_type_64bit}" = none ; then
+ AC_MSG_RESULT([using long])
+ else
+ AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit})
+ AC_MSG_RESULT([${tcl_cv_type_64bit}])
+
+ # Now check for auxiliary declarations
+ AC_MSG_CHECKING([for struct dirent64])
+ AC_CACHE_VAL(tcl_cv_struct_dirent64,[
+ AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/dirent.h>],[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)
+ fi
+ AC_MSG_RESULT([${tcl_cv_struct_dirent64}])
+
+ AC_MSG_CHECKING([for struct stat64])
+ AC_CACHE_VAL(tcl_cv_struct_stat64,[
+ AC_TRY_COMPILE([#include <sys/stat.h>],[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)
+ fi
+ AC_MSG_RESULT([${tcl_cv_struct_stat64}])
+
+ AC_MSG_CHECKING([for off64_t])
+ AC_CACHE_VAL(tcl_cv_type_off64_t,[
+ AC_TRY_COMPILE([#include <sys/types.h>],[off64_t offset;
+],
+ tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)])
+ if test "x${tcl_cv_type_off64_t}" = "xyes" ; then
+ AC_DEFINE(HAVE_TYPE_OFF64_T)
+ fi
+ AC_MSG_RESULT([${tcl_cv_type_off64_t}])
+ 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_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, [
+ AC_MSG_CHECKING([for correct TEA configuration])
+ if test x"${PACKAGE}" = x ; then
+ AC_MSG_ERROR([
+The PACKAGE variable must be defined by your TEA configure.in])
+ fi
+ AC_MSG_RESULT([ok])
+ TEA_INITED=ok
+ case "`uname -s`" in
+ *win32*|*WIN32*|*CYGWIN_NT*|*CYGWIN_9*|*CYGWIN_ME*|*MINGW32_*)
+ AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo)
+ EXEEXT=".exe"
+ TEA_PLATFORM="windows"
+ ;;
+ *)
+ CYGPATH=echo
+ EXEEXT=""
+ TEA_PLATFORM="unix"
+ ;;
+ esac
+
+ AC_SUBST(EXEEXT)
+ AC_SUBST(CYGPATH)
+])
+
+#------------------------------------------------------------------------
+# 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, [
+ # Should be AC_MSG_NOTICE, but that requires autoconf 2.50
+ if test "${prefix}" = "NONE"; then
+ prefix_default=yes
+ if test x"${TCL_PREFIX}" != x; then
+ AC_MSG_WARN([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}])
+ prefix=${TCL_PREFIX}
+ else
+ prefix=/usr/local
+ fi
+ fi
+ if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" ; then
+ if test x"${TCL_EXEC_PREFIX}" != x; then
+ AC_MSG_WARN([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}])
+ exec_prefix=${TCL_EXEC_PREFIX}
+ else
+ exec_prefix=$prefix
+ fi
+ fi
+])
+
+#------------------------------------------------------------------------
+# TEA_PROG_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, [
+ # 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
+
+ #------------------------------------------------------------------------
+ # 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_MSG_CHECKING([if the compiler understands -pipe])
+ OLDCC="$CC"
+ CC="$CC -pipe"
+ AC_TRY_COMPILE(,, AC_MSG_RESULT([yes]), CC="$OLDCC"
+ AC_MSG_RESULT([no]))
+ fi
+
+ 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_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
+#------------------------------------------------------------------------
+
+AC_DEFUN(TEA_MAKE_LIB, [
+ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then
+ MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(\[$](PACKAGE)_OBJECTS)"
+ MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LDFLAGS} \${SHLIB_LD_LIBS} \$(LDFLAGS) -out:\[$]@ \$(\[$](PACKAGE)_OBJECTS)"
+ MAKE_STUB_LIB="\${STLIB_LD} -out:\[$]@ \$(\[$](PACKAGE)stub_OBJECTS)"
+ else
+ MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(\[$](PACKAGE)_OBJECTS)"
+ MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(\[$](PACKAGE)_OBJECTS) \${SHLIB_LDFLAGS} \${SHLIB_LD_LIBS}"
+ MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(\[$](PACKAGE)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 the ${DBGX} in the suffix is
+ # substituted.
+ #--------------------------------------------------------------------
+
+ 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 "${PACKAGE}_LIB_FILE=${PACKAGE}${SHARED_LIB_SUFFIX}"
+ RANLIB=:
+ else
+ eval eval "${PACKAGE}_LIB_FILE=${PACKAGE}${UNSHARED_LIB_SUFFIX}"
+ fi
+ # Some packages build there own stubs libraries
+ eval eval "${PACKAGE}stub_LIB_FILE=${PACKAGE}stub${UNSHARED_LIB_SUFFIX}"
+ else
+ 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 "${PACKAGE}_LIB_FILE=lib${PACKAGE}${SHARED_LIB_SUFFIX}"
+ RANLIB=:
+ else
+ eval eval "${PACKAGE}_LIB_FILE=lib${PACKAGE}${UNSHARED_LIB_SUFFIX}"
+ fi
+ # Some packages build there own stubs libraries
+ eval eval "${PACKAGE}stub_LIB_FILE=lib${PACKAGE}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)
+])
+
+#------------------------------------------------------------------------
+# 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/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_GENERIC_DIR_NATIVE
+# TCL_UNIX_DIR_NATIVE
+# TCL_WIN_DIR_NATIVE
+# TCL_BMAP_DIR_NATIVE
+# TCL_TOOL_DIR_NATIVE
+# TCL_PLATFORM_DIR_NATIVE
+# TCL_BIN_DIR_NATIVE
+# TCL_INCLUDES
+#------------------------------------------------------------------------
+
+AC_DEFUN(TEA_PRIVATE_TCL_HEADERS, [
+ AC_MSG_CHECKING([for Tcl private include files])
+
+ if test "${TEA_PLATFORM}" = "windows"; then
+ TCL_TOP_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}`\"
+ TCL_GENERIC_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/generic`\"
+ TCL_UNIX_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/unix`\"
+ TCL_WIN_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/win`\"
+ TCL_BMAP_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/bitmaps`\"
+ TCL_TOOL_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/tools`\"
+ TCL_COMPAT_DIR_NATIVE=\"`${CYGPATH} ${TCL_SRC_DIR}/compat`\"
+ TCL_PLATFORM_DIR_NATIVE=${TCL_WIN_DIR_NATIVE}
+ else
+ TCL_TOP_DIR_NATIVE='$(TCL_SRC_DIR)'
+ TCL_GENERIC_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/generic'
+ TCL_UNIX_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/unix'
+ TCL_WIN_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/win'
+ TCL_BMAP_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/bitmaps'
+ TCL_TOOL_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/tools'
+ TCL_COMPAT_DIR_NATIVE='$(TCL_TOP_DIR_NATIVE)/compat'
+ TCL_PLATFORM_DIR_NATIVE=${TCL_UNIX_DIR_NATIVE}
+ fi
+
+ AC_SUBST(TCL_TOP_DIR_NATIVE)
+ AC_SUBST(TCL_GENERIC_DIR_NATIVE)
+ AC_SUBST(TCL_UNIX_DIR_NATIVE)
+ AC_SUBST(TCL_WIN_DIR_NATIVE)
+ AC_SUBST(TCL_BMAP_DIR_NATIVE)
+ AC_SUBST(TCL_TOOL_DIR_NATIVE)
+ AC_SUBST(TCL_PLATFORM_DIR_NATIVE)
+
+ TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}"
+ AC_SUBST(TCL_INCLUDES)
+ AC_MSG_RESULT([Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}])
+])
+
+#------------------------------------------------------------------------
+# 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
+ # Check order: pkg --prefix location, Tcl's --prefix location,
+ # directory of tclConfig.sh, and Tcl source directory.
+ # Looking in the source dir is not ideal, but OK.
+
+ eval "temp_includedir=${includedir}"
+ 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` \
+ `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`"
+ if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then
+ list="$list /usr/local/include /usr/include"
+ 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, [
+ AC_MSG_CHECKING([for Tk private include files])
+
+ if test "${TEA_PLATFORM}" = "windows"; then
+ TK_TOP_DIR_NATIVE=\"`${CYGPATH} ${TK_SRC_DIR}`\"
+ TK_UNIX_DIR_NATIVE=\"`${CYGPATH} ${TK_SRC_DIR}/unix`\"
+ TK_WIN_DIR_NATIVE=\"`${CYGPATH} ${TK_SRC_DIR}/win`\"
+ TK_GENERIC_DIR_NATIVE=\"`${CYGPATH} ${TK_SRC_DIR}/generic`\"
+ TK_XLIB_DIR_NATIVE=\"`${CYGPATH} ${TK_SRC_DIR}/xlib`\"
+ TK_PLATFORM_DIR_NATIVE=${TK_WIN_DIR_NATIVE}
+
+ TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE} -I${TK_XLIB_DIR_NATIVE}"
+ else
+ TK_TOP_DIR_NATIVE='$(TK_SRC_DIR)'
+ TK_GENERIC_DIR_NATIVE='$(TK_TOP_DIR_NATIVE)/generic'
+ TK_UNIX_DIR_NATIVE='$(TK_TOP_DIR_NATIVE)/unix'
+ TK_WIN_DIR_NATIVE='$(TK_TOP_DIR_NATIVE)/win'
+ TK_PLATFORM_DIR_NATIVE=${TK_UNIX_DIR_NATIVE}
+
+ TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}"
+ fi
+
+ AC_SUBST(TK_TOP_DIR_NATIVE)
+ AC_SUBST(TK_UNIX_DIR_NATIVE)
+ AC_SUBST(TK_WIN_DIR_NATIVE)
+ AC_SUBST(TK_GENERIC_DIR_NATIVE)
+ AC_SUBST(TK_XLIB_DIR_NATIVE)
+ AC_SUBST(TK_PLATFORM_DIR_NATIVE)
+
+ AC_SUBST(TK_INCLUDES)
+ AC_MSG_RESULT([Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}])
+])
+
+#------------------------------------------------------------------------
+# 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
+ # Check order: pkg --prefix location, Tcl's --prefix location,
+ # directory of tclConfig.sh, and Tcl source directory.
+ # Looking in the source dir is not ideal, but OK.
+
+ eval "temp_includedir=${includedir}"
+ list="`ls -d ${temp_includedir} 2>/dev/null` \
+ `ls -d ${TK_PREFIX}/include 2>/dev/null` \
+ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \
+ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null` \
+ `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`"
+ if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then
+ list="$list /usr/local/include /usr/include"
+ 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)
+])
+
+#------------------------------------------------------------------------
+# TEA_PROG_TCLSH
+# Locate a tclsh shell in the following directories:
+# ${TCL_BIN_DIR} ${TCL_BIN_DIR}/../bin
+# ${exec_prefix}/bin ${prefix}/bin
+# ${PATH}
+#
+# Arguments
+# none
+#
+# Results
+# Subst's the following values:
+# TCLSH_PROG
+#------------------------------------------------------------------------
+
+AC_DEFUN(TEA_PROG_TCLSH, [
+ AC_MSG_CHECKING([for tclsh])
+
+ AC_CACHE_VAL(ac_cv_path_tclsh, [
+ search_path=`echo ${TCL_BIN_DIR}:${TCL_BIN_DIR}/../bin:${exec_prefix}/bin:${prefix}/bin:${PATH} | sed -e 's/:/ /g'`
+ for dir in $search_path ; do
+ for j in `ls -r $dir/tclsh[[8-9]]*${EXEEXT} 2> /dev/null` \
+ `ls -r $dir/tclsh*${EXEEXT} 2> /dev/null` ; do
+ if test x"$ac_cv_path_tclsh" = x ; then
+ if test -f "$j" ; then
+ ac_cv_path_tclsh=$j
+ break
+ fi
+ fi
+ done
+ done
+ ])
+
+ if test -f "$ac_cv_path_tclsh" ; then
+ TCLSH_PROG=$ac_cv_path_tclsh
+ AC_MSG_RESULT([$TCLSH_PROG])
+ else
+ AC_MSG_ERROR([No tclsh found in PATH: $search_path])
+ fi
+ AC_SUBST(TCLSH_PROG)
+])
+
+#------------------------------------------------------------------------
+# TEA_PROG_WISH
+# Locate a wish shell in the following directories:
+# ${TK_BIN_DIR} ${TK_BIN_DIR}/../bin
+# ${TCL_BIN_DIR} ${TCL_BIN_DIR}/../bin
+# ${exec_prefix}/bin ${prefix}/bin
+# ${PATH}
+#
+# Arguments
+# none
+#
+# Results
+# Subst's the following values:
+# WISH_PROG
+#------------------------------------------------------------------------
+
+AC_DEFUN(TEA_PROG_WISH, [
+ AC_MSG_CHECKING([for wish])
+
+ AC_CACHE_VAL(ac_cv_path_wish, [
+ search_path=`echo ${TK_BIN_DIR}:${TK_BIN_DIR}/../bin:${TCL_BIN_DIR}:${TCL_BIN_DIR}/../bin:${exec_prefix}/bin:${prefix}/bin:${PATH} | sed -e 's/:/ /g'`
+ for dir in $search_path ; do
+ for j in `ls -r $dir/wish[[8-9]]*${EXEEXT} 2> /dev/null` \
+ `ls -r $dir/wish*${EXEEXT} 2> /dev/null` ; do
+ if test x"$ac_cv_path_wish" = x ; then
+ if test -f "$j" ; then
+ ac_cv_path_wish=$j
+ break
+ fi
+ fi
+ done
+ done
+ ])
+
+ if test -f "$ac_cv_path_wish" ; then
+ WISH_PROG=$ac_cv_path_wish
+ AC_MSG_RESULT([$WISH_PROG])
+ else
+ AC_MSG_ERROR([No wish found in PATH: $search_path])
+ fi
+ AC_SUBST(WISH_PROG)
+])
+
+#------------------------------------------------------------------------
+# 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
+ 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[[8-9]].[[0-9]]* 2>/dev/null` \
+ ../../$1 \
+ `ls -dr ../../$1[[8-9]].[[0-9]]* 2>/dev/null` \
+ ../../../$1 \
+ `ls -dr ../../../$1[[8-9]].[[0-9]]* 2>/dev/null` \
+ ${srcdir}/../$1 \
+ `ls -dr ${srcdir}/../$1[[8-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 ${exec_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` \
+ ; 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}
+ fi
+
+ AC_SUBST($1_VERSION)
+ 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)
+])