tktable added

--HG--
branch : aspn
This commit is contained in:
baloan
2011-03-14 23:41:59 +01:00
parent 648a39a1f3
commit d19378fbab
46 changed files with 39160 additions and 2 deletions

View File

@@ -6,5 +6,6 @@
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/aspn/src</path>
<path>/aspn/tktable</path>
</pydev_pathproperty>
</pydev_project>

View File

@@ -12,8 +12,8 @@ class StoppableThread(Thread):
"""Thread class with a stop() method. The thread itself has to check
regularly for the stopped() condition."""
def __init__(self):
super(StoppableThread, self).__init__()
def __init__(self, *args, **kwargs):
super(StoppableThread, self).__init__(*args, **kwargs)
self._stop = Event()
def stop(self):

1700
tktable/ChangeLog Normal file

File diff suppressed because it is too large Load Diff

488
tktable/Makefile.in Normal file
View File

@@ -0,0 +1,488 @@
# 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) 2003-2008 ActiveState Software
#
# 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.15 2008/11/14 23:16:52 hobbs Exp $
#========================================================================
# Nothing of the variables below this line need to be changed. Please
# check the TARGETS section below to make sure the make targets are
# correct.
#========================================================================
#========================================================================
# The names of the source files is defined in the configure script.
# The object files are used for linking into the final library.
# This will be used when a dist target is added to the Makefile.
# It is not important to specify the directory, as long as it is the
# $(srcdir) or in the generic, win or unix subdirectory.
#========================================================================
PKG_SOURCES = @PKG_SOURCES@
PKG_OBJECTS = @PKG_OBJECTS@
#========================================================================
# PKG_TCL_SOURCES identifies Tcl runtime files that are associated with
# this package that need to be installed, if any.
#========================================================================
PKG_TCL_SOURCES = @PKG_TCL_SOURCES@
#========================================================================
# This is a list of public header files to be installed, if any.
#========================================================================
PKG_HEADERS = @PKG_HEADERS@
PKG_EXTRA_FILES = license.txt README.txt
PKG_MAN_PAGES = tkTable.n
#========================================================================
# "PKG_LIB_FILE" refers to the library (dynamic or static as per
# configuration options) composed of the named objects.
#========================================================================
PKG_LIB_FILE = @PKG_LIB_FILE@
PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@
lib_BINARIES = $(PKG_LIB_FILE)
BINARIES = tkTable.tcl.h $(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_NAME)$(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_NAME = @PACKAGE_NAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
CC = @CC@
CFLAGS_DEFAULT = @CFLAGS_DEFAULT@
CFLAGS_WARNING = @CFLAGS_WARNING@
CLEANFILES = @CLEANFILES@
EXEEXT = @EXEEXT@
LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@
MAKE_LIB = @MAKE_LIB@
MAKE_SHARED_LIB = @MAKE_SHARED_LIB@
MAKE_STATIC_LIB = @MAKE_STATIC_LIB@
MAKE_STUB_LIB = @MAKE_STUB_LIB@
OBJEXT = @OBJEXT@
RANLIB = @RANLIB@
RANLIB_STUB = @RANLIB_STUB@
SHLIB_CFLAGS = @SHLIB_CFLAGS@
SHLIB_LD = @SHLIB_LD@
SHLIB_LD_FLAGS = @SHLIB_LD_FLAGS@
SHLIB_LD_LIBS = @SHLIB_LD_LIBS@
STLIB_LD = @STLIB_LD@
TCL_DEFS = @TCL_DEFS@
TCL_SRC_DIR = @TCL_SRC_DIR@
TCL_BIN_DIR = @TCL_BIN_DIR@
TK_SRC_DIR = @TK_SRC_DIR@
TK_BIN_DIR = @TK_BIN_DIR@
# Not used by sample, but retained for reference of what Tcl required
TCL_LIBS = @TCL_LIBS@
TK_LIBS = @TK_LIBS@
#========================================================================
# TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our
# package without installing. The other environment variables allow us
# to test against an uninstalled Tcl. Add special env vars that you
# require for testing here (like TCLX_LIBRARY).
#========================================================================
EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR)
TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \
TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` \
@LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \
PATH="$(EXTRA_PATH):$(PATH)" \
TCLLIBPATH="$(top_builddir)"
TCLSH_PROG = @TCLSH_PROG@
WISH_PROG = @WISH_PROG@
TCLSH = $(TCLSH_ENV) $(TCLSH_PROG)
WISH = $(TCLSH_ENV) $(WISH_PROG)
# The local includes must come first, because the TK_XINCLUDES can be
# just a comment
INCLUDES = @PKG_INCLUDES@ \
@TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@
## NO_EMBEDDED_RUNTIME means that the tkTable.tcl file will not be embedded
## into the executable, thus the default tkTable.tcl library file will not
## be available when the library is loaded.
## If this is defined, the tkTable.tcl file must be available in a
## predefined set of directories (see docs).
#TBL_CFLAGS += -DNO_EMBEDDED_RUNTIME
## USE_EXIT_HANDLER is necessary for 8.1 before b3 and 8.0
## It is a work-around for the improper unloading of DLLs when exiting
#TBL_CFLAGS += -DUSE_EXIT_HANDLER
## NO_SORT_CELLS changes the behavior of certain commands (like curselection)
## to not sort the cells before returning them. If this is not important to
## you, it can cut save significant time for large return sets (> 1000 cells).
## You can always pass the data to [lsort -dictionary $cells] to get the same
## result.
#TBL_CFLAGS += -DNO_SORT_CELLS
## Experimental, not documented, not complete...
#TBL_CFLAGS += -DPROCS
## Jeff's magic extra debug flag
#TBL_CFLAGS += -DDEBUG
PKG_CFLAGS = $(TBL_CFLAGS) @PKG_CFLAGS@
DEFS = @DEFS@ $(PKG_CFLAGS) \
-DTBL_COMMAND=\"table\" \
-DTBL_RUNTIME=\"tkTable.tcl\" \
-DTBL_RUNTIME_DIR=\"$(pkglibdir)\"
CONFIG_CLEAN_FILES = Makefile
CPPFLAGS = @CPPFLAGS@
LIBS = @PKG_LIBS@ @LIBS@
AR = @AR@
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
#========================================================================
# Start of user-definable TARGETS section
#========================================================================
#========================================================================
# TEA TARGETS. Please note that the "libraries:" target refers to platform
# independent files, and the "binaries:" target inclues executable programs and
# platform-dependent libraries. Modify these targets so that they install
# the various pieces of your package. The make and install rules
# for the BINARIES that you specified above have already been done.
#========================================================================
all: binaries libraries doc
#========================================================================
# The binaries target builds executable programs, Windows .dll's, unix
# shared/static libraries, and any other platform-dependent files.
# The list of targets to build for "binaries:" is specified at the top
# of the Makefile, in the "BINARIES" variable.
#========================================================================
binaries: $(BINARIES) pkgIndex.tcl
libraries:
doc:
install: all install-binaries install-libraries install-doc
install-binaries: binaries install-lib-binaries install-bin-binaries
@mkdir -p $(DESTDIR)$(pkglibdir)
$(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir)
@list='$(PKG_EXTRA_FILES)'; for p in $$list; do \
if test -f $(srcdir)/$$p; then \
destp=`basename $$p`; \
echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \
$(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \
fi; \
done
#========================================================================
# This rule installs platform-independent files, such as header files.
#========================================================================
install-libraries: libraries
#========================================================================
# Install documentation. Unix manpages should go in the $(mandir)
# directory.
#========================================================================
install-doc: doc
@mkdir -p $(DESTDIR)$(pkglibdir)/html
@list='$(PKG_MAN_PAGES)'; for p in $$list; do \
html=`basename $$p|sed -e 's/.[^.]*$$//'`.html; \
$(INSTALL_DATA) $(srcdir)/doc/$$html $(DESTDIR)$(pkglibdir)/html/; \
done
html:
cd $(srcdir)/doc; \
list='$(PKG_MAN_PAGES)'; for p in $$list; do \
html=`basename $$p|sed -e 's/.[^.]*$$//'`.html; \
echo "Creating \"$$html\" from \"$$p\""; \
rm -f $$html; \
groff -Tascii -man $$p \
| rman -f HTML \
> $$html; \
done
# Piping to cat is necessary on Windows to see the output, and
# harmless on Unix
test: binaries libraries
$(WISH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) | cat
demo: binaries libraries
$(WISH) `@CYGPATH@ $(srcdir)/demos/debug.tcl` $(TESTFLAGS) | cat
shell: binaries libraries
@$(WISH) $(SCRIPT)
gdb:
$(TCLSH_ENV) gdb $(WISH_PROG) $(SCRIPT)
depend:
#========================================================================
# $(PKG_LIB_FILE) should be listed as part of the BINARIES variable
# mentioned above. That will ensure that this target is built when you
# run "make binaries".
#
# The $(PKG_OBJECTS) objects are created and linked into the final
# library. In most cases these object files will correspond to the
# source files above.
#========================================================================
$(PKG_LIB_FILE): $(PKG_OBJECTS)
-rm -f $(PKG_LIB_FILE)
${MAKE_LIB}
$(RANLIB) $(PKG_LIB_FILE)
#========================================================================
# In the following lines, $(srcdir) refers to the toplevel directory
# containing your extension. If your sources are in a subdirectory,
# you will have to modify the paths to reflect this:
#
# tkpkg.$(OBJEXT): $(srcdir)/src/win/tkpkg.c
# $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/tkpkg.c` -o $@
#
# Setting the VPATH variable to a list of paths will cause the
# makefile to look into these paths when resolving .c to .obj
# dependencies.
#========================================================================
# I added leading $(srcdir) because autoconf 2.53 strips it off
VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win
# I would prefer to use $< over $?, but FreeBSD's can't handle it, and
# with only one prereq, $? is sufficient
tkTable.tcl.h: $(srcdir)/library/tkTable.tcl
sed -e '/^\#/d' -e '/^$$/d' -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' < `@CYGPATH@ $?` > '$@' || { rm -f $@; exit 1; }
.SUFFIXES: .c .$(OBJEXT)
.c.@OBJEXT@:
$(COMPILE) -c `@CYGPATH@ $<` -o $@
pkgIndex.tcl:
(\
echo 'if {[catch {package require Tcl 8.2}]} return';\
echo 'package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \
[list load [file join $$dir $(PKG_LIB_FILE)] $(PACKAGE_NAME)]'\
) > pkgIndex.tcl
#========================================================================
# 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.
#
# You should not have to modify this target.
#========================================================================
install-lib-binaries:
@mkdir -p $(DESTDIR)$(pkglibdir)
@list='$(lib_BINARIES)'; for p in $$list; do \
if test -f $$p; then \
echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \
echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \
$(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \
ext=`echo $$p|sed -e "s/.*\.//"`; \
if test "x$$ext" = "xdll"; then \
lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \
if test -f $$lib; then \
echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \
$(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \
fi; \
fi; \
fi; \
done
@list='$(PKG_TCL_SOURCES)'; for p in $$list; do \
if test -f $(srcdir)/$$p; then \
destp=`basename $$p`; \
echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \
$(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \
fi; \
done
#========================================================================
# Install binary executables (e.g. .exe files)
#
# You should not have to modify this target.
#========================================================================
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
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
uninstall-binaries:
list='$(lib_BINARIES)'; for p in $$list; do \
rm -f $(DESTDIR)$(pkglibdir)/$$p; \
done
list='$(PKG_TCL_SOURCES)'; for p in $$list; do \
p=`basename $$p`; \
rm -f $(DESTDIR)$(pkglibdir)/$$p; \
done
list='$(bin_BINARIES)'; for p in $$list; do \
rm -f $(DESTDIR)$(bindir)/$$p; \
done
#========================================================================
# Starkit creation - requires ActiveTcl or compatible tclsh
# You should not have to modify this target.
#========================================================================
STARKIT_EXT = .kit.tcl
STARKIT_TCLSH = $(TCLSH)
STARKIT_BASE = tclsh
STARKIT = $(PACKAGE_NAME)$(STARKIT_EXT)
starkit-clean:
rm -f $(STARKIT)
starkit: starkit-clean
@echo "Building $(STARKIT)"
(\
echo 'package require vfs'; \
echo 'package require Mk4tcl'; \
echo ''; \
echo 'set HEADER {#!/bin/sh';\
echo '# \\'; \
echo 'exec %1s "$$0" $${1+"$$@"}'; \
echo 'package require starkit'; \
echo 'starkit::header mk4 -readonly}'; \
echo ''; \
echo 'set HEADER [format "$$HEADER\n%c" [file tail [info nameofexe]] 0x1a]'; \
echo 'set file "$(STARKIT)"'; \
echo 'set fid [open $$file w]'; \
echo 'puts $$fid $$HEADER'; \
echo 'close $$fid'; \
echo ''; \
echo 'vfs::mk4::Mount $$file $$file'; \
echo 'file copy $(PKG_LIB_FILE) $$file/'; \
echo 'vfs::unmount $$file'; \
) | $(STARKIT_TCLSH)
#========================================================================
# Distribution creation
# You should not have to modify this target.
#========================================================================
TAR = tar
#COMPRESS = $(TAR) cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar
COMPRESS = $(TAR) 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)/README.* $(srcdir)/*.txt $(srcdir)/ChangeLog \
$(srcdir)/Makefile.in $(srcdir)/aclocal.m4 \
$(srcdir)/configure $(srcdir)/configure.in $(DIST_DIR)/
chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4
chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in
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
mkdir $(DIST_DIR)/demos
cp -p $(srcdir)/demos/*.{tcl,py,gif} $(DIST_DIR)/demos/
mkdir $(DIST_DIR)/doc
cp -p $(srcdir)/doc/*.{html,n} $(DIST_DIR)/doc/
mkdir $(DIST_DIR)/generic
cp -p $(srcdir)/generic/*.[ch] $(DIST_DIR)/generic/
mkdir $(DIST_DIR)/library
cp -p $(srcdir)/library/*.{tcl,py} $(DIST_DIR)/library/
mkdir $(DIST_DIR)/tests
cp -p $(srcdir)/tests/*.{tcl,test} $(DIST_DIR)/tests/
mkdir $(DIST_DIR)/unix
cp -p $(srcdir)/unix/tktable.spec $(DIST_DIR)/unix/
mkdir $(DIST_DIR)/win
cp -p $(srcdir)/win/makefile.vc $(DIST_DIR)/win/
(cd $(DIST_ROOT); $(COMPRESS);)
.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:

20
tktable/README.blt Normal file
View File

@@ -0,0 +1,20 @@
If tkTable is used at the same time as BLT then there are two name
conflicts to be aware of.
BLT also has a table.n man page. TkTable's man page will still be
available as tkTable.n.
BLT also has a "table" command. The table command of the last
extension loaded will be in effect. If you need to use both table
commands then eval "rename table blttable" after loading blt and
before loading tkTable, or perhaps "rename table tkTable" if you
load the tkTable extension first.
In general this shouldn't be a problem as long as you load tkTable
last. The BLT "table" command facilities have been subsumed by the
Tk "grid" command (available in Tk4.1+), so the BLT table should
only be used in legacy code.
Alternatively, if you want both or have another "table" command,
then change the TBL_COMMAND macro in the makefile before compiling,
and it tkTable will define your named command for the table widget.

149
tktable/README.txt Normal file
View File

@@ -0,0 +1,149 @@
/*
* Conceptually based on Tk3 table widget by Roland King (rols@lehman.com)
*
* see ChangeLog file for details
*
* current maintainer: jeff at hobbs org
*
* Copyright 1997-2002, Jeffrey Hobbs (jeff@hobbs.org)
*/
*************************************
The Tk Table Widget Version 2.0+
*************************************
INTRODUCTION
TkTable is a table/matrix widget extension to tk/tcl.
The basic features of the widget are:
* multi-line cells
* support for embedded windows (one per cell)
* row & column spanning
* variable width columns / height rows (interactively resizable)
* row and column titles
* multiple data sources ((Tcl array || Tcl command) &| internal caching)
* supports standard Tk reliefs, fonts, colors, etc.
* x/y scrollbar support
* 'tag' styles per row, column or cell to change visual appearance
* in-cell editing - returns value back to data source
* support for disabled (read-only) tables or cells (via tags)
* multiple selection modes, with "active" cell
* multiple drawing modes to get optimal performance for larger tables
* optional 'flashes' when things update
* cell validation support
* Works everywhere Tk does (including Windows and Mac!)
* Unicode support (Tk8.1+)
FINDING THE WIDGET
0. The newest version is most likely found at:
http://tktable.sourceforge.net/
http://www.purl.org/net/hobbs/tcl/capp/
BUILDING AND INSTALLING THE WIDGET
1. Uncompress and unpack the distribution
ON UNIX and OS X:
gzip -cd Tktable<version>.tar.gz | tar xf -
ON WINDOWS:
use something like WinZip to unpack the archive.
ON MACINTOSH:
use StuffIt Expander to unstuff the archive.
This will create a subdirectory tkTable<version> with all the files in it.
2. Configure
ON UNIX and OS X:
cd Tktable<version>
./configure
tkTable uses information left in tkConfig.sh when you built tk. This
file will be found in $exec_prefix/lib/. You might set the --prefix and
--exec-prefix options of configure if you don't want the default
(/usr/local). If building on multiple unix platforms, the following is
recommended to isolate build conflicts:
mkdir <builddir>/<platform>
cd !$
/path/to/Tktable<version>/configure
ON WINDOWS:
Version 2.8 added support for building in the cygwin environment on
Windows based on TEA (http://www.tcl.tk/doc/tea/). You can retrieve
cygwin from:
http://sources.redhat.com/cygwin/
Inside the cygwin environment, you build the same as on Unix.
Otherwise, hack makefile.vc until it works and compile. It has problems
executing wish from a path with a space in it, but the DLL builds just
fine. A DLL should be available where you found this archive.
3. Make and Install
ON UNIX< OS X or WINDOWS (with cygwin):
make
make test (OPTIONAL)
make demo (OPTIONAL)
make install
ON WINDOWS (makefile.vc):
nmake -f makefile.vc
nmake -f makefile.vc test (OPTIONAL)
nmake -f makefile.vc install
tkTable is built to comply to the latest tcl package conventions.
There is also a specific "make static" for those who need it.
4. Use it
Start a regular wish interpreter, 'load' the library, and use the table.
There are a few test scripts in the demos directory which you can source.
5. Read the documentation
There is a Unix manpage and HTML translation provided in the doc/
subdirectory. These describe the table widget's features and commands
in depth. If something is confusing, just to try it out.
6. Python users
There is a library/tktable.py wrapper for use with Python/Tkinter.
THINGS TO WATCH OUT FOR
Packing
The table tries not to allocate huge chunks of screen real estate if
you ask it for a lot of rows and columns. You can always stretch out
the frame or explicitly tell it how big it can be. If you want to
stretch the table, remember to pack it with fill both and expand on,
or with grid, give it -sticky news and configure the grid row and column
for some weighting.
Array
The array elements for the table are of the form array(2,3) etc. Make
sure there are no spaces around the ','. Negative indices are allowed.
Editing
If you can't edit, remember that the focus model in tk is explicit, so
you need to click on the table or give it the focus command. Just
having a selected cell is not the same thing as being able to edit.
You also need the editing cursor. If you can't get the cursor, make
sure that you actually have a variable assigned to the table, and that
the "state" of the cell is not disabled.
COMMENTS, BUGS, etc.
* Please can you send comments and bug reports to the current maintainer
and their best will be done to address them. A mailing list for
tktable discussion is tktable-users@lists.sourceforge.net.
* If you find a bug, a short piece of Tcl that exercises it would be very
useful, or even better, compile with debugging and specify where it
crashed in that short piece of Tcl. Use the SourceForge site to check
for known bugs or submit new ones.

63
tktable/TODO.txt Normal file
View File

@@ -0,0 +1,63 @@
## TODO LIST
##
## updated 1 June 1999, jeff at hobbs org
##
## Any information in here may be out of date. For up-to-date info see:
## http://tktable.sourceforge.net/
##
These are recommendations, not all of the same priority, and not
all necessarily will be implemented. If you see something you
feel is important, email me and say so. Very democratic.
* some sort of textbbox command that will return the size of the
text in a cell, to allow for perfect cell sizing.
* anchor title areas in different parts of the screen
* -rowstretchmode fill ignores initial # of rows, or config requests for more.
* interpret 0 rows/cols to be FILL
* add -colstretchmode fill
* scratch stretchmode "fill" in favor of "dynamic" which would monitor
the max extent of row/col (difficult)
* fix selection routines to properly handle title area movement
* support smooth scrolling of rows/cols
* add ability to index by tagname
* overhaul tag mechanism (include way to query for tags on a cell, add
priority)
* add internal sort procedures
pathName sort -row {the list of rows we want to sort | all}
-col {the list of cols we use for sorting}
-master row,col
-command _command_to_use_
-type {for each column specifies the type of sort:
ascii | dictionary | integer | real }
-order {for each column specify the order of sort:
increasing | decreasing | none }
* row/column swap (maybe only in terms of visual remapping)
= BBBB U U GGG SSS
== B B U U G S
==- B BB U U G GGG SSS
== B B U U G G S
= BBBB UUU GGGG SSS
MINOR:
Windows: With "-colstretchmode last", the scrollbar behaves oddly in
handling the space for the last cell properly when moving the
main part of the scrollbar with the mouse. This seems to be
that even though the scrollbar receives the "set 0.6xxx 1",
the scrollbar immediately jumps back to what the mouse says,
although this isn't a problem in X...
Windows: when moving windows in "Show Window While Dragging" mode,
the column titles don't refresh properly.
Windows: When using bitmaps in cells, they occasionally don't redraw
correctly. The work-around is to use -drawmode slow.

9
tktable/aclocal.m4 vendored Normal file
View File

@@ -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
#

12133
tktable/configure vendored Normal file

File diff suppressed because it is too large Load Diff

187
tktable/configure.in Normal file
View File

@@ -0,0 +1,187 @@
#! /bin/bash -norc
#
# RCS: @(#) $Id: configure.in,v 1.16 2008/11/14 23:16:52 hobbs Exp $
#
#--------------------------------------------------------------------
# Sample configure.in for Tcl Extensions. The only places you should
# need to modify this file are marked by the string __CHANGE__
#--------------------------------------------------------------------
#-----------------------------------------------------------------------
# __CHANGE__
# Set your package name and version numbers here.
#
# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
# set as provided. These will also be added as -D defs in your Makefile
# so you can encode the package version directly into the source files.
#-----------------------------------------------------------------------
AC_INIT([Tktable], [2.10])
#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------
TEA_INIT([3.7])
AC_CONFIG_AUX_DIR(tclconfig)
#--------------------------------------------------------------------
# Load the tclConfig.sh file
#--------------------------------------------------------------------
TEA_PATH_TCLCONFIG
TEA_LOAD_TCLCONFIG
#--------------------------------------------------------------------
# Load the tkConfig.sh file if necessary (Tk extension)
#--------------------------------------------------------------------
TEA_PATH_TKCONFIG
TEA_LOAD_TKCONFIG
#-----------------------------------------------------------------------
# Handle the --prefix=... option by defaulting to what Tcl gave.
# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER.
#-----------------------------------------------------------------------
TEA_PREFIX
#-----------------------------------------------------------------------
# Standard compiler checks.
# This sets up CC by using the CC env var, or looks for gcc otherwise.
# This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create
# the basic setup necessary to compile executables.
#-----------------------------------------------------------------------
TEA_SETUP_COMPILER
#-----------------------------------------------------------------------
# __CHANGE__
# Specify the C source files to compile in TEA_ADD_SOURCES,
# public headers that need to be installed in TEA_ADD_HEADERS,
# stub library C source files to compile in TEA_ADD_STUB_SOURCES,
# and runtime Tcl library files in TEA_ADD_TCL_SOURCES.
# This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS
# and PKG_TCL_SOURCES.
#-----------------------------------------------------------------------
TEA_ADD_SOURCES([tkTable.c tkTableWin.c tkTableTag.c tkTableEdit.c
tkTableCell.c tkTableCellSort.c tkTableCmds.c tkTableUtil.c])
# PostScript is on the drawing board
#TEA_ADD_SOURCES([tkTablePs.c])
# This header isn't really meant for distribution
#TEA_ADD_HEADERS([generic/tkTable.h])
TEA_ADD_INCLUDES([-I. -I\"`${CYGPATH} ${srcdir}/generic`\"])
TEA_ADD_CFLAGS([])
TEA_ADD_STUB_SOURCES([])
TEA_ADD_TCL_SOURCES([library/tkTable.tcl library/tktable.py])
#--------------------------------------------------------------------
# __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_PATH_TCLCONFIG/TEA_LOAD_TCLCONFIG
#--------------------------------------------------------------------
TEA_PUBLIC_TCL_HEADERS
TEA_PUBLIC_TK_HEADERS
#TEA_PRIVATE_TCL_HEADERS
#TEA_PRIVATE_TK_HEADERS
#--------------------------------------------------------------------
# For Unix/Tk builds, make sure that the X libraries/headers are found.
#--------------------------------------------------------------------
TEA_PATH_X
#--------------------------------------------------------------------
# __CHANGE__
# A few miscellaneous platform-specific items:
#
# Define a special symbol for Windows (BUILD_Tktable in this case) so
# that we create the export library with the dll.
#
# 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.
#
# TEA_ADD any extra compiler/build info here.
#--------------------------------------------------------------------
if test "${TEA_PLATFORM}" = "windows" ; then
AC_DEFINE_UNQUOTED(BUILD_Tktable)
CLEANFILES="pkgIndex.tcl tkTable.tcl.h *.lib *.dll *.exp *.ilk *.pdb *.pch"
TEA_ADD_LIBS([gdi32.lib user32.lib])
else
CLEANFILES="pkgIndex.tcl tkTable.tcl.h"
fi
AC_SUBST(CLEANFILES)
#--------------------------------------------------------------------
# Check whether --enable-threads or --disable-threads was given.
# So far only Tcl responds to this one.
#--------------------------------------------------------------------
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.
#--------------------------------------------------------------------
AC_DEFINE(USE_TCL_STUBS)
AC_DEFINE(USE_TK_STUBS)
#--------------------------------------------------------------------
# This macro generates a line to use when building a library. It
# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS,
# and TEA_LOAD_TCLCONFIG macros above.
#--------------------------------------------------------------------
TEA_MAKE_LIB
#--------------------------------------------------------------------
# Find tclsh so that we can run pkg_mkIndex to generate the pkgIndex.tcl
# file during the install process. Don't run the TCLSH_PROG through
# ${CYGPATH} because it's being used directly by make.
# Require that we use a tclsh shell version 8.2 or later since earlier
# versions have bugs in the pkg_mkIndex routine.
#--------------------------------------------------------------------
TEA_PROG_TCLSH
TEA_PROG_WISH
#--------------------------------------------------------------------
# Finally, substitute all of the various values into the Makefile.
#--------------------------------------------------------------------
AC_OUTPUT([Makefile])

61
tktable/demos/basic.tcl Normal file
View File

@@ -0,0 +1,61 @@
#!/bin/sh
# the next line restarts using wish \
exec wish "$0" ${1+"$@"}
## basic.tcl
##
## This demo shows the basic use of the table widget
##
## jeff at hobbs org
source [file join [file dirname [info script]] loadtable.tcl]
array set table {
rows 8
cols 8
table .t
array t
}
proc fill { array x y } {
upvar $array f
for {set i -$x} {$i<$x} {incr i} {
for {set j -$y} {$j<$y} {incr j} { set f($i,$j) "r$i,c$j" }
}
}
## Test out the use of a procedure to define tags on rows and columns
proc rowProc row { if {$row>0 && $row%2} { return OddRow } }
proc colProc col { if {$col>0 && $col%2} { return OddCol } }
label .label -text "TkTable v1 Example"
fill $table(array) $table(rows) $table(cols)
table $table(table) -rows $table(rows) -cols $table(cols) \
-variable $table(array) \
-width 6 -height 6 \
-titlerows 1 -titlecols 2 \
-roworigin -1 -colorigin -2 \
-yscrollcommand {.sy set} -xscrollcommand {.sx set} \
-rowtagcommand rowProc -coltagcommand colProc \
-colstretchmode last -rowstretchmode last \
-selectmode extended -sparsearray 0
scrollbar .sy -command [list $table(table) yview]
scrollbar .sx -command [list $table(table) xview] -orient horizontal
button .exit -text "Exit" -command {exit}
grid .label - -sticky ew
grid $table(table) .sy -sticky news
grid .sx -sticky ew
grid .exit -sticky ew -columnspan 2
grid columnconfig . 0 -weight 1
grid rowconfig . 1 -weight 1
$table(table) tag config OddRow -bg orange -fg purple
$table(table) tag config OddCol -bg brown -fg pink
$table(table) width -2 7 -1 7 1 5 2 8 4 14
puts [list Table is $table(table) with array [$table(table) cget -var]]

82
tktable/demos/buttons.tcl Normal file
View File

@@ -0,0 +1,82 @@
#!/bin/sh
# next line is a comment in tcl \
exec wish "$0" ${1+"$@"}
## buttons.tcl
##
## demonstrates the simulation of a button array
##
## ellson@lucent.com
## modifications made by jeff at hobbs org
source [file join [file dirname [info script]] loadtable.tcl]
array set table {
rows 20
cols 20
table .table
}
# create the table
set t $table(table)
table $t -rows [expr {$table(rows)+1}] -cols [expr {$table(cols)+1}] \
-titlerows 1 -titlecols 1 \
-roworigin -1 -colorigin -1 \
-colwidth 4 \
-width 8 -height 8 \
-variable tab \
-flashmode off \
-cursor top_left_arrow \
-borderwidth 2 \
-state disabled \
-xscrollcommand ".sx set" -yscrollcommand ".sy set"
scrollbar .sx -orient h -command "$t xview"
scrollbar .sy -orient v -command "$t yview"
grid $t .sy -sticky nsew
grid .sx -sticky ew
grid columnconfig . 0 -weight 1
grid rowconfig . 0 -weight 1
# set up tags for the various states of the buttons
$t tag configure OFF -bg red -relief raised
$t tag configure ON -bg green -relief sunken
$t tag configure sel -bg gray75 -relief flat
# clean up if mouse leaves the widget
bind $t <Leave> {
%W selection clear all
}
# highlight the cell under the mouse
bind $t <Motion> {
if {[%W selection includes @%x,%y]} break
%W selection clear all
%W selection set @%x,%y
break
## "break" prevents the call to tkTableCheckBorder
}
# mousebutton 1 toggles the value of the cell
# use of "selection includes" would work here
bind $t <1> {
set rc [%W cursel]
if {[string match ON $tab($rc)]} {
set tab($rc) OFF
%W tag celltag OFF $rc
} {
set tab($rc) ON
%W tag celltag ON $rc
}
}
# inititialize the array, titles, and celltags
for {set i 0} {$i < $table(rows)} {incr i} {
set tab($i,-1) $i
for {set j 0} {$j < $table(cols)} {incr j} {
if {! $i} {set tab(-1,$j) $j}
set tab($i,$j) "OFF"
$t tag celltag OFF $i,$j
}
}

85
tktable/demos/command.tcl Normal file
View File

@@ -0,0 +1,85 @@
#!/bin/sh
# the next line restarts using wish \
exec wish "$0" ${1+"$@"}
## command.tcl
##
## This demo shows the use of the table widget's -command options
##
## jeff at hobbs org
source [file join [file dirname [info script]] loadtable.tcl]
array set table {
rows 10
cols 10
table .table
array DATA
}
proc fill { array x y } {
upvar $array f
for {set i -$x} {$i<$x} {incr i} {
for {set j -$y} {$j<$y} {incr j} { set f($i,$j) "$i x $j" }
}
}
## Test out the use of a procedure to define tags on rows and columns
proc rowProc row { if {$row>0 && $row%2} { return OddRow } }
proc colProc col { if {$col>0 && $col%2} { return OddCol } }
proc tblCmd { arrayName set cell val } {
upvar \#0 $arrayName data
if {$set} {
#echo set $cell $val
set data($cell) $val
} else {
#echo get $cell
if {[info exists data($cell)]} {
return $data($cell)
} else {
return
}
}
}
label .label -text "TkTable -command Example"
label .current -textvar CURRENT -width 5
entry .active -textvar ACTIVE
bind .active <Return> "$table(table) curvalue \[%W get\]"
fill $table(array) $table(rows) $table(cols)
set t $table(table)
table $table(table) -rows $table(rows) -cols $table(cols) \
-command [list tblCmd $table(array) %i %C %s] -cache 1 \
-width 6 -height 6 \
-titlerows 1 -titlecols 1 \
-yscrollcommand {.sy set} -xscrollcommand {.sx set} \
-roworigin -1 -colorigin -1 \
-rowtagcommand rowProc -coltagcommand colProc \
-selectmode extended \
-rowstretch unset -colstretch unset \
-flashmode on -browsecommand {
set CURRENT %S
set ACTIVE [%W get %S]
} -validate 1 -validatecommand {
set ACTIVE %S
return 1
}
scrollbar .sy -command [list $table(table) yview] -orient v
scrollbar .sx -command [list $table(table) xview] -orient h
grid .label - - -sticky ew
grid .current .active - -sticky ew
grid $table(table) - .sy -sticky nsew
grid .sx - -sticky ew
grid columnconfig . 1 -weight 1
grid rowconfig . 2 -weight 1
$table(table) tag config OddRow -bg orange -fg purple
$table(table) tag config OddCol -bg brown -fg pink
puts [list Table is $table(table)]

112
tktable/demos/debug.tcl Normal file
View File

@@ -0,0 +1,112 @@
#!/bin/sh
# the next line restarts using wish \
exec wish "$0" ${1+"$@"}
## version2.tcl
##
## This demo uses most features of the table widget
##
## jeff at hobbs org
source [file join [file dirname [info script]] loadtable.tcl]
array set table {
rows 25
cols 20
table .t
array t
}
proc fill { array x y } {
upvar $array f
for {set i -$x} {$i<$x} {incr i} {
for {set j -$y} {$j<$y} {incr j} { set f($i,$j) "r$i,c$j" }
}
}
## Test out the use of a procedure to define tags on rows and columns
proc colProc col { if {$col > 0 && $col % 2} { return OddCol } }
label .label -text "TkTable v2 Example"
fill $table(array) $table(rows) $table(cols)
table $table(table) \
-rows $table(rows) -cols $table(cols) \
-variable $table(array) \
-width 6 -height 8 \
-titlerows 1 -titlecols 2 \
-roworigin -5 -colorigin -2 \
-yscrollcommand {.sy set} \
-xscrollcommand {.sx set} \
-coltagcommand colProc \
-selectmode extended \
-rowstretch unset \
-colstretch unset \
-selecttitles 0 \
-drawmode single
scrollbar .sy -command [list $table(table) yview]
scrollbar .sx -command [list $table(table) xview] -orient horizontal
button .exit -text "Exit" -command {exit}
grid .label - -sticky ew
grid $table(table) .sy -sticky news
grid .sx -sticky ew
grid .exit -sticky ew -columnspan 2
grid columnconfig . 0 -weight 1
grid rowconfig . 1 -weight 1
$table(table) tag config OddCol -bg brown -fg pink
$table(table) tag config title -bg red -fg green -relief sunken
$table(table) tag config dis -state disabled
set i -1
set first [$table(table) cget -colorigin]
foreach anchor {n s e w nw ne sw se c} {
$table(table) tag config $anchor -anchor $anchor
$table(table) tag row $anchor [incr i]
$table(table) set $i,$first $anchor
}
font create courier -family Courier -size 10
$table(table) tag config s -font courier -justify center
image create photo logo \
-file [file join [file dirname [info script]] tcllogo.gif]
$table(table) tag config logo -image logo -showtext 1
$table(table) tag cell logo 1,2 2,3 4,1
$table(table) tag cell dis 2,1 1,-1 3,0
$table(table) width -2 8 -1 9 0 12 4 14
$table(table) set \
1,1 "multi-line\ntext\nmight be\ninteresting" \
3,2 "more\nmulti-line\nplaying\n" \
2,2 "null\0byte"
set i -1
# This is in the row span
set l [label $table(table).s -text "Window s" -bg yellow]
$table(table) window config 6,0 -sticky s -window $l
# This is in the row titles
set l [label $table(table).ne -text "Window ne" -bg yellow]
$table(table) window config 4,-1 -sticky ne -window $l
# This will get swallowed by a span
set l [label $table(table).ew -text "Window ew" -bg yellow]
$table(table) window config 5,3 -sticky ew -window $l
# This is in the col titles
set l [label $table(table).news -text "Window news" -bg yellow]
$table(table) window config -5,1 -sticky news -window $l
set l [label [winfo parent $table(table)].l -text "Sibling l" -bg orange]
$table(table) window config 5,1 -sticky news -window $l
if {![catch {$table(table) span}]} {
$table(table) span -1,-2 0,3 1,2 0,5 3,2 2,2 6,0 4,0
}
puts [list Table is $table(table) with array [$table(table) cget -var]]
#$table(table) postscript -file out.ps -first origin -last 2,2
#if {[string match {} [info commands tkcon]]} exit

View File

@@ -0,0 +1,87 @@
#!/bin/sh
# the next line restarts using wish \
exec wish "$0" ${1+"$@"}
## dynarows.tcl
##
## This demos shows the use of the validation mechanism of the table
## and uses the table's cache (no -command or -variable) with a cute
## dynamic row routine.
##
## jeff at hobbs org
source [file join [file dirname [info script]] loadtable.tcl]
proc table_validate {w idx} {
if {[scan $idx %d,%d row col] != 2} return
set val [$w get $idx]
## Entries in the last row are allowed to be empty
set nrows [$w cget -rows]
if {$row == ${nrows}-1 && [string match {} $val]} { return }
if {[catch {clock scan $val} time]} {
bell
$w activate $idx
$w selection clear all
$w selection set active
$w see active
} else {
set date {}
foreach item [clock format $time -format "%m %d %Y"] {
lappend date [string trimleft $item "0"]
}
$w set $idx [join $date "/"]
if {$row == ${nrows}-1} {
## if this is the last row and both cols 1 && 2 are not empty
## then add a row and redo configs
if {[string comp [$w get $row,1] {}] && \
[string comp [$w get $row,2] {}]} {
$w tag row {} $row
$w set $row,0 $row
$w configure -rows [incr nrows]
$w tag row unset [incr row]
$w set $row,0 "*"
$w see $row,1
$w activate $row,1
}
}
}
}
label .example -text "Dynamic Date Validated Rows"
set t .table
table $t -rows 2 -cols 3 -cache 1 -selecttype row \
-titlerows 1 -titlecols 1 \
-yscrollcommand { .sy set } \
-xscrollcommand { .sx set } \
-height 5 -colstretch unset -rowstretch unset \
-autoclear 1 -browsecommand {table_validate %W %s}
$t set 0,1 "Begin" 0,2 "End" 1,0 "*"
$t tag config unset -fg \#008811
$t tag config title -fg red
$t tag row unset 1
$t width 0 3
scrollbar .sy -command [list $t yview]
scrollbar .sx -command [list $t xview] -orient horizontal
grid .example - -sticky ew
grid $t .sy -sticky news
grid .sx -sticky ew
grid columnconfig . 0 -weight 1
grid rowconfig . 1 -weight 1
bind $t <Return> {
set r [%W index active row]
set c [%W index active col]
if {$c == 2} {
%W activate [incr r],1
} else {
%W activate $r,[incr c]
}
%W see active
break
}
bind $t <KP_Enter> [bind $t <Return>]

View File

@@ -0,0 +1,52 @@
# loadtable.tcl
#
# Ensures that the table library extension is loaded
if {[string equal "Windows CE" $::tcl_platform(os)]} {
if {[info proc puts] != "puts" || ![llength [info command ::tcl::puts]]} {
# Rename puts to something innocuous on Windows CE,
# but only if it wasn't already renamed (thus it's a proc)
rename puts ::tcl::puts
proc puts args {
set la [llength $args]
if {$la<1 || $la>3} {
error "usage: puts ?-nonewline? ?channel? string"
}
set nl \n
if {[lindex $args 0]=="-nonewline"} {
set nl ""
set args [lrange $args 1 end]
}
if {[llength $args]==1} {
set args [list stdout [join $args]] ;# (2)
}
foreach {channel s} $args break
if {$channel=="stdout" || $channel=="stderr"} {
#$::putsw insert end $s$nl
} else {
set cmd ::tcl::puts
if {$nl==""} {lappend cmd -nonewline}
lappend cmd $channel $s
uplevel 1 $cmd
}
}
}
}
set ::VERSION 2.10
if {[string compare unix $tcl_platform(platform)]} {
set table(library) Tktable$::VERSION[info sharedlibextension]
} else {
set table(library) libTktable$::VERSION[info sharedlibextension]
}
if {
[string match {} [info commands table]]
&& [catch {package require Tktable $::VERSION} err]
&& [catch {load [file join [pwd] $table(library)]} err]
&& [catch {load [file join [pwd] .. unix $table(library)]} err]
&& [catch {load [file join [pwd] .. win $table(library)]} err]
} {
error $err
} else {
puts "Tktable v[package provide Tktable] loaded"
}

76
tktable/demos/maxsize.tcl Normal file
View File

@@ -0,0 +1,76 @@
#!/bin/sh
# the next line restarts using wish \
exec wish "$0" ${1+"$@"}
## maxsize.tcl
##
## This demo uses a really big table. The big startup time is in
## filling the table's Tcl array var.
##
## jeff at hobbs org
source [file join [file dirname [info script]] loadtable.tcl]
array set table {
rows 40000
cols 10
table .t
array t
}
proc fill { array x y } {
upvar $array f
for {set row 0} {$row<$x} {incr row} {
for {set col 0} {$col<$y} {incr col} {
set f($row,$col) "$row,$col"
}
}
}
## Test out the use of a procedure to define tags on rows and columns
proc colProc col { if {$col > 0 && $col % 2} { return OddCol } }
label .label -text "TkTable v2 Example"
fill $table(array) $table(rows) $table(cols)
table $table(table) \
-rows $table(rows) -cols $table(cols) \
-variable $table(array) \
-width 6 -height 8 \
-titlerows 1 -titlecols 1 \
-yscrollcommand {.sy set} \
-xscrollcommand {.sx set} \
-coltagcommand colProc \
-selectmode extended \
-rowstretch unset \
-colstretch unset \
-selecttitles 0 \
-drawmode slow
scrollbar .sy -command [list $table(table) yview]
scrollbar .sx -command [list $table(table) xview] -orient horizontal
button .exit -text "Exit" -command {exit}
grid .label - -sticky ew
grid $table(table) .sy -sticky news
grid .sx -sticky ew
grid .exit -sticky ew -columnspan 2
grid columnconfig . 0 -weight 1
grid rowconfig . 1 -weight 1
$table(table) tag config OddCol -bg brown -fg pink
$table(table) tag config title -bg red -fg blue -relief sunken
$table(table) tag config dis -state disabled
set i -1
set first [$table(table) cget -colorigin]
foreach anchor {n s e w nw ne sw se c} {
$table(table) tag config $anchor -anchor $anchor
$table(table) tag row $anchor [incr i]
$table(table) set $i,$first $anchor
}
font create courier -family Courier -size 10
$table(table) tag config s -font courier -justify center
$table(table) width -2 8 -1 9 0 12 4 14
puts [list Table is $table(table) with array [$table(table) cget -var]]

View File

@@ -0,0 +1,122 @@
#!/bin/sh
# the next line restarts using wish \
exec wish "$0" ${1+"$@"}
## spreadsheet.tcl
##
## This demos shows how you can simulate a 3D table
## and has other basic features to begin a basic spreadsheet
##
## jeff at hobbs org
source [file join [file dirname [info script]] loadtable.tcl]
array set table {
rows 10
cols 10
page AA
table .table
default pink
AA orange
BB blue
CC green
}
proc colorize num { if {$num>0 && $num%2} { return colored } }
proc fill {array {r 10} {c 10}} {
upvar \#0 $array ary
for {set i 0} {$i < $r} {incr i} {
for {set j 0} {$j < $c} {incr j} {
if {$j && $i} {
set ary($i,$j) "$array $i,$j"
} elseif {$i} {
set ary($i,$j) "$i"
} elseif {$j} {
set ary($i,$j) [format %c [expr 64+$j]]
}
}
}
}
proc changepage {w e name el op} {
global $name table
if {[string comp {} $el]} { set name [list $name\($el\)] }
set i [set $name]
if {[string comp $i [$w cget -var]]} {
$w sel clear all
$w config -variable $i
$e config -textvar ${i}(active)
$w activate origin
if {[info exists table($i)]} {
$w tag config colored -bg $table($i)
} else {
$w tag config colored -bg $table(default)
}
$w see active
}
}
label .example -text "TkTable v1 Spreadsheet Example"
label .current -textvar table(current) -width 5
entry .active -textvar $table(page)(active)
label .lpage -text "PAGE:" -width 6 -anchor e
tk_optionMenu .page table(page) AA BB CC DD
fill $table(page)
fill BB [expr {$table(rows)/2}] [expr {$table(cols)/2}]
trace var table(page) w [list changepage $table(table) .active]
set t $table(table)
table $t \
-rows $table(rows) \
-cols $table(cols) \
-variable $table(page) \
-titlerows 1 \
-titlecols 1 \
-yscrollcommand { .sy set } \
-xscrollcommand { .sx set } \
-coltagcommand colorize \
-flashmode on \
-selectmode extended \
-colstretch unset \
-rowstretch unset \
-width 5 -height 5 \
-browsecommand {set table(current) %S}
$t tag config colored -bg $table($table(page))
$t tag config title -fg red -relief groove
$t tag config blue -bg blue
$t tag config green -bg green
$t tag cell green 6,3 5,7 4,9
$t tag cell blue 8,8
$t tag row blue 7
$t tag col blue 6 8
$t width 0 3 2 7
scrollbar .sy -command [list $t yview]
scrollbar .sx -command [list $t xview] -orient horizontal
button .exit -text "Exit" -command exit
grid .example - - - - -sticky ew
grid .current .active .lpage .page - -sticky ew
grid $t - - - .sy -sticky ns
grid .sx - - - -sticky ew
grid .exit - - - - -sticky ew
grid columnconfig . 1 -weight 1
grid rowconfig . 2 -weight 1
grid config $t -sticky news
bind .active <Return> [list tkTableMoveCell $t 1 0]
menu .menu
menu .menu.file
. config -menu .menu
.menu add cascade -label "File" -underline 0 -menu .menu.file
.menu.file add command -label "Fill Array" -command { fill $table(page) }
.menu.file add command -label "Quit" -command exit
puts [list Table is $table(table) with array [$table(table) cget -var]]

BIN
tktable/demos/tcllogo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

344
tktable/demos/tktable.py Normal file
View File

@@ -0,0 +1,344 @@
#
# #### OUTDATE MODULE ####
# This has been superceded by the tktable.py that ships in the lib area.
# This is kept for compatibility as the newer wrapper is not 100% compatible.
# #### OUTDATE MODULE ####
#
# This file is taken from the usenet:
# http://groups.google.com/groups?selm=351A52BC.27EA0BE2%40desys.de
# From: Klaus Roethemeyer <klaus.roethemeyer at desys.de>
#
# It is provided here as an example of using Tktable with Python/Tkinter.
#============================================================================
#
# MODULE: This module contains the wrapper class for the tktable widget
#
# CREATED: Roethemeyer, 20.01.98
#
# VERSION: $Id: tktable.py,v 1.2 2008/11/14 22:49:35 hobbs Exp $
#
#============================================================================
#============================================================================
# import modules
#----------------------------------------------------------------------------
import string, types, Tkinter
#----------------------------------------------------------------------------
#============================================================================
# ArrayVar
#----------------------------------------------------------------------------
class ArrayVar(Tkinter.Variable):
_default = ''
def __init__(self, master = None):
Tkinter.Variable.__init__(self, master)
def get(self, index = None):
if not index:
res = {}
for i in self.names():
res[i] = self._tk.globalgetvar(self._name, i)
try: del res['None']
except KeyError: pass
return res
else:
return self._tk.globalgetvar(self._name, index)
def names(self):
return string.split(self._tk.call('array', 'names', self._name))
def set(self, index, value = ''):
if value == None:
value = ''
return self._tk.globalsetvar(self._name, index, value)
#----------------------------------------------------------------------------
#============================================================================
# Table
#----------------------------------------------------------------------------
class Table(Tkinter.Widget):
_switches1 = ('cols', 'holddimensions', 'holdtags', 'keeptitles', 'rows', '-')
_tabsubst_format = ('%c', '%C', '%i', '%r', '%s', '%S', '%W')
_tabsubst_commands = ('browsecommand', 'browsecmd', 'command',
'selectioncommand', 'selcmd',
'validatecommand', 'valcmd')
def __init__(self, master, cnf={}, **kw):
try:
master.tk.call('package', 'require', 'Tktable')
except Tkinter.TclError:
master.tk.call('load', '', 'Tktable')
Tkinter.Widget.__init__(self, master, 'table', cnf, kw)
def _options(self, cnf, kw = None):
if kw:
cnf = Tkinter._cnfmerge((cnf, kw))
else:
cnf = Tkinter._cnfmerge(cnf)
res = ()
for k, v in cnf.items():
if v is not None:
if k[-1] == '_': k = k[:-1]
if callable(v):
if k in self._tabsubst_commands:
v = "%s %s" % (self._register(v, self._tabsubst),
string.join(self._tabsubst_format))
else:
v = self._register(v)
res = res + ('-'+k, v)
return res
def _tabsubst(self, *args):
tk = self.tk
if len(args) != len(self._tabsubst_format): return args
c, C, i, r, s, S, W = args
e = Tkinter.Event()
e.widget = self
e.c = tk.getint(c)
e.i = tk.getint(i)
e.r = tk.getint(r)
e.C = (e.r, e.c)
try: e.s = tk.getint(s)
except Tkinter.TclError: e.s = s
try: e.S = tk.getint(S)
except Tkinter.TclError: e.S = S
e.W = W
return (e,)
def _getCells(self, cellString):
res = []
for i in string.split(cellString):
res.append(tuple(map(int, string.split(i, ','))))
return res
def _getLines(self, lineString):
return map(int, string.split(lineString))
def _prepareArgs1(self, args):
args = list(args)
for i in xrange(len(args)):
if args[i] in self._switches1:
args[i] = "-" + args[i]
return tuple(args)
def activate(self, index):
self.tk.call(self._w, 'activate', index)
def bbox(self, first, last=None):
return self._getints(self.tk.call(self._w, 'bbox', first, last)) or None
def border_mark(self, x, y, row=None, col=None):
self.tk.call(self._w, 'border', 'mark', x, y, row, col)
def border_dragto(self, x, y):
self.tk.call(self._w, 'border', 'dragto', x, y)
def curselection(self, setValue = None):
if setValue != None:
self.tk.call(self._w, 'curselection', 'set', setValue)
else:
return self._getCells(self.tk.call(self._w, 'curselection'))
def delete_active(self, index, more = None):
self.tk.call(self._w, 'delete', 'active', index, more)
def delete_cols(self, *args):
apply(self.tk.call, (self._w, 'delete', 'cols') + self._prepareArgs1(args))
def delete_rows(self, *args):
apply(self.tk.call, (self._w, 'delete', 'rows') + self._prepareArgs1(args))
def flush(self, first=None, last=None):
self.tk.call(self._w, 'flush', first, last)
def get(self, first, last=None):
return self.tk.call(self._w, 'get', first, last)
def height(self, *args):
apply(self.tk.call, (self._w, 'height') + args)
def icursor(self, arg):
self.tk.call(self._w, 'icursor', arg)
def index(self, index, rc = None):
if rc == None:
return self._getCells(self.tk.call(self._w, 'index', index, rc))[0]
else:
return self._getCells(self.tk.call(self._w, 'index', index, rc))[0][0]
def insert_active(self, index, value):
self.tk.call(self._w, 'insert', 'active', index, value)
def insert_cols(self, *args):
apply(self.tk.call, (self._w, 'insert', 'cols') + self._prepareArgs1(args))
def insert_rows(self, *args):
apply(self.tk.call, (self._w, 'insert', 'rows') + self._prepareArgs1(args))
def reread(self):
self.tk.call(self._w, 'reread')
def scan_mark(self, x, y):
self.tk.call(self._w, 'scan', 'mark', x, y)
def scan_dragto(self, x, y):
self.tk.call(self._w, 'scan', 'dragto', x, y)
def see(self, index):
self.tk.call(self._w, 'see', index)
def selection_anchor(self, index):
self.tk.call(self._w, 'selection', 'anchor', index)
def selection_clear(self, first, last=None):
self.tk.call(self._w, 'selection', 'clear', first, last)
def selection_includes(self, index):
return int(self.tk.call(self._w, 'selection', 'includes', index))
def selection_set(self, first, last=None):
self.tk.call(self._w, 'selection', 'set', first, last)
def set(self, *args):
apply(self.tk.call, (self._w, 'set') + args)
def tag_cell(self, tagName, *args):
result = apply(self.tk.call, (self._w, 'tag', 'cell', tagName) + args)
if not args: return self._getCells(result)
def tag_cget(self, tagName, option):
return self.tk.call(self._w, 'tag', 'cget', tagName, '-' + option)
def tag_col(self, tagName, *args):
result = apply(self.tk.call, (self._w, 'tag', 'col', tagName) + args)
if not args: return self._getLines(result)
def tag_configure(self, tagName, cnf={}, **kw):
if not cnf and not kw:
return self.tk.call(self._w, 'tag', 'configure', tagName)
if type(cnf) == types.StringType and not kw:
return self.tk.call(self._w, 'tag', 'configure', tagName, '-' + cnf)
if type(cnf) == types.DictType:
apply(self.tk.call,
(self._w, 'tag', 'configure', tagName)
+ self._options(cnf, kw))
else:
raise TypeError, "usage: <instance>.tag_configure tagName [option] | [option=value]+"
def tag_delete(self, tagName):
self.tk.call(self._w, 'tag', 'delete', tagName)
def tag_exists(self, tagName):
return self.getboolean(self.tk.call(self._w, 'tag', 'exists', tagName))
def tag_includes(self, tagName, index):
return self.getboolean(self.tk.call(self._w, 'tag', 'includes', tagName, index))
def tag_names(self, pattern=None):
return self.tk.call(self._w, 'tag', 'names', pattern)
def tag_row(self, tagName, *args):
result = apply(self.tk.call, (self._w, 'tag', 'row', tagName) + args)
if not args: return self._getLines(result)
def validate(self, index):
self.tk.call(self._w, 'validate', index)
def width(self, *args):
result = apply(self.tk.call, (self._w, 'width') + args)
if not args:
str = string.replace(result, '{', '')
str = string.replace(str, '}', '')
lst = string.split(str)
x = len(lst)
x2 = x / 2
return tuple(map(lambda i, j, l=lst: (int(l[i]), int(l[j])),
xrange(x2), xrange(x2, x)))
elif len(args) == 1:
return int(result)
else:
return result
def xview(self, *args):
if not args:
return self._getdoubles(self.tk.call(self._w, 'xview'))
apply(self.tk.call, (self._w, 'xview') + args)
def yview(self, *args):
if not args:
return self._getdoubles(self.tk.call(self._w, 'yview'))
apply(self.tk.call, (self._w, 'yview') + args)
#----------------------------------------------------------------------------
#============================================================================
# Test-Function
#----------------------------------------------------------------------------
if __name__ == '__main__':
from Tkinter import Tk, Label, Button
import pprint
prn = pprint.PrettyPrinter(indent = 6).pprint
def test_cmd(event=None):
if event.i == 0:
return '%i, %i' % (event.r, event.c)
else:
return 'set'
def browsecmd(event):
print "event:", event.__dict__
print "curselection:", test.curselection()
print "active:", test.index('active', 'row')
print "anchor:", test.index('anchor', 'row')
root = Tk()
#root.tk.call('load', '', 'Tktable')
var = ArrayVar(root)
for y in range(-1, 4):
for x in range(-1, 5):
index = "%i,%i" % (y, x)
var.set(index, index)
label = Label(root, text="Proof-of-existence test for Tktable")
label.pack(side = 'top', fill = 'x')
quit = Button(root, text="QUIT", command=root.destroy)
quit.pack(side = 'bottom', fill = 'x')
test = Table(root,
rows=10,
cols=5,
state='disabled',
width=6,
height=6,
titlerows=1,
titlecols=1,
roworigin=-1,
colorigin=-1,
selectmode='browse',
selecttype='row',
rowstretch='unset',
colstretch='last',
browsecmd=browsecmd,
flashmode='on',
variable=var,
usecommand=0,
command=test_cmd)
test.pack(expand=1, fill='both')
test.tag_configure('sel', background = 'yellow')
test.tag_configure('active', background = 'blue')
test.tag_configure('title', anchor='w', bg='red', relief='sunken')
root.mainloop()
#----------------------------------------------------------------------------

95
tktable/demos/valid.tcl Normal file
View File

@@ -0,0 +1,95 @@
#!/bin/sh
# the next line restarts using wish \
exec wish "$0" ${1+"$@"}
## valid.tcl
##
## This demos shows the use of the validation mechanism of the table
## and uses the table's cache (no -command or -variable)
##
## jeff at hobbs org
source [file join [file dirname [info script]] loadtable.tcl]
array set table {
rows 10
cols 10
table .table
}
proc colorize num {
if {$num>0 && $num%2} { return colored }
}
proc fill_headers {w {r 10} {c 10}} {
for {set i 1} {$i < $r} {incr i} {
$w set $i,0 "$i"
}
for {set j 1} {$j < $c} {incr j} {
if {$j%3==1} {
$w set 0,$j AlphaNum
} elseif {$j%2==1} {
$w set 0,$j Alpha
} elseif {$j} {
$w set 0,$j Real
}
}
}
proc validate {c val} {
if {$c%3==1} {
## Alphanum
set expr {^[A-Za-z0-9 ]*$}
} elseif {$c%2==1} {
## Alpha
set expr {^[A-Za-z ]*$}
} elseif {$c} {
## Real
set expr {^[-+]?[0-9]*\.?[0-9]*([0-9]\.?e[-+]?[0-9]*)?$}
}
if {[regexp $expr $val]} {
return 1
} else {
bell
return 0
}
}
label .example -text "TkTable v1 Validated Table Example"
set t $table(table)
table $t \
-rows $table(rows) \
-cols $table(cols) \
-cache 1 \
-titlerows 1 \
-titlecols 1 \
-yscrollcommand { .tsy set } \
-xscrollcommand { .tsx set } \
-width 5 -height 5 \
-coltagcommand colorize \
-flashmode on \
-selectmode extended \
-colstretch unset \
-rowstretch unset \
-validate yes \
-vcmd {if {![%W tag includes title %C]} { validate %c %S } }
fill_headers $t
$t tag config colored -bg lightblue
$t tag config title -fg red
$t width 0 3
scrollbar .tsy -command [list $t yview]
scrollbar .tsx -command [list $t xview] -orient horizontal
button .exit -text "Exit" -command {exit}
grid .example - -sticky ew
grid $t .tsy -sticky news
grid .tsx -sticky ew
grid .exit - -sticky ew
grid columnconfig . 0 -weight 1
grid rowconfig . 1 -weight 1
puts [list Table is $table(table)]

2039
tktable/doc/tkTable.html Normal file

File diff suppressed because it is too large Load Diff

1432
tktable/doc/tkTable.n Normal file

File diff suppressed because it is too large Load Diff

132
tktable/generic/tkAppInit.c Normal file
View File

@@ -0,0 +1,132 @@
/*
* tkAppInit.c --
*
* Provides a default version of the Tcl_AppInit procedure for
* use in wish and similar Tk-based applications.
*
* Copyright (c) 1993 The Regents of the University of California.
* Copyright (c) 1994-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* SCCS: @(#) tkAppInit.c 1.24 98/01/13 17:21:40
*/
#include "tk.h"
#include "locale.h"
/*
* The following variable is a special hack that is needed in order for
* Sun shared libraries to be used for Tcl.
*/
extern int matherr();
int *tclDummyMathPtr = (int *) matherr;
EXTERN int Tktable_Init _ANSI_ARGS_((Tcl_Interp *interp));
#ifdef TK_TEST
EXTERN int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN int Tktest_Init _ANSI_ARGS_((Tcl_Interp *interp));
#endif /* TK_TEST */
/*
*----------------------------------------------------------------------
*
* main --
*
* This is the main program for the application.
*
* Results:
* None: Tk_Main never returns here, so this procedure never
* returns either.
*
* Side effects:
* Whatever the application does.
*
*----------------------------------------------------------------------
*/
int
main(argc, argv)
int argc; /* Number of command-line arguments. */
char **argv; /* Values of command-line arguments. */
{
Tk_Main(argc, argv, Tcl_AppInit);
return 0; /* Needed only to prevent compiler warning. */
}
/*
*----------------------------------------------------------------------
*
* Tcl_AppInit --
*
* This procedure performs application-specific initialization.
* Most applications, especially those that incorporate additional
* packages, will have their own version of this procedure.
*
* Results:
* Returns a standard Tcl completion code, and leaves an error
* message in interp->result if an error occurs.
*
* Side effects:
* Depends on the startup script.
*
*----------------------------------------------------------------------
*/
int
Tcl_AppInit(interp)
Tcl_Interp *interp; /* Interpreter for application. */
{
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
if (Tk_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_StaticPackage(interp, "Tk", Tk_Init, (Tcl_PackageInitProc *) NULL);
#ifdef TK_TEST
if (Tcltest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init,
(Tcl_PackageInitProc *) NULL);
if (Tktest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_StaticPackage(interp, "Tktest", Tktest_Init,
(Tcl_PackageInitProc *) NULL);
#endif /* TK_TEST */
/*
* Call the init procedures for included packages. Each call should
* look like this:
*
* if (Mod_Init(interp) == TCL_ERROR) {
* return TCL_ERROR;
* }
*
* where "Mod" is the name of the module.
*/
if (Tktable_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_StaticPackage(interp, "Tktable", Tktable_Init, Tktable_SafeInit);
/*
* Call Tcl_CreateCommand for application-specific commands, if
* they weren't already created by the init procedures called above.
*/
/*
* Specify a user-specific startup file to invoke if the application
* is run interactively. Typically the startup file is "~/.apprc"
* where "app" is the name of the application. If this line is deleted
* then no user-specific startup file will be run under any conditions.
*/
Tcl_SetVar(interp, "tcl_rcFileName", "~/.wishrc", TCL_GLOBAL_ONLY);
return TCL_OK;
}

4090
tktable/generic/tkTable.c Normal file

File diff suppressed because it is too large Load Diff

658
tktable/generic/tkTable.h Normal file
View File

@@ -0,0 +1,658 @@
/*
* tkTable.h --
*
* This is the header file for the module that implements
* table widgets for the Tk toolkit.
*
* Copyright (c) 1997-2002 Jeffrey Hobbs
*
* See the file "license.txt" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tkTable.h,v 1.17 2004/07/20 20:46:21 hobbs Exp $
*/
#ifndef _TKTABLE_H_
#define _TKTABLE_H_
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <tk.h>
#ifdef MAC_TCL
# include <Xatom.h>
#else
# include <X11/Xatom.h>
#endif /* MAC_TCL */
#if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION == 0) /* Tcl8.0 stuff */
#define Tcl_GetString(objPtr) Tcl_GetStringFromObj(objPtr, (int *)NULL)
#endif
#if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))
# define HAVE_TCL84
#endif
/*
* Tcl/Tk 8.4 introduced better CONST-ness in the APIs, but we use CONST84 in
* some cases for compatibility with earlier Tcl headers to prevent warnings.
*/
#ifndef CONST84
# define CONST84
#endif
/* This EXTERN declaration is needed for Tcl < 8.0.3 */
#ifndef EXTERN
# ifdef __cplusplus
# define EXTERN extern "C"
# else
# define EXTERN extern
# endif
#endif
#ifdef TCL_STORAGE_CLASS
# undef TCL_STORAGE_CLASS
#endif
#ifdef BUILD_Tktable
# define TCL_STORAGE_CLASS DLLEXPORT
#else
# define TCL_STORAGE_CLASS DLLIMPORT
#endif
#ifdef WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
/* VC++ has an entry point called DllMain instead of DllEntryPoint */
# if defined(_MSC_VER)
# define DllEntryPoint DllMain
# endif
#endif
#if defined(WIN32) || defined(MAC_TCL) || defined(MAC_OSX_TK)
/* XSync call defined in the internals for some reason */
# ifndef XSync
# define XSync(display, bool) {display->request++;}
# endif
#endif /* defn of XSync */
#ifndef NORMAL_BG
# ifdef WIN32
# define NORMAL_BG "SystemButtonFace"
# define ACTIVE_BG NORMAL_BG
# define SELECT_BG "SystemHighlight"
# define SELECT_FG "SystemHighlightText"
# define DISABLED "SystemDisabledText"
# define HIGHLIGHT "SystemWindowFrame"
# define DEF_TABLE_FONT "{MS Sans Serif} 8"
# elif defined(MAC_TCL) || defined(MAC_OSX_TK)
# define NORMAL_BG "systemWindowBody"
# define ACTIVE_BG "#ececec"
# define SELECT_BG "systemHighlight"
# define SELECT_FG "systemHighlightText"
# define DISABLED "#a3a3a3"
# define HIGHLIGHT "Black"
# define DEF_TABLE_FONT "Helvetica 12"
# else
# define NORMAL_BG "#d9d9d9"
# define ACTIVE_BG "#fcfcfc"
# define SELECT_BG "#c3c3c3"
# define SELECT_FG "Black"
# define DISABLED "#a3a3a3"
# define HIGHLIGHT "Black"
# define DEF_TABLE_FONT "Helvetica -12"
# endif
#endif /* NORMAL_BG */
#define MAX(A,B) (((A)>(B))?(A):(B))
#define MIN(A,B) (((A)>(B))?(B):(A))
#define BETWEEN(val,min,max) ( ((val)<(min)) ? (min) : \
( ((val)>(max)) ? (max) : (val) ) )
#define CONSTRAIN(val,min,max) if ((val) < (min)) { (val) = (min); } \
else if ((val) > (max)) { (val) = (max); }
#define STREQ(s1, s2) (strcmp((s1), (s2)) == 0)
#define ARSIZE(A) (sizeof(A)/sizeof(*A))
#define INDEX_BUFSIZE 32 /* max size of buffer for indices */
#define TEST_KEY "#TEST KEY#" /* index for testing array existence */
/*
* Assigned bits of "flags" fields of Table structures, and what those
* bits mean:
*
* REDRAW_PENDING: Non-zero means a DoWhenIdle handler has
* already been queued to redisplay the table.
* REDRAW_BORDER: Non-zero means 3-D border must be redrawn
* around window during redisplay. Normally
* only text portion needs to be redrawn.
* CURSOR_ON: Non-zero means insert cursor is displayed at
* present. 0 means it isn't displayed.
* TEXT_CHANGED: Non-zero means the active cell text is being edited.
* HAS_FOCUS: Non-zero means this window has the input focus.
* HAS_ACTIVE: Non-zero means the active cell is set.
* HAS_ANCHOR: Non-zero means the anchor cell is set.
* BROWSE_CMD: Non-zero means we're evaluating the -browsecommand.
* VALIDATING: Non-zero means we are in a valCmd
* SET_ACTIVE: About to set the active array element internally
* ACTIVE_DISABLED: Non-zero means the active cell is -state disabled
* OVER_BORDER: Non-zero means we are over a table cell border
* REDRAW_ON_MAP: Forces a redraw on the unmap
* AVOID_SPANS: prevent cell spans from being used
*
* FIX - consider adding UPDATE_SCROLLBAR a la entry
*/
#define REDRAW_PENDING (1L<<0)
#define CURSOR_ON (1L<<1)
#define HAS_FOCUS (1L<<2)
#define TEXT_CHANGED (1L<<3)
#define HAS_ACTIVE (1L<<4)
#define HAS_ANCHOR (1L<<5)
#define BROWSE_CMD (1L<<6)
#define REDRAW_BORDER (1L<<7)
#define VALIDATING (1L<<8)
#define SET_ACTIVE (1L<<9)
#define ACTIVE_DISABLED (1L<<10)
#define OVER_BORDER (1L<<11)
#define REDRAW_ON_MAP (1L<<12)
#define AVOID_SPANS (1L<<13)
/* Flags for TableInvalidate && TableRedraw */
#define ROW (1L<<0)
#define COL (1L<<1)
#define CELL (1L<<2)
#define CELL_BAD (1<<0)
#define CELL_OK (1<<1)
#define CELL_SPAN (1<<2)
#define CELL_HIDDEN (1<<3)
#define CELL_VIEWABLE (CELL_OK|CELL_SPAN)
#define INV_FILL (1L<<3) /* use for Redraw when the affected
* row/col will affect neighbors */
#define INV_FORCE (1L<<4)
#define INV_HIGHLIGHT (1L<<5)
#define INV_NO_ERR_MSG (1L<<5) /* Don't leave an error message */
/* These alter how the selection set/clear commands behave */
#define SEL_ROW (1<<0)
#define SEL_COL (1<<1)
#define SEL_BOTH (1<<2)
#define SEL_CELL (1<<3)
#define SEL_NONE (1<<4)
/*
* Definitions for tablePtr->dataSource, by bit
*/
#define DATA_NONE 0
#define DATA_CACHE (1<<1)
#define DATA_ARRAY (1<<2)
#define DATA_COMMAND (1<<3)
/*
* Definitions for configuring -borderwidth
*/
#define BD_TABLE 0
#define BD_TABLE_TAG (1<<1)
#define BD_TABLE_WIN (1<<2)
/*
* Possible state values for tags
*/
typedef enum {
STATE_UNUSED, STATE_UNKNOWN, STATE_HIDDEN,
STATE_NORMAL, STATE_DISABLED, STATE_ACTIVE, STATE_LAST
} TableState;
/*
* Structure for use in parsing table commands/values.
* Accessor functions defined in tkTableUtil.c
*/
typedef struct {
char *name; /* name of the command/value */
int value; /* >0 because 0 represents an error or proc */
} Cmd_Struct;
/*
* The tag structure
*/
typedef struct {
Tk_3DBorder bg; /* background color */
Tk_3DBorder fg; /* foreground color */
char * borderStr; /* border style */
int borders; /* number of borders specified (1, 2 or 4) */
int bd[4]; /* cell border width */
int relief; /* relief type */
Tk_Font tkfont; /* Information about text font, or NULL. */
Tk_Anchor anchor; /* default anchor point */
char * imageStr; /* name of image */
Tk_Image image; /* actual pointer to image, if any */
TableState state; /* state of the cell */
Tk_Justify justify; /* justification of text in the cell */
int multiline; /* wrapping style of multiline text */
int wrap; /* wrapping style of multiline text */
int showtext; /* whether to display text over image */
char * ellipsis; /* ellipsis to display on clipped text */
} TableTag;
/* The widget structure for the table Widget */
typedef struct {
/* basic information about the window and the interpreter */
Tk_Window tkwin;
Display *display;
Tcl_Interp *interp;
Tcl_Command widgetCmd; /* Token for entry's widget command. */
/*
* Configurable Options
*/
int autoClear;
char *selectMode; /* single, browse, multiple, or extended */
int selectType; /* row, col, both, or cell */
int selectTitles; /* whether to do automatic title selection */
int rows, cols; /* number of rows and columns */
int defRowHeight; /* default row height in chars (positive)
* or pixels (negative) */
int defColWidth; /* default column width in chars (positive)
* or pixels (negative) */
int maxReqCols; /* the requested # cols to display */
int maxReqRows; /* the requested # rows to display */
int maxReqWidth; /* the maximum requested width in pixels */
int maxReqHeight; /* the maximum requested height in pixels */
char *arrayVar; /* name of traced array variable */
char *rowSep; /* separator string to place between
* rows when getting selection */
char *colSep; /* separator string to place between
* cols when getting selection */
TableTag defaultTag; /* the default tag colors/fonts etc */
char *yScrollCmd; /* the y-scroll command */
char *xScrollCmd; /* the x-scroll command */
char *browseCmd; /* the command that is called when the
* active cell changes */
int caching; /* whether to cache values of table */
char *command; /* A command to eval when get/set occurs
* for table values */
int useCmd; /* Signals whether to use command or the
* array variable, will be 0 if command errs */
char *selCmd; /* the command that is called to when a
* [selection get] call occurs for a table */
char *valCmd; /* Command prefix to use when invoking
* validate command. NULL means don't
* invoke commands. Malloc'ed. */
int validate; /* Non-zero means try to validate */
Tk_3DBorder insertBg; /* the cursor color */
Tk_Cursor cursor; /* the regular mouse pointer */
Tk_Cursor bdcursor; /* the mouse pointer when over borders */
#ifdef TITLE_CURSOR
Tk_Cursor titleCursor; /* the mouse pointer when over titles */
#endif
int exportSelection; /* Non-zero means tie internal table
* to X selection. */
TableState state; /* Normal or disabled. Table is read-only
* when disabled. */
int insertWidth; /* Total width of insert cursor. */
int insertBorderWidth; /* Width of 3-D border around insert cursor. */
int insertOnTime; /* Number of milliseconds cursor should spend
* in "on" state for each blink. */
int insertOffTime; /* Number of milliseconds cursor should spend
* in "off" state for each blink. */
int invertSelected; /* Whether to draw selected cells swapping
* foreground and background */
int colStretch; /* The way to stretch columns if the window
* is too large */
int rowStretch; /* The way to stretch rows if the window is
* too large */
int colOffset; /* X index of leftmost col in the display */
int rowOffset; /* Y index of topmost row in the display */
int drawMode; /* The mode to use when redrawing */
int flashMode; /* Specifies whether flashing is enabled */
int flashTime; /* The number of ms to flash a cell for */
int resize; /* -resizeborders option for interactive
* resizing of borders */
int sparse; /* Whether to use "sparse" arrays by
* deleting empty array elements (default) */
char *rowTagCmd, *colTagCmd;/* script to eval for getting row/tag cmd */
int highlightWidth; /* Width in pixels of highlight to draw
* around widget when it has the focus.
* <= 0 means don't draw a highlight. */
XColor *highlightBgColorPtr;/* Color for drawing traversal highlight
* area when highlight is off. */
XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
char *takeFocus; /* Used only in Tcl to check if this
* widget will accept focus */
int padX, padY; /* Extra space around text (pixels to leave
* on each side). Ignored for bitmaps and
* images. */
int ipadX, ipadY; /* Space to leave empty around cell borders.
* This differs from pad* in that it is always
* present for the cell (except windows). */
/*
* Cached Information
*/
#ifdef TITLE_CURSOR
Tk_Cursor *lastCursorPtr; /* pointer to last cursor defined. */
#endif
int titleRows, titleCols; /* the number of rows|cols to use as a title */
/* these are kept in real coords */
int topRow, leftCol; /* The topleft cell to display excluding the
* fixed title rows. This is just the
* config request. The actual cell used may
* be different to keep the screen full */
int anchorRow, anchorCol; /* the row,col of the anchor cell */
int activeRow, activeCol; /* the row,col of the active cell */
int oldTopRow, oldLeftCol; /* cached by TableAdjustParams */
int oldActRow, oldActCol; /* cached by TableAdjustParams */
int icursor; /* The index of the insertion cursor in the
* active cell */
int flags; /* An or'ed combination of flags concerning
* redraw/cursor etc. */
int dataSource; /* where our data comes from:
* DATA_{NONE,CACHE,ARRAY,COMMAND} */
int maxWidth, maxHeight; /* max width|height required in pixels */
int charWidth, charHeight; /* size of a character in the default font */
int *colPixels, *rowPixels; /* Array of the pixel widths/heights */
int *colStarts, *rowStarts; /* Array of start pixels for rows|columns */
int scanMarkX, scanMarkY; /* Used by "scan" and "border" to mark */
int scanMarkRow, scanMarkCol;/* necessary information for dragto */
/* values in these are kept in user coords */
Tcl_HashTable *cache; /* value cache */
/*
* colWidths and rowHeights are indexed from 0, so always adjust numbers
* by the appropriate *Offset factor
*/
Tcl_HashTable *colWidths; /* hash table of non default column widths */
Tcl_HashTable *rowHeights; /* hash table of non default row heights */
Tcl_HashTable *spanTbl; /* table for spans */
Tcl_HashTable *spanAffTbl; /* table for cells affected by spans */
Tcl_HashTable *tagTable; /* table for style tags */
Tcl_HashTable *winTable; /* table for embedded windows */
Tcl_HashTable *rowStyles; /* table for row styles */
Tcl_HashTable *colStyles; /* table for col styles */
Tcl_HashTable *cellStyles; /* table for cell styles */
Tcl_HashTable *flashCells; /* table of flashing cells */
Tcl_HashTable *selCells; /* table of selected cells */
Tcl_TimerToken cursorTimer; /* timer token for the cursor blinking */
Tcl_TimerToken flashTimer; /* timer token for the cell flashing */
char *activeBuf; /* buffer where the selection is kept
* for editing the active cell */
char **tagPrioNames; /* list of tag names in priority order */
TableTag **tagPrios; /* list of tag pointers in priority order */
TableTag *activeTagPtr; /* cache of active composite tag */
int activeX, activeY; /* cache offset of active layout in cell */
int tagPrioSize; /* size of tagPrios list */
int tagPrioMax; /* max allocated size of tagPrios list */
/* The invalid rectangle if there is an update pending */
int invalidX, invalidY, invalidWidth, invalidHeight;
int seen[4]; /* see TableUndisplay */
#ifdef POSTSCRIPT
/* Pointer to information used for generating Postscript for the canvas.
* NULL means no Postscript is currently being generated. */
struct TkPostscriptInfo *psInfoPtr;
#endif
#ifdef PROCS
Tcl_HashTable *inProc; /* cells where proc is being evaled */
int showProcs; /* whether to show embedded proc (1) or
* its calculated value (0) */
int hasProcs; /* whether table has embedded procs or not */
#endif
} Table;
/*
* HEADERS FOR EMBEDDED WINDOWS
*/
/*
* A structure of the following type holds information for each window
* embedded in a table widget.
*/
typedef struct TableEmbWindow {
Table *tablePtr; /* Information about the overall table
* widget. */
Tk_Window tkwin; /* Window for this segment. NULL means that
* the window hasn't been created yet. */
Tcl_HashEntry *hPtr; /* entry into winTable */
char *create; /* Script to create window on-demand.
* NULL means no such script.
* Malloc-ed. */
Tk_3DBorder bg; /* background color */
char *borderStr; /* border style */
int borders; /* number of borders specified (1, 2 or 4) */
int bd[4]; /* border width for cell around window */
int relief; /* relief type */
int sticky; /* How to align window in space */
int padX, padY; /* Padding to leave around each side
* of window, in pixels. */
int displayed; /* Non-zero means that the window has been
* displayed on the screen recently. */
} TableEmbWindow;
extern Tk_ConfigSpec tableSpecs[];
extern void EmbWinDisplay(Table *tablePtr, Drawable window,
TableEmbWindow *ewPtr, TableTag *tagPtr,
int x, int y, int width, int height);
extern void EmbWinUnmap(register Table *tablePtr,
int rlo, int rhi, int clo, int chi);
extern void EmbWinDelete(register Table *tablePtr, TableEmbWindow *ewPtr);
extern int Table_WinMove(register Table *tablePtr,
char *CONST srcPtr, char *CONST destPtr, int flags);
extern int Table_WinDelete(register Table *tablePtr, char *CONST idxPtr);
extern int Table_WindowCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int TableValidateChange(Table *tablePtr, int r,
int c, char *oldVal, char *newVal, int idx);
extern void TableLostSelection(ClientData clientData);
extern void TableSetActiveIndex(register Table *tablePtr);
/*
* HEADERS IN tkTableCmds.c
*/
extern int Table_ActivateCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_AdjustCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_BboxCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_BorderCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_ClearCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_CurselectionCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_CurvalueCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_GetCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_ScanCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_SeeCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_SelAnchorCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_SelClearCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_SelIncludesCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_SelSetCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_ViewCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
/*
* HEADERS IN tkTableEdit.c
*/
extern int Table_EditCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern void TableDeleteChars(register Table *tablePtr,
int idx, int count);
extern void TableInsertChars(register Table *tablePtr,
int idx, char *string);
/*
* HEADERS IN tkTableTag.c
*/
extern TableTag *TableNewTag(Table *tablePtr);
extern void TableResetTag(Table *tablePtr, TableTag *tagPtr);
extern void TableMergeTag(Table *tablePtr, TableTag *baseTag,
TableTag *addTag);
extern void TableInvertTag(TableTag *baseTag);
extern int TableGetTagBorders(TableTag *tagPtr,
int *left, int *right, int *top, int *bottom);
extern void TableInitTags(Table *tablePtr);
extern TableTag *FindRowColTag(Table *tablePtr,
int cell, int type);
extern void TableCleanupTag(Table *tablePtr,
TableTag *tagPtr);
extern int Table_TagCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
/*
* HEADERS IN tkTableUtil.c
*/
extern void Table_ClearHashTable(Tcl_HashTable *hashTblPtr);
extern int TableOptionBdSet(ClientData clientData,
Tcl_Interp *interp, Tk_Window tkwin,
CONST84 char *value, char *widgRec, int offset);
extern char * TableOptionBdGet(ClientData clientData,
Tk_Window tkwin, char *widgRec, int offset,
Tcl_FreeProc **freeProcPtr);
extern int TableTagConfigureBd(Table *tablePtr,
TableTag *tagPtr, char *oldValue, int nullOK);
extern int Cmd_OptionSet(ClientData clientData,
Tcl_Interp *interp,
Tk_Window unused, CONST84 char *value,
char *widgRec, int offset);
extern char * Cmd_OptionGet(ClientData clientData,
Tk_Window unused, char *widgRec,
int offset, Tcl_FreeProc **freeProcPtr);
/*
* HEADERS IN tkTableCell.c
*/
extern int TableTrueCell(Table *tablePtr, int row, int col,
int *trow, int *tcol);
extern int TableCellCoords(Table *tablePtr, int row,
int col, int *rx, int *ry, int *rw, int *rh);
extern int TableCellVCoords(Table *tablePtr, int row,
int col, int *rx, int *ry,
int *rw, int *rh, int full);
extern void TableWhatCell(register Table *tablePtr,
int x, int y, int *row, int *col);
extern int TableAtBorder(Table *tablePtr, int x, int y,
int *row, int *col);
extern char * TableGetCellValue(Table *tablePtr, int r, int c);
extern int TableSetCellValue(Table *tablePtr, int r, int c,
char *value);
extern int TableMoveCellValue(Table *tablePtr,
int fromr, int fromc, char *frombuf,
int tor, int toc, char *tobuf, int outOfBounds);
extern int TableGetIcursor(Table *tablePtr, char *arg,
int *posn);
#define TableGetIcursorObj(tablePtr, objPtr, posnPtr) \
TableGetIcursor(tablePtr, Tcl_GetString(objPtr), posnPtr)
extern int TableGetIndex(register Table *tablePtr,
char *str, int *row_p, int *col_p);
#define TableGetIndexObj(tablePtr, objPtr, rowPtr, colPtr) \
TableGetIndex(tablePtr, Tcl_GetString(objPtr), rowPtr, colPtr)
extern int Table_SetCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_HiddenCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern int Table_SpanCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern void TableSpanSanCheck(register Table *tablePtr);
/*
* HEADERS IN TKTABLECELLSORT
*/
/*
* We keep the old CellSort true because it is used for grabbing
* the selection, so we really want them ordered
*/
extern char * TableCellSort(Table *tablePtr, char *str);
#ifdef NO_SORT_CELLS
# define TableCellSortObj(interp, objPtr) (objPtr)
#else
extern Tcl_Obj* TableCellSortObj(Tcl_Interp *interp, Tcl_Obj *listObjPtr);
#endif
/*
* HEADERS IN TKTABLEPS
*/
#ifdef POSTSCRIPT
extern int Table_PostscriptCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
extern void Tcl_DStringAppendAllTCL_VARARGS(Tcl_DString *, arg1);
#endif
/*
* HEADERS IN TKTABLE
*/
EXTERN int Tktable_Init(Tcl_Interp *interp);
EXTERN int Tktable_SafeInit(Tcl_Interp *interp);
extern void TableGetActiveBuf(register Table *tablePtr);
extern void ExpandPercents(Table *tablePtr, char *before,
int r, int c, char *oldVal, char *newVal, int idx,
Tcl_DString *dsPtr, int cmdType);
extern void TableInvalidate(Table *tablePtr, int x, int y,
int width, int height, int force);
extern void TableRefresh(register Table *tablePtr,
int arg1, int arg2, int mode);
extern void TableGeometryRequest(Table *tablePtr);
extern void TableAdjustActive(register Table *tablePtr);
extern void TableAdjustParams(register Table *tablePtr);
extern void TableConfigCursor(register Table *tablePtr);
extern void TableAddFlash(Table *tablePtr, int row, int col);
#define TableInvalidateAll(tablePtr, flags) \
TableInvalidate((tablePtr), 0, 0, Tk_Width((tablePtr)->tkwin),\
Tk_Height((tablePtr)->tkwin), (flags))
/*
* Turn row/col into an index into the table
*/
#define TableMakeArrayIndex(r, c, i) sprintf((i), "%d,%d", (r), (c))
/*
* Turn array index back into row/col
* return the number of args parsed (should be two)
*/
#define TableParseArrayIndex(r, c, i) sscanf((i), "%d,%d", (r), (c))
/*
* Macro for finding the last cell of the table
*/
#define TableGetLastCell(tablePtr, rowPtr, colPtr) \
TableWhatCell((tablePtr),\
Tk_Width((tablePtr)->tkwin)-(tablePtr)->highlightWidth-1,\
Tk_Height((tablePtr)->tkwin)-(tablePtr)->highlightWidth-1,\
(rowPtr), (colPtr))
/*
* end of header
* reset TCL_STORAGE_CLASS to DLLIMPORT.
*/
#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLIMPORT
#endif /* _TKTABLE_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,400 @@
/*
* tkTableCell.c --
*
* This module implements cell sort functions for table
* widgets. The MergeSort algorithm and other aux sorting
* functions were taken from tclCmdIL.c lsort command:
* tclCmdIL.c --
*
* This file contains the top-level command routines for most of
* the Tcl built-in commands whose names begin with the letters
* I through L. It contains only commands in the generic core
* (i.e. those that don't depend much upon UNIX facilities).
*
* Copyright (c) 1987-1993 The Regents of the University of California.
* Copyright (c) 1993-1997 Lucent Technologies.
* Copyright (c) 1994-1997 Sun Microsystems, Inc.
* Copyright (c) 1998-1999 by Scriptics Corporation.
*
* Copyright (c) 1998-2002 Jeffrey Hobbs
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
*/
#include "tkTable.h"
#ifndef UCHAR
#define UCHAR(c) ((unsigned char) (c))
#endif
/*
* During execution of the "lsort" command, structures of the following
* type are used to arrange the objects being sorted into a collection
* of linked lists.
*/
typedef struct SortElement {
Tcl_Obj *objPtr; /* Object being sorted. */
struct SortElement *nextPtr; /* Next element in the list, or
* NULL for end of list. */
} SortElement;
static int TableSortCompareProc _ANSI_ARGS_((CONST VOID *first,
CONST VOID *second));
static SortElement * MergeSort _ANSI_ARGS_((SortElement *headPt));
static SortElement * MergeLists _ANSI_ARGS_((SortElement *leftPtr,
SortElement *rightPtr));
static int DictionaryCompare _ANSI_ARGS_((char *left,
char *right));
/*
*----------------------------------------------------------------------
*
* TableSortCompareProc --
* This procedure is invoked by qsort to determine the proper
* ordering between two elements.
*
* Results:
* < 0 means first is "smaller" than "second", > 0 means "first"
* is larger than "second", and 0 means they should be treated
* as equal.
*
* Side effects:
* None, unless a user-defined comparison command does something
* weird.
*
*----------------------------------------------------------------------
*/
static int
TableSortCompareProc(first, second)
CONST VOID *first, *second; /* Elements to be compared. */
{
char *str1 = *((char **) first);
char *str2 = *((char **) second);
return DictionaryCompare(str1, str2);
}
/*
*----------------------------------------------------------------------
*
* TableCellSort --
* Sort a list of table cell elements (of form row,col)
*
* Results:
* Returns the sorted list of elements. Because Tcl_Merge allocs
* the space for result, it must later be Tcl_Free'd by caller.
*
* Side effects:
* Behaviour undefined for ill-formed input list of elements.
*
*----------------------------------------------------------------------
*/
char *
TableCellSort(Table *tablePtr, char *str)
{
int listArgc;
CONST84 char **listArgv;
char *result;
if (Tcl_SplitList(tablePtr->interp, str, &listArgc, &listArgv) != TCL_OK) {
return str;
}
/* Thread safety: qsort is reportedly not thread-safe... */
qsort((VOID *) listArgv, (size_t) listArgc, sizeof (char *),
TableSortCompareProc);
result = Tcl_Merge(listArgc, listArgv);
ckfree((char *) listArgv);
return result;
}
/*
*----------------------------------------------------------------------
*
* DictionaryCompare - Not the Unicode version
*
* This function compares two strings as if they were being used in
* an index or card catalog. The case of alphabetic characters is
* ignored, except to break ties. Thus "B" comes before "b" but
* after "a". Also, integers embedded in the strings compare in
* numerical order. In other words, "x10y" comes after "x9y", not
* before it as it would when using strcmp().
*
* Results:
* A negative result means that the first element comes before the
* second, and a positive result means that the second element
* should come first. A result of zero means the two elements
* are equal and it doesn't matter which comes first.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
DictionaryCompare(left, right)
char *left, *right; /* The strings to compare */
{
int diff, zeros;
int secondaryDiff = 0;
while (1) {
if (isdigit(UCHAR(*right)) && isdigit(UCHAR(*left))) {
/*
* There are decimal numbers embedded in the two
* strings. Compare them as numbers, rather than
* strings. If one number has more leading zeros than
* the other, the number with more leading zeros sorts
* later, but only as a secondary choice.
*/
zeros = 0;
while ((*right == '0') && (isdigit(UCHAR(right[1])))) {
right++;
zeros--;
}
while ((*left == '0') && (isdigit(UCHAR(left[1])))) {
left++;
zeros++;
}
if (secondaryDiff == 0) {
secondaryDiff = zeros;
}
/*
* The code below compares the numbers in the two
* strings without ever converting them to integers. It
* does this by first comparing the lengths of the
* numbers and then comparing the digit values.
*/
diff = 0;
while (1) {
if (diff == 0) {
diff = UCHAR(*left) - UCHAR(*right);
}
right++;
left++;
if (!isdigit(UCHAR(*right))) {
if (isdigit(UCHAR(*left))) {
return 1;
} else {
/*
* The two numbers have the same length. See
* if their values are different.
*/
if (diff != 0) {
return diff;
}
break;
}
} else if (!isdigit(UCHAR(*left))) {
return -1;
}
}
continue;
}
diff = UCHAR(*left) - UCHAR(*right);
if (diff) {
if (isupper(UCHAR(*left)) && islower(UCHAR(*right))) {
diff = UCHAR(tolower(*left)) - UCHAR(*right);
if (diff) {
return diff;
} else if (secondaryDiff == 0) {
secondaryDiff = -1;
}
} else if (isupper(UCHAR(*right)) && islower(UCHAR(*left))) {
diff = UCHAR(*left) - UCHAR(tolower(UCHAR(*right)));
if (diff) {
return diff;
} else if (secondaryDiff == 0) {
secondaryDiff = 1;
}
} else {
return diff;
}
}
if (*left == 0) {
break;
}
left++;
right++;
}
if (diff == 0) {
diff = secondaryDiff;
}
return diff;
}
/*
*----------------------------------------------------------------------
*
* MergeLists -
*
* This procedure combines two sorted lists of SortElement structures
* into a single sorted list.
*
* Results:
* The unified list of SortElement structures.
*
* Side effects:
* None, unless a user-defined comparison command does something
* weird.
*
*----------------------------------------------------------------------
*/
static SortElement *
MergeLists(leftPtr, rightPtr)
SortElement *leftPtr; /* First list to be merged; may be
* NULL. */
SortElement *rightPtr; /* Second list to be merged; may be
* NULL. */
{
SortElement *headPtr;
SortElement *tailPtr;
if (leftPtr == NULL) {
return rightPtr;
}
if (rightPtr == NULL) {
return leftPtr;
}
if (DictionaryCompare(Tcl_GetString(leftPtr->objPtr),
Tcl_GetString(rightPtr->objPtr)) > 0) {
tailPtr = rightPtr;
rightPtr = rightPtr->nextPtr;
} else {
tailPtr = leftPtr;
leftPtr = leftPtr->nextPtr;
}
headPtr = tailPtr;
while ((leftPtr != NULL) && (rightPtr != NULL)) {
if (DictionaryCompare(Tcl_GetString(leftPtr->objPtr),
Tcl_GetString(rightPtr->objPtr)) > 0) {
tailPtr->nextPtr = rightPtr;
tailPtr = rightPtr;
rightPtr = rightPtr->nextPtr;
} else {
tailPtr->nextPtr = leftPtr;
tailPtr = leftPtr;
leftPtr = leftPtr->nextPtr;
}
}
if (leftPtr != NULL) {
tailPtr->nextPtr = leftPtr;
} else {
tailPtr->nextPtr = rightPtr;
}
return headPtr;
}
/*
*----------------------------------------------------------------------
*
* MergeSort -
*
* This procedure sorts a linked list of SortElement structures
* use the merge-sort algorithm.
*
* Results:
* A pointer to the head of the list after sorting is returned.
*
* Side effects:
* None, unless a user-defined comparison command does something
* weird.
*
*----------------------------------------------------------------------
*/
static SortElement *
MergeSort(headPtr)
SortElement *headPtr; /* First element on the list */
{
/*
* The subList array below holds pointers to temporary lists built
* during the merge sort. Element i of the array holds a list of
* length 2**i.
*/
# define NUM_LISTS 30
SortElement *subList[NUM_LISTS];
SortElement *elementPtr;
int i;
for(i = 0; i < NUM_LISTS; i++){
subList[i] = NULL;
}
while (headPtr != NULL) {
elementPtr = headPtr;
headPtr = headPtr->nextPtr;
elementPtr->nextPtr = 0;
for (i = 0; (i < NUM_LISTS) && (subList[i] != NULL); i++){
elementPtr = MergeLists(subList[i], elementPtr);
subList[i] = NULL;
}
if (i >= NUM_LISTS) {
i = NUM_LISTS-1;
}
subList[i] = elementPtr;
}
elementPtr = NULL;
for (i = 0; i < NUM_LISTS; i++){
elementPtr = MergeLists(subList[i], elementPtr);
}
return elementPtr;
}
#ifndef NO_SORT_CELLS
/*
*----------------------------------------------------------------------
*
* TableCellSortObj --
* Sorts a list of table cell elements (of form row,col) in place
*
* Results:
* Sorts list of elements in place.
*
* Side effects:
* Behaviour undefined for ill-formed input list of elements.
*
*----------------------------------------------------------------------
*/
Tcl_Obj *
TableCellSortObj(Tcl_Interp *interp, Tcl_Obj *listObjPtr)
{
int length, i;
Tcl_Obj *sortedObjPtr, **listObjPtrs;
SortElement *elementArray;
SortElement *elementPtr;
if (Tcl_ListObjGetElements(interp, listObjPtr,
&length, &listObjPtrs) != TCL_OK) {
return NULL;
}
if (length <= 0) {
return listObjPtr;
}
elementArray = (SortElement *) ckalloc(length * sizeof(SortElement));
for (i=0; i < length; i++){
elementArray[i].objPtr = listObjPtrs[i];
elementArray[i].nextPtr = &elementArray[i+1];
}
elementArray[length-1].nextPtr = NULL;
elementPtr = MergeSort(elementArray);
sortedObjPtr = Tcl_NewObj();
for (; elementPtr != NULL; elementPtr = elementPtr->nextPtr){
Tcl_ListObjAppendElement(NULL, sortedObjPtr, elementPtr->objPtr);
}
ckfree((char*) elementArray);
return sortedObjPtr;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,723 @@
/*
* tkTableEdit.c --
*
* This module implements editing functions of a table widget.
*
* Copyright (c) 1998-2000 Jeffrey Hobbs
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tkTableEdit.c,v 1.7 2002/10/16 07:30:56 hobbs Exp $
*/
#include "tkTable.h"
static void TableModifyRC _ANSI_ARGS_((register Table *tablePtr,
int doRows, int movetag,
Tcl_HashTable *tagTblPtr, Tcl_HashTable *dimTblPtr,
int offset, int from, int to, int lo, int hi,
int outOfBounds));
/* insert/delete subcommands */
static CONST84 char *modCmdNames[] = {
"active", "cols", "rows", (char *)NULL
};
enum modCmd {
MOD_ACTIVE, MOD_COLS, MOD_ROWS
};
/* insert/delete row/col switches */
static CONST84 char *rcCmdNames[] = {
"-keeptitles", "-holddimensions", "-holdselection",
"-holdtags", "-holdwindows", "--",
(char *) NULL
};
enum rcCmd {
OPT_TITLES, OPT_DIMS, OPT_SEL,
OPT_TAGS, OPT_WINS, OPT_LAST
};
#define HOLD_TITLES 1<<0
#define HOLD_DIMS 1<<1
#define HOLD_TAGS 1<<2
#define HOLD_WINS 1<<3
#define HOLD_SEL 1<<4
/*
*--------------------------------------------------------------
*
* Table_EditCmd --
* This procedure is invoked to process the insert/delete method
* that corresponds to a table widget managed by this module.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*--------------------------------------------------------------
*/
int
Table_EditCmd(ClientData clientData, register Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
register Table *tablePtr = (Table *) clientData;
int doInsert, cmdIndex, first, last;
if (objc < 4) {
Tcl_WrongNumArgs(interp, 2, objv,
"option ?switches? arg ?arg?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[2], modCmdNames,
"option", 0, &cmdIndex) != TCL_OK) {
return TCL_ERROR;
}
doInsert = (*(Tcl_GetString(objv[1])) == 'i');
switch ((enum modCmd) cmdIndex) {
case MOD_ACTIVE:
if (doInsert) {
/* INSERT */
if (objc != 5) {
Tcl_WrongNumArgs(interp, 3, objv, "index string");
return TCL_ERROR;
}
if (TableGetIcursorObj(tablePtr, objv[3], &first) != TCL_OK) {
return TCL_ERROR;
} else if ((tablePtr->flags & HAS_ACTIVE) &&
!(tablePtr->flags & ACTIVE_DISABLED) &&
tablePtr->state == STATE_NORMAL) {
TableInsertChars(tablePtr, first, Tcl_GetString(objv[4]));
}
} else {
/* DELETE */
if (objc > 5) {
Tcl_WrongNumArgs(interp, 3, objv, "first ?last?");
return TCL_ERROR;
}
if (TableGetIcursorObj(tablePtr, objv[3], &first) != TCL_OK) {
return TCL_ERROR;
}
if (objc == 4) {
last = first+1;
} else if (TableGetIcursorObj(tablePtr, objv[4],
&last) != TCL_OK) {
return TCL_ERROR;
}
if ((last >= first) && (tablePtr->flags & HAS_ACTIVE) &&
!(tablePtr->flags & ACTIVE_DISABLED) &&
tablePtr->state == STATE_NORMAL) {
TableDeleteChars(tablePtr, first, last-first);
}
}
break; /* EDIT ACTIVE */
case MOD_COLS:
case MOD_ROWS: {
/*
* ROW/COL INSERTION/DELETION
* FIX: This doesn't handle spans
*/
int i, lo, hi, argsLeft, offset, minkeyoff, doRows;
int maxrow, maxcol, maxkey, minkey, flags, count, *dimPtr;
Tcl_HashTable *tagTblPtr, *dimTblPtr;
Tcl_HashSearch search;
doRows = (cmdIndex == MOD_ROWS);
flags = 0;
for (i = 3; i < objc; i++) {
if (*(Tcl_GetString(objv[i])) != '-') {
break;
}
if (Tcl_GetIndexFromObj(interp, objv[i], rcCmdNames,
"switch", 0, &cmdIndex) != TCL_OK) {
return TCL_ERROR;
}
if (cmdIndex == OPT_LAST) {
i++;
break;
}
switch (cmdIndex) {
case OPT_TITLES:
flags |= HOLD_TITLES;
break;
case OPT_DIMS:
flags |= HOLD_DIMS;
break;
case OPT_SEL:
flags |= HOLD_SEL;
break;
case OPT_TAGS:
flags |= HOLD_TAGS;
break;
case OPT_WINS:
flags |= HOLD_WINS;
break;
}
}
argsLeft = objc - i;
if (argsLeft < 1 || argsLeft > 2) {
Tcl_WrongNumArgs(interp, 3, objv, "?switches? index ?count?");
return TCL_ERROR;
}
count = 1;
maxcol = tablePtr->cols-1+tablePtr->colOffset;
maxrow = tablePtr->rows-1+tablePtr->rowOffset;
if (strcmp(Tcl_GetString(objv[i]), "end") == 0) {
/* allow "end" to be specified as an index */
first = (doRows) ? maxrow : maxcol;
} else if (Tcl_GetIntFromObj(interp, objv[i], &first) != TCL_OK) {
return TCL_ERROR;
}
if (argsLeft == 2 &&
Tcl_GetIntFromObj(interp, objv[++i], &count) != TCL_OK) {
return TCL_ERROR;
}
if (count == 0 || (tablePtr->state == STATE_DISABLED)) {
return TCL_OK;
}
if (doRows) {
maxkey = maxrow;
minkey = tablePtr->rowOffset;
minkeyoff = tablePtr->rowOffset+tablePtr->titleRows;
offset = tablePtr->rowOffset;
tagTblPtr = tablePtr->rowStyles;
dimTblPtr = tablePtr->rowHeights;
dimPtr = &(tablePtr->rows);
lo = tablePtr->colOffset
+ ((flags & HOLD_TITLES) ? tablePtr->titleCols : 0);
hi = maxcol;
} else {
maxkey = maxcol;
minkey = tablePtr->colOffset;
minkeyoff = tablePtr->colOffset+tablePtr->titleCols;
offset = tablePtr->colOffset;
tagTblPtr = tablePtr->colStyles;
dimTblPtr = tablePtr->colWidths;
dimPtr = &(tablePtr->cols);
lo = tablePtr->rowOffset
+ ((flags & HOLD_TITLES) ? tablePtr->titleRows : 0);
hi = maxrow;
}
/* constrain the starting index */
if (first > maxkey) {
first = maxkey;
} else if (first < minkey) {
first = minkey;
}
if (doInsert) {
/* +count means insert after index,
* -count means insert before index */
if (count < 0) {
count = -count;
} else {
first++;
}
if ((flags & HOLD_TITLES) && (first < minkeyoff)) {
count -= minkeyoff-first;
if (count <= 0) {
return TCL_OK;
}
first = minkeyoff;
}
if (!(flags & HOLD_DIMS)) {
maxkey += count;
*dimPtr += count;
}
/*
* We need to call TableAdjustParams before TableModifyRC to
* ensure that side effect code like var traces that might get
* called will access the correct new dimensions.
*/
if (*dimPtr < 1) {
*dimPtr = 1;
}
TableAdjustParams(tablePtr);
for (i = maxkey; i >= first; i--) {
/* move row/col style && width/height here */
TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr,
offset, i, i-count, lo, hi, ((i-count) < first));
}
if (!(flags & HOLD_WINS)) {
/*
* This may be a little severe, but it does unmap the
* windows that need to be unmapped, and those that should
* stay do remap correctly. [Bug #551325]
*/
if (doRows) {
EmbWinUnmap(tablePtr,
first - tablePtr->rowOffset,
maxkey - tablePtr->rowOffset,
lo - tablePtr->colOffset,
hi - tablePtr->colOffset);
} else {
EmbWinUnmap(tablePtr,
lo - tablePtr->rowOffset,
hi - tablePtr->rowOffset,
first - tablePtr->colOffset,
maxkey - tablePtr->colOffset);
}
}
} else {
/* (index = i && count = 1) == (index = i && count = -1) */
if (count < 0) {
/* if the count is negative, make sure that the col count will
* delete no greater than the original index */
if (first+count < minkey) {
if (first-minkey < abs(count)) {
/*
* In this case, the user is asking to delete more rows
* than exist before the minkey, so we have to shrink
* the count down to the existing rows up to index.
*/
count = first-minkey;
} else {
count += first-minkey;
}
first = minkey;
} else {
first += count;
count = -count;
}
}
if ((flags & HOLD_TITLES) && (first <= minkeyoff)) {
count -= minkeyoff-first;
if (count <= 0) {
return TCL_OK;
}
first = minkeyoff;
}
if (count > maxkey-first+1) {
count = maxkey-first+1;
}
if (!(flags & HOLD_DIMS)) {
*dimPtr -= count;
}
/*
* We need to call TableAdjustParams before TableModifyRC to
* ensure that side effect code like var traces that might get
* called will access the correct new dimensions.
*/
if (*dimPtr < 1) {
*dimPtr = 1;
}
TableAdjustParams(tablePtr);
for (i = first; i <= maxkey; i++) {
TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr,
offset, i, i+count, lo, hi, ((i+count) > maxkey));
}
}
if (!(flags & HOLD_SEL) &&
Tcl_FirstHashEntry(tablePtr->selCells, &search) != NULL) {
/* clear selection - forceful, but effective */
Tcl_DeleteHashTable(tablePtr->selCells);
Tcl_InitHashTable(tablePtr->selCells, TCL_STRING_KEYS);
}
/*
* Make sure that the modified dimension is actually legal
* after removing all that stuff.
*/
if (*dimPtr < 1) {
*dimPtr = 1;
TableAdjustParams(tablePtr);
}
/* change the geometry */
TableGeometryRequest(tablePtr);
/* FIX:
* This has to handle when the previous rows/cols resize because
* of the *stretchmode. InvalidateAll does that, but could be
* more efficient.
*/
TableInvalidateAll(tablePtr, 0);
break;
}
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TableDeleteChars --
* Remove one or more characters from an table widget.
*
* Results:
* None.
*
* Side effects:
* Memory gets freed, the table gets modified and (eventually)
* redisplayed.
*
*----------------------------------------------------------------------
*/
void
TableDeleteChars(tablePtr, index, count)
register Table *tablePtr; /* Table widget to modify. */
int index; /* Index of first character to delete. */
int count; /* How many characters to delete. */
{
#ifdef TCL_UTF_MAX
int byteIndex, byteCount, newByteCount, numBytes, numChars;
char *new, *string;
string = tablePtr->activeBuf;
numBytes = strlen(string);
numChars = Tcl_NumUtfChars(string, numBytes);
if ((index + count) > numChars) {
count = numChars - index;
}
if (count <= 0) {
return;
}
byteIndex = Tcl_UtfAtIndex(string, index) - string;
byteCount = Tcl_UtfAtIndex(string + byteIndex, count)
- (string + byteIndex);
newByteCount = numBytes + 1 - byteCount;
new = (char *) ckalloc((unsigned) newByteCount);
memcpy(new, string, (size_t) byteIndex);
strcpy(new + byteIndex, string + byteIndex + byteCount);
#else
int oldlen;
char *new;
/* this gets the length of the string, as well as ensuring that
* the cursor isn't beyond the end char */
TableGetIcursor(tablePtr, "end", &oldlen);
if ((index+count) > oldlen)
count = oldlen-index;
if (count <= 0)
return;
new = (char *) ckalloc((unsigned)(oldlen-count+1));
strncpy(new, tablePtr->activeBuf, (size_t) index);
strcpy(new+index, tablePtr->activeBuf+index+count);
/* make sure this string is null terminated */
new[oldlen-count] = '\0';
#endif
/* This prevents deletes on BREAK or validation error. */
if (tablePtr->validate &&
TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
tablePtr->activeCol+tablePtr->colOffset,
tablePtr->activeBuf, new, index) != TCL_OK) {
ckfree(new);
return;
}
ckfree(tablePtr->activeBuf);
tablePtr->activeBuf = new;
/* mark the text as changed */
tablePtr->flags |= TEXT_CHANGED;
if (tablePtr->icursor >= index) {
if (tablePtr->icursor >= (index+count)) {
tablePtr->icursor -= count;
} else {
tablePtr->icursor = index;
}
}
TableSetActiveIndex(tablePtr);
TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL);
}
/*
*----------------------------------------------------------------------
*
* TableInsertChars --
* Add new characters to the active cell of a table widget.
*
* Results:
* None.
*
* Side effects:
* New information gets added to tablePtr; it will be redisplayed
* soon, but not necessarily immediately.
*
*----------------------------------------------------------------------
*/
void
TableInsertChars(tablePtr, index, value)
register Table *tablePtr; /* Table that is to get the new elements. */
int index; /* Add the new elements before this element. */
char *value; /* New characters to add (NULL-terminated
* string). */
{
#ifdef TCL_UTF_MAX
int oldlen, byteIndex, byteCount;
char *new, *string;
byteCount = strlen(value);
if (byteCount == 0) {
return;
}
/* Is this an autoclear and this is the first update */
/* Note that this clears without validating */
if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) {
/* set the buffer to be empty */
tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1);
tablePtr->activeBuf[0] = '\0';
/* the insert position now has to be 0 */
index = 0;
tablePtr->icursor = 0;
}
string = tablePtr->activeBuf;
byteIndex = Tcl_UtfAtIndex(string, index) - string;
oldlen = strlen(string);
new = (char *) ckalloc((unsigned)(oldlen + byteCount + 1));
memcpy(new, string, (size_t) byteIndex);
strcpy(new + byteIndex, value);
strcpy(new + byteIndex + byteCount, string + byteIndex);
/* validate potential new active buffer */
/* This prevents inserts on either BREAK or validation error. */
if (tablePtr->validate &&
TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
tablePtr->activeCol+tablePtr->colOffset,
tablePtr->activeBuf, new, byteIndex) != TCL_OK) {
ckfree(new);
return;
}
/*
* The following construction is used because inserting improperly
* formed UTF-8 sequences between other improperly formed UTF-8
* sequences could result in actually forming valid UTF-8 sequences;
* the number of characters added may not be Tcl_NumUtfChars(string, -1),
* because of context. The actual number of characters added is how
* many characters were are in the string now minus the number that
* used to be there.
*/
if (tablePtr->icursor >= index) {
tablePtr->icursor += Tcl_NumUtfChars(new, oldlen+byteCount)
- Tcl_NumUtfChars(tablePtr->activeBuf, oldlen);
}
ckfree(string);
tablePtr->activeBuf = new;
#else
int oldlen, newlen;
char *new;
newlen = strlen(value);
if (newlen == 0) return;
/* Is this an autoclear and this is the first update */
/* Note that this clears without validating */
if (tablePtr->autoClear && !(tablePtr->flags & TEXT_CHANGED)) {
/* set the buffer to be empty */
tablePtr->activeBuf = (char *)ckrealloc(tablePtr->activeBuf, 1);
tablePtr->activeBuf[0] = '\0';
/* the insert position now has to be 0 */
index = 0;
}
oldlen = strlen(tablePtr->activeBuf);
/* get the buffer to at least the right length */
new = (char *) ckalloc((unsigned)(oldlen+newlen+1));
strncpy(new, tablePtr->activeBuf, (size_t) index);
strcpy(new+index, value);
strcpy(new+index+newlen, (tablePtr->activeBuf)+index);
/* make sure this string is null terminated */
new[oldlen+newlen] = '\0';
/* validate potential new active buffer */
/* This prevents inserts on either BREAK or validation error. */
if (tablePtr->validate &&
TableValidateChange(tablePtr, tablePtr->activeRow+tablePtr->rowOffset,
tablePtr->activeCol+tablePtr->colOffset,
tablePtr->activeBuf, new, index) != TCL_OK) {
ckfree(new);
return;
}
ckfree(tablePtr->activeBuf);
tablePtr->activeBuf = new;
if (tablePtr->icursor >= index) {
tablePtr->icursor += newlen;
}
#endif
/* mark the text as changed */
tablePtr->flags |= TEXT_CHANGED;
TableSetActiveIndex(tablePtr);
TableRefresh(tablePtr, tablePtr->activeRow, tablePtr->activeCol, CELL);
}
/*
*----------------------------------------------------------------------
*
* TableModifyRC --
* Helper function that does the core work of moving rows/cols
* and associated tags.
*
* Results:
* None.
*
* Side effects:
* Moves cell data and possibly tag data
*
*----------------------------------------------------------------------
*/
static void
TableModifyRC(tablePtr, doRows, flags, tagTblPtr, dimTblPtr,
offset, from, to, lo, hi, outOfBounds)
Table *tablePtr; /* Information about text widget. */
int doRows; /* rows (1) or cols (0) */
int flags; /* flags indicating what to move */
Tcl_HashTable *tagTblPtr, *dimTblPtr; /* Pointers to the row/col tags
* and width/height tags */
int offset; /* appropriate offset */
int from, to; /* the from and to row/col */
int lo, hi; /* the lo and hi col/row */
int outOfBounds; /* the boundary check for shifting items */
{
int j, new;
char buf[INDEX_BUFSIZE], buf1[INDEX_BUFSIZE];
Tcl_HashEntry *entryPtr, *newPtr;
TableEmbWindow *ewPtr;
/*
* move row/col style && width/height here
* If -holdtags is specified, we don't move the user-set widths/heights
* of the absolute rows/columns, otherwise we enter here to move the
* dimensions appropriately
*/
if (!(flags & HOLD_TAGS)) {
entryPtr = Tcl_FindHashEntry(tagTblPtr, (char *)from);
if (entryPtr != NULL) {
Tcl_DeleteHashEntry(entryPtr);
}
entryPtr = Tcl_FindHashEntry(dimTblPtr, (char *)from-offset);
if (entryPtr != NULL) {
Tcl_DeleteHashEntry(entryPtr);
}
if (!outOfBounds) {
entryPtr = Tcl_FindHashEntry(tagTblPtr, (char *)to);
if (entryPtr != NULL) {
newPtr = Tcl_CreateHashEntry(tagTblPtr, (char *)from, &new);
Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
Tcl_DeleteHashEntry(entryPtr);
}
entryPtr = Tcl_FindHashEntry(dimTblPtr, (char *)to-offset);
if (entryPtr != NULL) {
newPtr = Tcl_CreateHashEntry(dimTblPtr, (char *)from-offset,
&new);
Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
Tcl_DeleteHashEntry(entryPtr);
}
}
}
for (j = lo; j <= hi; j++) {
if (doRows /* rows */) {
TableMakeArrayIndex(from, j, buf);
TableMakeArrayIndex(to, j, buf1);
TableMoveCellValue(tablePtr, to, j, buf1, from, j, buf,
outOfBounds);
} else {
TableMakeArrayIndex(j, from, buf);
TableMakeArrayIndex(j, to, buf1);
TableMoveCellValue(tablePtr, j, to, buf1, j, from, buf,
outOfBounds);
}
/*
* If -holdselection is specified, we leave the selected cells in the
* absolute cell values, otherwise we enter here to move the
* selection appropriately
*/
if (!(flags & HOLD_SEL)) {
entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf);
if (entryPtr != NULL) {
Tcl_DeleteHashEntry(entryPtr);
}
if (!outOfBounds) {
entryPtr = Tcl_FindHashEntry(tablePtr->selCells, buf1);
if (entryPtr != NULL) {
Tcl_CreateHashEntry(tablePtr->selCells, buf, &new);
Tcl_DeleteHashEntry(entryPtr);
}
}
}
/*
* If -holdtags is specified, we leave the tags in the
* absolute cell values, otherwise we enter here to move the
* tags appropriately
*/
if (!(flags & HOLD_TAGS)) {
entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf);
if (entryPtr != NULL) {
Tcl_DeleteHashEntry(entryPtr);
}
if (!outOfBounds) {
entryPtr = Tcl_FindHashEntry(tablePtr->cellStyles, buf1);
if (entryPtr != NULL) {
newPtr = Tcl_CreateHashEntry(tablePtr->cellStyles, buf,
&new);
Tcl_SetHashValue(newPtr, Tcl_GetHashValue(entryPtr));
Tcl_DeleteHashEntry(entryPtr);
}
}
}
/*
* If -holdwindows is specified, we leave the windows in the
* absolute cell values, otherwise we enter here to move the
* windows appropriately
*/
if (!(flags & HOLD_WINS)) {
/*
* Delete whatever window might be in our destination
*/
Table_WinDelete(tablePtr, buf);
if (!outOfBounds) {
/*
* buf1 is where the window is
* buf is where we want it to be
*
* This is an adaptation of Table_WinMove, which we can't
* use because we are intermediately fiddling with boundaries
*/
entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf1);
if (entryPtr != NULL) {
/*
* If there was a window in our source,
* get the window pointer to move it
*/
ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
/* and free the old hash table entry */
Tcl_DeleteHashEntry(entryPtr);
entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, buf,
&new);
/*
* We needn't check if a window was in buf, since the
* Table_WinDelete above should guarantee that no window
* is there. Just set the new entry's value.
*/
Tcl_SetHashValue(entryPtr, (ClientData) ewPtr);
ewPtr->hPtr = entryPtr;
}
}
}
}
}

View File

@@ -0,0 +1,90 @@
/*
* tkTableInitScript.h --
*
* This file contains common init script for tkTable
*
* Copyright (c) 1998 Jeffrey Hobbs
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
/*
* The following string is the startup script executed when the table is
* loaded. It looks on disk in several different directories for a script
* "TBL_RUNTIME" (as defined in Makefile) that is compatible with this
* version of tkTable. The sourced script has all key bindings defined.
*/
static char tkTableInitScript[] = "if {[info proc tkTableInit]==\"\"} {\n\
proc tkTableInit {} {\n\
global tk_library tcl_pkgPath errorInfo env\n\
rename tkTableInit {}\n\
set errors {}\n\
if {![info exists env(TK_TABLE_LIBRARY_FILE)]} {\n\
set env(TK_TABLE_LIBRARY_FILE) " TBL_RUNTIME "\n\
}\n\
if {[info exists env(TK_TABLE_LIBRARY)]} {\n\
lappend dirs $env(TK_TABLE_LIBRARY)\n\
}\n\
lappend dirs " TBL_RUNTIME_DIR "\n\
if {[info exists tcl_pkgPath]} {\n\
foreach i $tcl_pkgPath {\n\
lappend dirs [file join $i Tktable" PACKAGE_VERSION "] \\\n\
[file join $i Tktable] $i\n\
}\n\
}\n\
lappend dirs $tk_library [pwd]\n\
foreach i $dirs {\n\
set try [file join $i $env(TK_TABLE_LIBRARY_FILE)]\n\
if {[file exists $try]} {\n\
if {![catch {uplevel #0 [list source $try]} msg]} {\n\
set env(TK_TABLE_LIBRARY) $i\n\
return\n\
} else {\n\
append errors \"$try: $msg\n$errorInfo\n\"\n\
}\n\
}\n\
}\n"
#ifdef NO_EMBEDDED_RUNTIME
" set msg \"Can't find a $env(TK_TABLE_LIBRARY_FILE) in the following directories: \n\"\n\
append msg \" $dirs\n\n$errors\n\n\"\n\
append msg \"This probably means that TkTable wasn't installed properly.\"\n\
return -code error $msg\n"
#else
" set env(TK_TABLE_LIBRARY) EMBEDDED_RUNTIME\n"
# ifdef MAC_TCL
" source -rsrc tkTable"
# else
" uplevel #0 {"
# include "tkTable.tcl.h"
" }"
# endif
#endif
" }\n\
}\n\
tkTableInit";
/*
* The init script can't make certain calls in a safe interpreter,
* so we always have to use the embedded runtime for it
*/
static char tkTableSafeInitScript[] = "if {[info proc tkTableInit]==\"\"} {\n\
proc tkTableInit {} {\n\
set env(TK_TABLE_LIBRARY) EMBEDDED_RUNTIME\n"
#ifdef NO_EMBEDDED_RUNTIME
" append msg \"tkTable requires embedded runtime to be compiled for\"\n\
append msg \" use in safe interpreters\"\n\
return -code error $msg\n"
#endif
# ifdef MAC_TCL
" source -rsrc tkTable"
# else
" uplevel #0 {"
# include "tkTable.tcl.h"
" }"
# endif
" }\n\
}\n\
tkTableInit";

1299
tktable/generic/tkTablePs.c Normal file

File diff suppressed because it is too large Load Diff

1354
tktable/generic/tkTableTag.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,372 @@
/*
* tkTableUtil.c --
*
* This module contains utility functions for table widgets.
*
* Copyright (c) 2000-2002 Jeffrey Hobbs
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tkTableUtil.c,v 1.4 2002/10/16 07:31:48 hobbs Exp $
*/
#include "tkTable.h"
static char * Cmd_GetName _ANSI_ARGS_((const Cmd_Struct *cmds, int val));
static int Cmd_GetValue _ANSI_ARGS_((const Cmd_Struct *cmds,
const char *arg));
static void Cmd_GetError _ANSI_ARGS_((Tcl_Interp *interp,
const Cmd_Struct *cmds, const char *arg));
/*
*--------------------------------------------------------------
*
* Table_ClearHashTable --
* This procedure is invoked to clear a STRING_KEY hash table,
* freeing the string entries and then deleting the hash table.
* The hash table cannot be used after calling this, except to
* be freed or reinitialized.
*
* Results:
* Cached info will be lost.
*
* Side effects:
* Can cause redraw.
* See the user documentation.
*
*--------------------------------------------------------------
*/
void
Table_ClearHashTable(Tcl_HashTable *hashTblPtr)
{
Tcl_HashEntry *entryPtr;
Tcl_HashSearch search;
char *value;
for (entryPtr = Tcl_FirstHashEntry(hashTblPtr, &search);
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
value = (char *) Tcl_GetHashValue(entryPtr);
if (value != NULL) ckfree(value);
}
Tcl_DeleteHashTable(hashTblPtr);
}
/*
*----------------------------------------------------------------------
*
* TableOptionBdSet --
*
* This routine configures the borderwidth value for a tag.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* It may adjust the tag struct values of bd[0..4] and borders.
*
*----------------------------------------------------------------------
*/
int
TableOptionBdSet(clientData, interp, tkwin, value, widgRec, offset)
ClientData clientData; /* Type of struct being set. */
Tcl_Interp *interp; /* Used for reporting errors. */
Tk_Window tkwin; /* Window containing table widget. */
CONST84 char *value; /* Value of option. */
char *widgRec; /* Pointer to record for item. */
int offset; /* Offset into item. */
{
char **borderStr;
int *bordersPtr, *bdPtr;
int type = (int) clientData;
int result = TCL_OK;
int argc;
CONST84 char **argv;
if ((type == BD_TABLE) && (value[0] == '\0')) {
/*
* NULL strings aren't allowed for the table global -bd
*/
Tcl_AppendResult(interp, "borderwidth value may not be empty",
(char *) NULL);
return TCL_ERROR;
}
if ((type == BD_TABLE) || (type == BD_TABLE_TAG)) {
TableTag *tagPtr = (TableTag *) (widgRec + offset);
borderStr = &(tagPtr->borderStr);
bordersPtr = &(tagPtr->borders);
bdPtr = tagPtr->bd;
} else if (type == BD_TABLE_WIN) {
TableEmbWindow *tagPtr = (TableEmbWindow *) widgRec;
borderStr = &(tagPtr->borderStr);
bordersPtr = &(tagPtr->borders);
bdPtr = tagPtr->bd;
} else {
panic("invalid type given to TableOptionBdSet\n");
return TCL_ERROR; /* lint */
}
result = Tcl_SplitList(interp, value, &argc, &argv);
if (result == TCL_OK) {
int i, bd[4];
if (((type == BD_TABLE) && (argc == 0)) || (argc == 3) || (argc > 4)) {
Tcl_AppendResult(interp,
"1, 2 or 4 values must be specified for borderwidth",
(char *) NULL);
result = TCL_ERROR;
} else {
/*
* We use the shadow bd array first, in case we have an error
* parsing arguments half way through.
*/
for (i = 0; i < argc; i++) {
if (Tk_GetPixels(interp, tkwin, argv[i], &(bd[i])) != TCL_OK) {
result = TCL_ERROR;
break;
}
}
/*
* If everything is OK, store the parsed and given values for
* easy retrieval.
*/
if (result == TCL_OK) {
for (i = 0; i < argc; i++) {
bdPtr[i] = MAX(0, bd[i]);
}
if (*borderStr) {
ckfree(*borderStr);
}
if (value) {
*borderStr = (char *) ckalloc(strlen(value) + 1);
strcpy(*borderStr, value);
} else {
*borderStr = NULL;
}
*bordersPtr = argc;
}
}
ckfree ((char *) argv);
}
return result;
}
/*
*----------------------------------------------------------------------
*
* TableOptionBdGet --
*
* Results:
* Value of the -bd option.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
char *
TableOptionBdGet(clientData, tkwin, widgRec, offset, freeProcPtr)
ClientData clientData; /* Type of struct being set. */
Tk_Window tkwin; /* Window containing canvas widget. */
char *widgRec; /* Pointer to record for item. */
int offset; /* Offset into item. */
Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with
* information about how to reclaim
* storage for return string. */
{
register int type = (int) clientData;
if (type == BD_TABLE) {
return ((TableTag *) (widgRec + offset))->borderStr;
} else if (type == BD_TABLE_TAG) {
return ((TableTag *) widgRec)->borderStr;
} else if (type == BD_TABLE_WIN) {
return ((TableEmbWindow *) widgRec)->borderStr;
} else {
panic("invalid type given to TableOptionBdSet\n");
return NULL; /* lint */
}
}
/*
*----------------------------------------------------------------------
*
* TableTagConfigureBd --
* This routine configures the border values based on a tag.
* The previous value of the bd string (oldValue) is assumed to
* be a valid value for this tag.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* It may adjust the value used by -bd.
*
*----------------------------------------------------------------------
*/
int
TableTagConfigureBd(Table *tablePtr, TableTag *tagPtr,
char *oldValue, int nullOK)
{
int i, argc, result = TCL_OK;
CONST84 char **argv;
/*
* First check to see if the value really changed.
*/
if (strcmp(tagPtr->borderStr ? tagPtr->borderStr : "",
oldValue ? oldValue : "") == 0) {
return TCL_OK;
}
tagPtr->borders = 0;
if (!nullOK && ((tagPtr->borderStr == NULL)
|| (*(tagPtr->borderStr) == '\0'))) {
/*
* NULL strings aren't allowed for this tag
*/
result = TCL_ERROR;
} else if (tagPtr->borderStr) {
result = Tcl_SplitList(tablePtr->interp, tagPtr->borderStr,
&argc, &argv);
if (result == TCL_OK) {
if ((!nullOK && (argc == 0)) || (argc == 3) || (argc > 4)) {
Tcl_SetResult(tablePtr->interp,
"1, 2 or 4 values must be specified to -borderwidth",
TCL_STATIC);
result = TCL_ERROR;
} else {
for (i = 0; i < argc; i++) {
if (Tk_GetPixels(tablePtr->interp, tablePtr->tkwin,
argv[i], &(tagPtr->bd[i])) != TCL_OK) {
result = TCL_ERROR;
break;
}
tagPtr->bd[i] = MAX(0, tagPtr->bd[i]);
}
tagPtr->borders = argc;
}
ckfree ((char *) argv);
}
}
if (result != TCL_OK) {
if (tagPtr->borderStr) {
ckfree ((char *) tagPtr->borderStr);
}
if (oldValue != NULL) {
size_t length = strlen(oldValue) + 1;
/*
* We are making the assumption that oldValue is correct.
* We have to reparse in case the bad new value had a couple
* of correct args before failing on a bad pixel value.
*/
Tcl_SplitList(tablePtr->interp, oldValue, &argc, &argv);
for (i = 0; i < argc; i++) {
Tk_GetPixels(tablePtr->interp, tablePtr->tkwin,
argv[i], &(tagPtr->bd[i]));
}
ckfree ((char *) argv);
tagPtr->borders = argc;
tagPtr->borderStr = (char *) ckalloc(length);
memcpy(tagPtr->borderStr, oldValue, length);
} else {
tagPtr->borders = 0;
tagPtr->borderStr = (char *) NULL;
}
}
return result;
}
/*
*----------------------------------------------------------------------
*
* Cmd_OptionSet --
*
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Cmd_OptionSet(ClientData clientData, Tcl_Interp *interp,
Tk_Window unused, CONST84 char *value, char *widgRec, int offset)
{
Cmd_Struct *p = (Cmd_Struct *)clientData;
int mode = Cmd_GetValue(p,value);
if (!mode) {
Cmd_GetError(interp,p,value);
return TCL_ERROR;
}
*((int*)(widgRec+offset)) = mode;
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Cmd_OptionGet --
*
*
* Results:
* Value of the option.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
char *
Cmd_OptionGet(ClientData clientData, Tk_Window unused,
char *widgRec, int offset, Tcl_FreeProc **freeProcPtr)
{
Cmd_Struct *p = (Cmd_Struct *)clientData;
int mode = *((int*)(widgRec+offset));
return Cmd_GetName(p,mode);
}
/*
* simple Cmd_Struct lookup functions
*/
char *
Cmd_GetName(const Cmd_Struct *cmds, int val)
{
for(;cmds->name && cmds->name[0];cmds++) {
if (cmds->value==val) return cmds->name;
}
return NULL;
}
int
Cmd_GetValue(const Cmd_Struct *cmds, const char *arg)
{
unsigned int len = strlen(arg);
for(;cmds->name && cmds->name[0];cmds++) {
if (!strncmp(cmds->name, arg, len)) return cmds->value;
}
return 0;
}
void
Cmd_GetError(Tcl_Interp *interp, const Cmd_Struct *cmds, const char *arg)
{
int i;
Tcl_AppendResult(interp, "bad option \"", arg, "\" must be ", (char *) 0);
for(i=0;cmds->name && cmds->name[0];cmds++,i++) {
Tcl_AppendResult(interp, (i?", ":""), cmds->name, (char *) 0);
}
}

View File

@@ -0,0 +1,955 @@
/*
* tkTableWin.c --
*
* This module implements embedded windows for table widgets.
* Much of this code is adapted from tkGrid.c and tkTextWind.c.
*
* Copyright (c) 1998-2002 Jeffrey Hobbs
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* RCS: @(#) $Id: tkTableWin.c,v 1.6 2004/06/11 00:24:44 hobbs Exp $
*/
#include "tkTable.h"
static int StickyParseProc _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, Tk_Window tkwin,
CONST84 char *value, char *widgRec, int offset));
static char * StickyPrintProc _ANSI_ARGS_((ClientData clientData,
Tk_Window tkwin, char *widgRec, int offset,
Tcl_FreeProc **freeProcPtr));
static void EmbWinLostSlaveProc _ANSI_ARGS_((ClientData clientData,
Tk_Window tkwin));
static void EmbWinRequestProc _ANSI_ARGS_((ClientData clientData,
Tk_Window tkwin));
static void EmbWinCleanup _ANSI_ARGS_((Table *tablePtr,
TableEmbWindow *ewPtr));
static int EmbWinConfigure _ANSI_ARGS_((Table *tablePtr,
TableEmbWindow *ewPtr,
int objc, Tcl_Obj *CONST objv[]));
static void EmbWinStructureProc _ANSI_ARGS_((ClientData clientData,
XEvent *eventPtr));
static void EmbWinUnmapNow _ANSI_ARGS_((Tk_Window ewTkwin,
Tk_Window tkwin));
static Tk_GeomMgr tableGeomType = {
"table", /* name */
EmbWinRequestProc, /* requestProc */
EmbWinLostSlaveProc, /* lostSlaveProc */
};
/* windows subcommands */
static CONST84 char *winCmdNames[] = {
"cget", "configure", "delete", "move", "names", (char *) NULL
};
enum winCommand {
WIN_CGET, WIN_CONFIGURE, WIN_DELETE, WIN_MOVE, WIN_NAMES
};
/* Flag values for "sticky"ness The 16 combinations subsume the packer's
* notion of anchor and fill.
*
* STICK_NORTH This window sticks to the top of its cavity.
* STICK_EAST This window sticks to the right edge of its cavity.
* STICK_SOUTH This window sticks to the bottom of its cavity.
* STICK_WEST This window sticks to the left edge of its cavity.
*/
#define STICK_NORTH (1<<0)
#define STICK_EAST (1<<1)
#define STICK_SOUTH (1<<2)
#define STICK_WEST (1<<3)
/*
* The default specification for configuring embedded windows
* Done like this to make the command line parsing easy
*/
static Tk_CustomOption stickyOption = { StickyParseProc, StickyPrintProc,
(ClientData) NULL };
static Tk_CustomOption tagBdOpt = { TableOptionBdSet, TableOptionBdGet,
(ClientData) BD_TABLE_WIN };
static Tk_ConfigSpec winConfigSpecs[] = {
{TK_CONFIG_BORDER, "-background", "background", "Background", NULL,
Tk_Offset(TableEmbWindow, bg),
TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
{TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0},
{TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0},
{TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", "",
0 /* no offset */,
TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK, &tagBdOpt },
{TK_CONFIG_STRING, "-create", (char *)NULL, (char *)NULL, (char *)NULL,
Tk_Offset(TableEmbWindow, create),
TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
{TK_CONFIG_PIXELS, "-padx", (char *)NULL, (char *)NULL, (char *)NULL,
Tk_Offset(TableEmbWindow, padX), TK_CONFIG_DONT_SET_DEFAULT },
{TK_CONFIG_PIXELS, "-pady", (char *)NULL, (char *)NULL, (char *)NULL,
Tk_Offset(TableEmbWindow, padY), TK_CONFIG_DONT_SET_DEFAULT },
{TK_CONFIG_CUSTOM, "-sticky", (char *)NULL, (char *)NULL, (char *)NULL,
Tk_Offset(TableEmbWindow, sticky), TK_CONFIG_DONT_SET_DEFAULT,
&stickyOption},
{TK_CONFIG_RELIEF, "-relief", "relief", "Relief", NULL,
Tk_Offset(TableEmbWindow, relief), 0 },
{TK_CONFIG_WINDOW, "-window", (char *)NULL, (char *)NULL, (char *)NULL,
Tk_Offset(TableEmbWindow, tkwin),
TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
{TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
(char *)NULL, 0, 0 }
};
/*
*----------------------------------------------------------------------
*
* StickyPrintProc --
* Converts the internal boolean combination of "sticky" bits onto
* a TCL string element containing zero or more of n, s, e, or w.
*
* Results:
* A string is placed into the "result" pointer.
*
* Side effects:
* none.
*
*----------------------------------------------------------------------
*/
static char *
StickyPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
ClientData clientData; /* Ignored. */
Tk_Window tkwin; /* Window for text widget. */
char *widgRec; /* Pointer to TkTextEmbWindow
* structure. */
int offset; /* Ignored. */
Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with
* information about how to reclaim
* storage for return string. */
{
int flags = ((TableEmbWindow *) widgRec)->sticky;
int count = 0;
char *result = (char *) ckalloc(5*sizeof(char));
if (flags&STICK_NORTH) result[count++] = 'n';
if (flags&STICK_EAST) result[count++] = 'e';
if (flags&STICK_SOUTH) result[count++] = 's';
if (flags&STICK_WEST) result[count++] = 'w';
*freeProcPtr = TCL_DYNAMIC;
result[count] = '\0';
return result;
}
/*
*----------------------------------------------------------------------
*
* StringParseProc --
* Converts an ascii string representing a widgets stickyness
* into the boolean result.
*
* Results:
* The boolean combination of the "sticky" bits is retuned. If an
* error occurs, such as an invalid character, -1 is returned instead.
*
* Side effects:
* none
*
*----------------------------------------------------------------------
*/
static int
StickyParseProc(clientData, interp, tkwin, value, widgRec, offset)
ClientData clientData; /* Not used.*/
Tcl_Interp *interp; /* Used for reporting errors. */
Tk_Window tkwin; /* Window for text widget. */
CONST84 char *value; /* Value of option. */
char *widgRec; /* Pointer to TkTextEmbWindow
* structure. */
int offset; /* Offset into item (ignored). */
{
register TableEmbWindow *ewPtr = (TableEmbWindow *) widgRec;
int sticky = 0;
char c;
while ((c = *value++) != '\0') {
switch (c) {
case 'n': case 'N': sticky |= STICK_NORTH; break;
case 'e': case 'E': sticky |= STICK_EAST; break;
case 's': case 'S': sticky |= STICK_SOUTH; break;
case 'w': case 'W': sticky |= STICK_WEST; break;
case ' ': case ',': case '\t': case '\r': case '\n': break;
default:
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"bad sticky value \"", --value,
"\": must contain n, s, e or w",
(char *) NULL);
return TCL_ERROR;
}
}
ewPtr->sticky = sticky;
return TCL_OK;
}
/*
* ckallocs space for a new embedded window structure and clears the structure
* returns the pointer to the new structure
*/
static TableEmbWindow *
TableNewEmbWindow(Table *tablePtr)
{
TableEmbWindow *ewPtr = (TableEmbWindow *) ckalloc(sizeof(TableEmbWindow));
memset((VOID *) ewPtr, 0, sizeof(TableEmbWindow));
/*
* Set the values that aren't 0/NULL by default
*/
ewPtr->tablePtr = tablePtr;
ewPtr->relief = -1;
ewPtr->padX = -1;
ewPtr->padY = -1;
return ewPtr;
}
/*
*----------------------------------------------------------------------
*
* EmbWinCleanup --
* Releases resources used by an embedded window before it is freed up.
*
* Results:
* Window will no longer be valid.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
EmbWinCleanup(Table *tablePtr, TableEmbWindow *ewPtr)
{
Tk_FreeOptions(winConfigSpecs, (char *) ewPtr, tablePtr->display, 0);
}
/*
*--------------------------------------------------------------
*
* EmbWinDisplay --
*
* This procedure is invoked by TableDisplay for
* mapping windows into cells.
*
* Results:
* Displays or moves window on table screen.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
void
EmbWinDisplay(Table *tablePtr, Drawable window, TableEmbWindow *ewPtr,
TableTag *tagPtr, int x, int y, int width, int height)
{
Tk_Window tkwin = tablePtr->tkwin;
Tk_Window ewTkwin = ewPtr->tkwin;
int diffx=0; /* Cavity width - slave width. */
int diffy=0; /* Cavity hight - slave height. */
int sticky = ewPtr->sticky;
int padx, pady;
if (ewPtr->bg) tagPtr->bg = ewPtr->bg;
if (ewPtr->relief != -1) tagPtr->relief = ewPtr->relief;
if (ewPtr->borders) {
tagPtr->borderStr = ewPtr->borderStr;
tagPtr->borders = ewPtr->borders;
tagPtr->bd[0] = ewPtr->bd[0];
tagPtr->bd[1] = ewPtr->bd[1];
tagPtr->bd[2] = ewPtr->bd[2];
tagPtr->bd[3] = ewPtr->bd[3];
}
padx = (ewPtr->padX < 0) ? tablePtr->padX : ewPtr->padX;
pady = (ewPtr->padY < 0) ? tablePtr->padY : ewPtr->padY;
x += padx;
width -= padx*2;
y += pady;
height -= pady*2;
if (width > Tk_ReqWidth(ewPtr->tkwin)) {
diffx = width - Tk_ReqWidth(ewPtr->tkwin);
width = Tk_ReqWidth(ewPtr->tkwin);
}
if (height > Tk_ReqHeight(ewPtr->tkwin)) {
diffy = height - Tk_ReqHeight(ewPtr->tkwin);
height = Tk_ReqHeight(ewPtr->tkwin);
}
if (sticky&STICK_EAST && sticky&STICK_WEST) {
width += diffx;
}
if (sticky&STICK_NORTH && sticky&STICK_SOUTH) {
height += diffy;
}
if (!(sticky&STICK_WEST)) {
x += (sticky&STICK_EAST) ? diffx : diffx/2;
}
if (!(sticky&STICK_NORTH)) {
y += (sticky&STICK_SOUTH) ? diffy : diffy/2;
}
/*
* If we fall below a specific minimum width/height requirement,
* we just unmap the window
*/
if (width < 2 || height < 2) {
if (ewPtr->displayed) {
EmbWinUnmapNow(ewTkwin, tkwin);
}
return;
}
if (tkwin == Tk_Parent(ewTkwin)) {
if ((x != Tk_X(ewTkwin)) || (y != Tk_Y(ewTkwin))
|| (width != Tk_Width(ewTkwin))
|| (height != Tk_Height(ewTkwin))) {
Tk_MoveResizeWindow(ewTkwin, x, y, width, height);
}
Tk_MapWindow(ewTkwin);
} else {
Tk_MaintainGeometry(ewTkwin, tkwin, x, y, width, height);
}
ewPtr->displayed = 1;
}
/*
*--------------------------------------------------------------
*
* EmbWinUnmapNow --
* Handles unmapping the window depending on parent.
* tkwin should be tablePtr->tkwin.
* ewTkwin should be ewPtr->tkwin.
*
* Results:
* Removes the window.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
static void
EmbWinUnmapNow(Tk_Window ewTkwin, Tk_Window tkwin)
{
if (tkwin != Tk_Parent(ewTkwin)) {
Tk_UnmaintainGeometry(ewTkwin, tkwin);
}
Tk_UnmapWindow(ewTkwin);
}
/*
*--------------------------------------------------------------
*
* EmbWinUnmap --
* This procedure is invoked by TableAdjustParams for
* unmapping windows managed moved offscreen.
* rlo, ... should be in real coords.
*
* Results:
* None.
*
* Side effects:
* Unmaps embedded windows.
*
*--------------------------------------------------------------
*/
void
EmbWinUnmap(Table *tablePtr, int rlo, int rhi, int clo, int chi)
{
register TableEmbWindow *ewPtr;
Tcl_HashEntry *entryPtr;
int row, col, trow, tcol;
char buf[INDEX_BUFSIZE];
/*
* Transform numbers from real to user user coords
*/
rlo += tablePtr->rowOffset;
rhi += tablePtr->rowOffset;
clo += tablePtr->colOffset;
chi += tablePtr->colOffset;
for (row = rlo; row <= rhi; row++) {
for (col = clo; col <= chi; col++) {
TableTrueCell(tablePtr, row, col, &trow, &tcol);
TableMakeArrayIndex(trow, tcol, buf);
entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf);
if (entryPtr != NULL) {
ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
if (ewPtr->displayed) {
ewPtr->displayed = 0;
if (ewPtr->tkwin != NULL && tablePtr->tkwin != NULL) {
EmbWinUnmapNow(ewPtr->tkwin, tablePtr->tkwin);
}
}
}
}
}
}
/*
*--------------------------------------------------------------
*
* EmbWinRequestProc --
* This procedure is invoked by Tk_GeometryRequest for
* windows managed by the Table.
*
* Results:
* None.
*
* Side effects:
* Arranges for tkwin, and all its managed siblings, to
* be re-arranged at the next idle point.
*
*--------------------------------------------------------------
*/
static void
EmbWinRequestProc(clientData, tkwin)
ClientData clientData; /* Table's information about
* window that got new preferred
* geometry. */
Tk_Window tkwin; /* Other Tk-related information
* about the window. */
{
register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData;
/*
* Resize depends on the sticky
*/
if (ewPtr->displayed && ewPtr->hPtr != NULL) {
Table *tablePtr = ewPtr->tablePtr;
int row, col, x, y, width, height;
TableParseArrayIndex(&row, &col,
Tcl_GetHashKey(tablePtr->winTable, ewPtr->hPtr));
if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset,
col-tablePtr->colOffset, &x, &y, &width, &height,
0)) {
TableInvalidate(tablePtr, x, y, width, height, 0);
}
}
}
static void
EmbWinRemove(TableEmbWindow *ewPtr)
{
Table *tablePtr = ewPtr->tablePtr;
if (ewPtr->tkwin != NULL) {
Tk_DeleteEventHandler(ewPtr->tkwin, StructureNotifyMask,
EmbWinStructureProc, (ClientData) ewPtr);
ewPtr->tkwin = NULL;
}
ewPtr->displayed = 0;
if (tablePtr->tkwin != NULL) {
int row, col, x, y, width, height;
TableParseArrayIndex(&row, &col,
Tcl_GetHashKey(tablePtr->winTable, ewPtr->hPtr));
/* this will cause windows removed from the table to actually
* cause the associated embdedded window hash data to be removed */
Tcl_DeleteHashEntry(ewPtr->hPtr);
if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset,
col-tablePtr->colOffset, &x, &y, &width, &height,
0))
TableInvalidate(tablePtr, x, y, width, height, 1);
}
/* this will cause windows removed from the table to actually
* cause the associated embdedded window hash data to be removed */
EmbWinCleanup(tablePtr, ewPtr);
ckfree((char *) ewPtr);
}
/*
*--------------------------------------------------------------
*
* EmbWinLostSlaveProc --
* This procedure is invoked by Tk whenever some other geometry
* claims control over a slave that used to be managed by us.
*
* Results:
* None.
*
* Side effects:
* Forgets all table-related information about the slave.
*
*--------------------------------------------------------------
*/
static void
EmbWinLostSlaveProc(clientData, tkwin)
ClientData clientData; /* Table structure for slave window that
* was stolen away. */
Tk_Window tkwin; /* Tk's handle for the slave window. */
{
register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData;
#if 0
Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr);
#endif
EmbWinUnmapNow(tkwin, ewPtr->tablePtr->tkwin);
EmbWinRemove(ewPtr);
}
/*
*--------------------------------------------------------------
*
* EmbWinStructureProc --
* This procedure is invoked by the Tk event loop whenever
* StructureNotify events occur for a window that's embedded
* in a table widget. This procedure's only purpose is to
* clean up when windows are deleted.
*
* Results:
* None.
*
* Side effects:
* The window is disassociated from the window segment, and
* the portion of the table is redisplayed.
*
*--------------------------------------------------------------
*/
static void
EmbWinStructureProc(clientData, eventPtr)
ClientData clientData; /* Pointer to record describing window item. */
XEvent *eventPtr; /* Describes what just happened. */
{
register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData;
if (eventPtr->type != DestroyNotify) {
return;
}
EmbWinRemove(ewPtr);
}
/*
*--------------------------------------------------------------
*
* EmbWinDelete --
* This procedure is invoked by ... whenever
* an embedded window is being deleted.
*
* Results:
* None.
*
* Side effects:
* The embedded window is deleted, if it exists, and any resources
* associated with it are released.
*
*--------------------------------------------------------------
*/
void
EmbWinDelete(register Table *tablePtr, TableEmbWindow *ewPtr)
{
Tcl_HashEntry *entryPtr = ewPtr->hPtr;
if (ewPtr->tkwin != NULL) {
Tk_Window tkwin = ewPtr->tkwin;
/*
* Delete the event handler for the window before destroying
* the window, so that EmbWinStructureProc doesn't get called
* (we'll already do everything that it would have done, and
* it will just get confused).
*/
ewPtr->tkwin = NULL;
Tk_DeleteEventHandler(tkwin, StructureNotifyMask,
EmbWinStructureProc, (ClientData) ewPtr);
Tk_DestroyWindow(tkwin);
}
if (tablePtr->tkwin != NULL && entryPtr != NULL) {
int row, col, x, y, width, height;
TableParseArrayIndex(&row, &col,
Tcl_GetHashKey(tablePtr->winTable, entryPtr));
Tcl_DeleteHashEntry(entryPtr);
if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset,
col-tablePtr->colOffset,
&x, &y, &width, &height, 0))
TableInvalidate(tablePtr, x, y, width, height, 0);
}
#if 0
Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr);
#endif
EmbWinCleanup(tablePtr, ewPtr);
ckfree((char *) ewPtr);
}
/*
*--------------------------------------------------------------
*
* EmbWinConfigure --
* This procedure is called to handle configuration options
* for an embedded window.
*
* Results:
* The return value is a standard Tcl result. If TCL_ERROR is
* returned, then the interp's result contains an error message..
*
* Side effects:
* Configuration information for the embedded window changes,
* such as alignment, stretching, or name of the embedded
* window.
*
*--------------------------------------------------------------
*/
static int
EmbWinConfigure(tablePtr, ewPtr, objc, objv)
Table *tablePtr; /* Information about table widget that
* contains embedded window. */
TableEmbWindow *ewPtr; /* Embedded window to be configured. */
int objc; /* Number of objs in objv. */
Tcl_Obj *CONST objv[]; /* Obj type options. */
{
Tcl_Interp *interp = tablePtr->interp;
Tk_Window oldWindow;
int i, result;
CONST84 char **argv;
oldWindow = ewPtr->tkwin;
/* Stringify */
argv = (CONST84 char **) ckalloc((objc + 1) * sizeof(char *));
for (i = 0; i < objc; i++)
argv[i] = Tcl_GetString(objv[i]);
argv[i] = NULL;
result = Tk_ConfigureWidget(interp, tablePtr->tkwin,
winConfigSpecs, objc, argv, (char *) ewPtr,
TK_CONFIG_ARGV_ONLY);
ckfree((char *) argv);
if (result != TCL_OK) {
return TCL_ERROR;
}
if (oldWindow != ewPtr->tkwin) {
ewPtr->displayed = 0;
if (oldWindow != NULL) {
Tk_DeleteEventHandler(oldWindow, StructureNotifyMask,
EmbWinStructureProc, (ClientData) ewPtr);
Tk_ManageGeometry(oldWindow, (Tk_GeomMgr *) NULL,
(ClientData) NULL);
EmbWinUnmapNow(oldWindow, tablePtr->tkwin);
}
if (ewPtr->tkwin != NULL) {
Tk_Window ancestor, parent;
/*
* Make sure that the table is either the parent of the
* embedded window or a descendant of that parent. Also,
* don't allow a top-level window to be managed inside
* a table.
*/
parent = Tk_Parent(ewPtr->tkwin);
for (ancestor = tablePtr->tkwin; ;
ancestor = Tk_Parent(ancestor)) {
if (ancestor == parent) {
break;
}
if (Tk_IsTopLevel(ancestor)) {
badMaster:
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"can't embed ",
Tk_PathName(ewPtr->tkwin), " in ",
Tk_PathName(tablePtr->tkwin),
(char *)NULL);
ewPtr->tkwin = NULL;
return TCL_ERROR;
}
}
if (Tk_IsTopLevel(ewPtr->tkwin) ||
(ewPtr->tkwin == tablePtr->tkwin)) {
goto badMaster;
}
/*
* Take over geometry management for the window, plus create
* an event handler to find out when it is deleted.
*/
Tk_ManageGeometry(ewPtr->tkwin, &tableGeomType, (ClientData)ewPtr);
Tk_CreateEventHandler(ewPtr->tkwin, StructureNotifyMask,
EmbWinStructureProc, (ClientData) ewPtr);
}
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* Table_WinMove --
* This procedure is invoked by ... whenever
* an embedded window is being moved.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* If an embedded window is in the dest cell, it is deleted.
*
*--------------------------------------------------------------
*/
int
Table_WinMove(register Table *tablePtr, char *CONST srcPtr,
char *CONST destPtr, int flags)
{
int srow, scol, row, col, new;
Tcl_HashEntry *entryPtr;
TableEmbWindow *ewPtr;
if (TableGetIndex(tablePtr, srcPtr, &srow, &scol) != TCL_OK ||
TableGetIndex(tablePtr, destPtr, &row, &col) != TCL_OK) {
return TCL_ERROR;
}
entryPtr = Tcl_FindHashEntry(tablePtr->winTable, srcPtr);
if (entryPtr == NULL) {
if (flags & INV_NO_ERR_MSG) {
return TCL_OK;
} else {
Tcl_AppendStringsToObj(Tcl_GetObjResult(tablePtr->interp),
"no window at index \"", srcPtr, "\"", (char *) NULL);
return TCL_ERROR;
}
}
/* avoid moving it to the same location */
if (srow == row && scol == col) {
return TCL_OK;
}
/* get the window pointer */
ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
/* and free the old hash table entry */
Tcl_DeleteHashEntry(entryPtr);
entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, destPtr, &new);
if (!new) {
/* window already there - just delete it */
TableEmbWindow *ewPtrDel;
ewPtrDel = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
/* This prevents the deletion of it's own entry, since we need it */
ewPtrDel->hPtr = NULL;
EmbWinDelete(tablePtr, ewPtrDel);
}
/* set the new entry's value */
Tcl_SetHashValue(entryPtr, (ClientData) ewPtr);
ewPtr->hPtr = entryPtr;
if (flags & INV_FORCE) {
int x, y, w, h;
/* Invalidate old cell */
if (TableCellVCoords(tablePtr, srow-tablePtr->rowOffset,
scol-tablePtr->colOffset, &x, &y, &w, &h, 0)) {
TableInvalidate(tablePtr, x, y, w, h, 0);
}
/* Invalidate new cell */
if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset,
col-tablePtr->colOffset, &x, &y, &w, &h, 0)) {
TableInvalidate(tablePtr, x, y, w, h, 0);
}
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* Table_WinDelete --
* This procedure is invoked by ... whenever
* an embedded window is being delete.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Window info will be deleted.
*
*--------------------------------------------------------------
*/
int
Table_WinDelete(register Table *tablePtr, char *CONST idxPtr)
{
Tcl_HashEntry *entryPtr;
entryPtr = Tcl_FindHashEntry(tablePtr->winTable, idxPtr);
if (entryPtr != NULL) {
/* get the window pointer & clean up data associated with it */
EmbWinDelete(tablePtr, (TableEmbWindow *) Tcl_GetHashValue(entryPtr));
}
return TCL_OK;
}
/*
*--------------------------------------------------------------
*
* Table_WindowCmd --
* This procedure is invoked to process the window method
* that corresponds to a widget managed by this module.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*--------------------------------------------------------------
*/
int
Table_WindowCmd(ClientData clientData, register Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[])
{
register Table *tablePtr = (Table *)clientData;
int result = TCL_OK, cmdIndex, row, col, x, y, width, height, i, new;
TableEmbWindow *ewPtr;
Tcl_HashEntry *entryPtr;
Tcl_HashSearch search;
char buf[INDEX_BUFSIZE], *keybuf, *winname;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?");
return TCL_ERROR;
}
/* parse the next argument */
if (Tcl_GetIndexFromObj(interp, objv[2], winCmdNames,
"option", 0, &cmdIndex) != TCL_OK) {
return TCL_ERROR;
}
switch ((enum winCommand) cmdIndex) {
case WIN_CGET:
if (objc != 5) {
Tcl_WrongNumArgs(interp, 3, objv, "index option");
return TCL_ERROR;
}
entryPtr = Tcl_FindHashEntry(tablePtr->winTable,
Tcl_GetString(objv[3]));
if (entryPtr == NULL) {
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"no window at index \"",
Tcl_GetString(objv[3]), "\"", (char *)NULL);
return TCL_ERROR;
} else {
ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
result = Tk_ConfigureValue(interp, tablePtr->tkwin, winConfigSpecs,
(char *) ewPtr,
Tcl_GetString(objv[4]), 0);
}
return result; /* CGET */
case WIN_CONFIGURE:
if (objc < 4) {
Tcl_WrongNumArgs(interp, 3, objv, "index ?arg arg ...?");
return TCL_ERROR;
}
if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR) {
return TCL_ERROR;
}
TableMakeArrayIndex(row, col, buf);
entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, buf, &new);
if (new) {
/* create the structure */
ewPtr = TableNewEmbWindow(tablePtr);
/* insert it into the table */
Tcl_SetHashValue(entryPtr, (ClientData) ewPtr);
ewPtr->hPtr = entryPtr;
/* configure the window structure */
result = EmbWinConfigure(tablePtr, ewPtr, objc-4, objv+4);
if (result == TCL_ERROR) {
/* release the structure */
EmbWinCleanup(tablePtr, ewPtr);
ckfree((char *) ewPtr);
/* and free the hash table entry */
Tcl_DeleteHashEntry(entryPtr);
}
} else {
/* window exists, do a reconfig if we have enough args */
/* get the window pointer from the table */
ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
/* 5 args means that there are values to replace */
if (objc > 5) {
/* and do a reconfigure */
result = EmbWinConfigure(tablePtr, ewPtr, objc-4, objv+4);
}
}
if (result == TCL_ERROR) {
return TCL_ERROR;
}
/*
* If there were less than 6 args, we need
* to do a printout of the config, even for new windows
*/
if (objc < 6) {
result = Tk_ConfigureInfo(interp, tablePtr->tkwin, winConfigSpecs,
(char *) ewPtr, (objc == 5)?
Tcl_GetString(objv[4]) : NULL, 0);
} else {
/* Otherwise we reconfigured so invalidate
* the table for a redraw */
if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset,
col-tablePtr->colOffset,
&x, &y, &width, &height, 0)) {
TableInvalidate(tablePtr, x, y, width, height, 1);
}
}
return result; /* CONFIGURE */
case WIN_DELETE:
if (objc < 4) {
Tcl_WrongNumArgs(interp, 3, objv, "index ?index ...?");
return TCL_ERROR;
}
for (i = 3; i < objc; i++) {
Table_WinDelete(tablePtr, Tcl_GetString(objv[i]));
}
break;
case WIN_MOVE:
if (objc != 5) {
Tcl_WrongNumArgs(interp, 3, objv, "srcIndex destIndex");
return TCL_ERROR;
}
result = Table_WinMove(tablePtr, Tcl_GetString(objv[3]),
Tcl_GetString(objv[4]), INV_FORCE);
break;
case WIN_NAMES: {
Tcl_Obj *objPtr = Tcl_NewObj();
/* just print out the window names */
if (objc < 3 || objc > 4) {
Tcl_WrongNumArgs(interp, 3, objv, "?pattern?");
return TCL_ERROR;
}
winname = (objc == 4) ? Tcl_GetString(objv[3]) : NULL;
entryPtr = Tcl_FirstHashEntry(tablePtr->winTable, &search);
while (entryPtr != NULL) {
keybuf = Tcl_GetHashKey(tablePtr->winTable, entryPtr);
if (objc == 3 || Tcl_StringMatch(keybuf, winname)) {
Tcl_ListObjAppendElement(NULL, objPtr,
Tcl_NewStringObj(keybuf, -1));
}
entryPtr = Tcl_NextHashEntry(&search);
}
Tcl_SetObjResult(interp, TableCellSortObj(interp, objPtr));
break;
}
}
return TCL_OK;
}

View File

@@ -0,0 +1,8 @@
#if 0
TBL_MAJOR_VERSION = 2
TBL_MINOR_VERSION = 10
PACKAGE_VERSION = $(TBL_MAJOR_VERSION).$(TBL_MINOR_VERSION)
#endif
#define TBL_MAJOR_VERSION 2
#define TBL_MINOR_VERSION 10
#define PACKAGE_VERSION "2.10"

825
tktable/library/tkTable.tcl Normal file
View File

@@ -0,0 +1,825 @@
# table.tcl --
#
# Version align with tkTable 2.7, jeff at hobbs org
# This file defines the default bindings for Tk table widgets
# and provides procedures that help in implementing those bindings.
#
# RCS: @(#) $Id: tkTable.tcl,v 1.14 2005/07/12 23:26:28 hobbs Exp $
#--------------------------------------------------------------------------
# ::tk::table::Priv elements used in this file:
#
# x && y - Coords in widget
# afterId - Token returned by "after" for autoscanning.
# tablePrev - The last element to be selected or deselected
# during a selection operation.
# mouseMoved - Boolean to indicate whether mouse moved while
# the button was pressed.
# borderInfo - Boolean to know if the user clicked on a border
# borderB1 - Boolean that set whether B1 can be used for the
# interactiving resizing
#--------------------------------------------------------------------------
namespace eval ::tk::table {
# Ensure that a namespace is created for us
variable Priv
array set Priv [list x 0 y 0 afterId {} mouseMoved 0 \
borderInfo {} borderB1 1]
}
# ::tk::table::ClipboardKeysyms --
# This procedure is invoked to identify the keys that correspond to
# the "copy", "cut", and "paste" functions for the clipboard.
#
# Arguments:
# copy - Name of the key (keysym name plus modifiers, if any,
# such as "Meta-y") used for the copy operation.
# cut - Name of the key used for the cut operation.
# paste - Name of the key used for the paste operation.
proc ::tk::table::ClipboardKeysyms {copy cut paste} {
bind Table <$copy> {tk_tableCopy %W}
bind Table <$cut> {tk_tableCut %W}
bind Table <$paste> {tk_tablePaste %W}
}
::tk::table::ClipboardKeysyms <Copy> <Cut> <Paste>
##
## Interactive cell resizing, affected by -resizeborders option
##
bind Table <3> {
## You might want to check for cell returned if you want to
## restrict the resizing of certain cells
%W border mark %x %y
}
bind Table <B3-Motion> { %W border dragto %x %y }
## Button events
bind Table <1> { ::tk::table::Button1 %W %x %y }
bind Table <B1-Motion> { ::tk::table::B1Motion %W %x %y }
bind Table <ButtonRelease-1> {
if {$::tk::table::Priv(borderInfo) == "" && [winfo exists %W]} {
::tk::table::CancelRepeat
%W activate @%x,%y
}
}
bind Table <Double-1> {
# empty
}
bind Table <Shift-1> {::tk::table::BeginExtend %W [%W index @%x,%y]}
bind Table <Control-1> {::tk::table::BeginToggle %W [%W index @%x,%y]}
bind Table <B1-Enter> {::tk::table::CancelRepeat}
bind Table <B1-Leave> {
if {$::tk::table::Priv(borderInfo) == ""} {
array set ::tk::table::Priv {x %x y %y}
::tk::table::AutoScan %W
}
}
bind Table <2> {
%W scan mark %x %y
array set ::tk::table::Priv {x %x y %y}
set ::tk::table::Priv(mouseMoved) 0
}
bind Table <B2-Motion> {
if {(%x != $::tk::table::Priv(x)) || (%y != $::tk::table::Priv(y))} {
set ::tk::table::Priv(mouseMoved) 1
}
if {$::tk::table::Priv(mouseMoved)} { %W scan dragto %x %y }
}
bind Table <ButtonRelease-2> {
if {!$::tk::table::Priv(mouseMoved)} { tk_tablePaste %W [%W index @%x,%y] }
}
## Key events
# This forces a cell commit if an active cell exists
bind Table <<Table_Commit>> {
catch {%W activate active}
}
# Remove this if you don't want cell commit to occur on every Leave for
# the table (via mouse) or FocusOut (loss of focus by table).
event add <<Table_Commit>> <Leave> <FocusOut>
bind Table <Shift-Up> {::tk::table::ExtendSelect %W -1 0}
bind Table <Shift-Down> {::tk::table::ExtendSelect %W 1 0}
bind Table <Shift-Left> {::tk::table::ExtendSelect %W 0 -1}
bind Table <Shift-Right> {::tk::table::ExtendSelect %W 0 1}
bind Table <Prior> {%W yview scroll -1 pages; %W activate topleft}
bind Table <Next> {%W yview scroll 1 pages; %W activate topleft}
bind Table <Control-Prior> {%W xview scroll -1 pages}
bind Table <Control-Next> {%W xview scroll 1 pages}
bind Table <Home> {%W see origin}
bind Table <End> {%W see end}
bind Table <Control-Home> {
%W selection clear all
%W activate origin
%W selection set active
%W see active
}
bind Table <Control-End> {
%W selection clear all
%W activate end
%W selection set active
%W see active
}
bind Table <Shift-Control-Home> {::tk::table::DataExtend %W origin}
bind Table <Shift-Control-End> {::tk::table::DataExtend %W end}
bind Table <Select> {::tk::table::BeginSelect %W [%W index active]}
bind Table <Shift-Select> {::tk::table::BeginExtend %W [%W index active]}
bind Table <Control-slash> {::tk::table::SelectAll %W}
bind Table <Control-backslash> {
if {[string match browse [%W cget -selectmode]]} {%W selection clear all}
}
bind Table <Up> {::tk::table::MoveCell %W -1 0}
bind Table <Down> {::tk::table::MoveCell %W 1 0}
bind Table <Left> {::tk::table::MoveCell %W 0 -1}
bind Table <Right> {::tk::table::MoveCell %W 0 1}
bind Table <KeyPress> {::tk::table::Insert %W %A}
bind Table <BackSpace> {::tk::table::BackSpace %W}
bind Table <Delete> {%W delete active insert}
bind Table <Escape> {%W reread}
#bind Table <Return> {::tk::table::MoveCell %W 1 0}
bind Table <Return> {::tk::table::Insert %W "\n"}
bind Table <Control-Left> {%W icursor [expr {[%W icursor]-1}]}
bind Table <Control-Right> {%W icursor [expr {[%W icursor]+1}]}
bind Table <Control-e> {%W icursor end}
bind Table <Control-a> {%W icursor 0}
bind Table <Control-k> {%W delete active insert end}
bind Table <Control-equal> {::tk::table::ChangeWidth %W active 1}
bind Table <Control-minus> {::tk::table::ChangeWidth %W active -1}
# Ignore all Alt, Meta, and Control keypresses unless explicitly bound.
# Otherwise, if a widget binding for one of these is defined, the
# <KeyPress> class binding will also fire and insert the character,
# which is wrong. Ditto for Tab.
bind Table <Alt-KeyPress> {# nothing}
bind Table <Meta-KeyPress> {# nothing}
bind Table <Control-KeyPress> {# nothing}
bind Table <Any-Tab> {# nothing}
if {[string match "macintosh" $::tcl_platform(platform)]} {
bind Table <Command-KeyPress> {# nothing}
}
# ::tk::table::GetSelection --
# This tries to obtain the default selection. On Unix, we first try
# and get a UTF8_STRING, a type supported by modern Unix apps for
# passing Unicode data safely. We fall back on the default STRING
# type otherwise. On Windows, only the STRING type is necessary.
# Arguments:
# w The widget for which the selection will be retrieved.
# Important for the -displayof property.
# sel The source of the selection (PRIMARY or CLIPBOARD)
# Results:
# Returns the selection, or an error if none could be found
#
if {[string compare $::tcl_platform(platform) "unix"]} {
proc ::tk::table::GetSelection {w {sel PRIMARY}} {
if {[catch {selection get -displayof $w -selection $sel} txt]} {
return -code error "could not find default selection"
} else {
return $txt
}
}
} else {
proc ::tk::table::GetSelection {w {sel PRIMARY}} {
if {[catch {selection get -displayof $w -selection $sel \
-type UTF8_STRING} txt] \
&& [catch {selection get -displayof $w -selection $sel} txt]} {
return -code error "could not find default selection"
} else {
return $txt
}
}
}
# ::tk::table::CancelRepeat --
# A copy of tkCancelRepeat, just in case it's not available or changes.
# This procedure is invoked to cancel an auto-repeat action described
# by ::tk::table::Priv(afterId). It's used by several widgets to auto-scroll
# the widget when the mouse is dragged out of the widget with a
# button pressed.
#
# Arguments:
# None.
proc ::tk::table::CancelRepeat {} {
variable Priv
after cancel $Priv(afterId)
set Priv(afterId) {}
}
# ::tk::table::Insert --
#
# Insert into the active cell
#
# Arguments:
# w - the table widget
# s - the string to insert
# Results:
# Returns nothing
#
proc ::tk::table::Insert {w s} {
if {[string compare $s {}]} {
$w insert active insert $s
}
}
# ::tk::table::BackSpace --
#
# BackSpace in the current cell
#
# Arguments:
# w - the table widget
# Results:
# Returns nothing
#
proc ::tk::table::BackSpace {w} {
set cur [$w icursor]
if {[string compare {} $cur] && $cur} {
$w delete active [expr {$cur-1}]
}
}
# ::tk::table::Button1 --
#
# This procedure is called to handle selecting with mouse button 1.
# It will distinguish whether to start selection or mark a border.
#
# Arguments:
# w - the table widget
# x - x coord
# y - y coord
# Results:
# Returns nothing
#
proc ::tk::table::Button1 {w x y} {
variable Priv
#
# $Priv(borderInfo) is null if the user did not click on a border
#
if {$Priv(borderB1) == 1} {
set Priv(borderInfo) [$w border mark $x $y]
# account for what resizeborders are set [Bug 876320] (ferenc)
set rbd [$w cget -resizeborders]
if {$rbd == "none" || ![llength $Priv(borderInfo)]
|| ($rbd == "col" && [lindex $Priv(borderInfo) 1] == "")
|| ($rbd == "row" && [lindex $Priv(borderInfo) 0] == "")} {
set Priv(borderInfo) ""
}
} else {
set Priv(borderInfo) ""
}
if {$Priv(borderInfo) == ""} {
#
# Only do this when a border wasn't selected
#
if {[winfo exists $w]} {
::tk::table::BeginSelect $w [$w index @$x,$y]
focus $w
}
array set Priv [list x $x y $y]
set Priv(mouseMoved) 0
}
}
# ::tk::table::B1Motion --
#
# This procedure is called to start processing mouse motion events while
# button 1 moves while pressed. It will distinguish whether to change
# the selection or move a border.
#
# Arguments:
# w - the table widget
# x - x coord
# y - y coord
# Results:
# Returns nothing
#
proc ::tk::table::B1Motion {w x y} {
variable Priv
# If we already had motion, or we moved more than 1 pixel,
# then we start the Motion routine
if {$Priv(borderInfo) != ""} {
#
# If the motion is on a border, drag it and skip the rest
# of this binding.
#
$w border dragto $x $y
} else {
#
# If we already had motion, or we moved more than 1 pixel,
# then we start the Motion routine
#
if {
$::tk::table::Priv(mouseMoved)
|| abs($x-$::tk::table::Priv(x)) > 1
|| abs($y-$::tk::table::Priv(y)) > 1
} {
set ::tk::table::Priv(mouseMoved) 1
}
if {$::tk::table::Priv(mouseMoved)} {
::tk::table::Motion $w [$w index @$x,$y]
}
}
}
# ::tk::table::BeginSelect --
#
# This procedure is typically invoked on button-1 presses. It begins
# the process of making a selection in the table. Its exact behavior
# depends on the selection mode currently in effect for the table;
# see the Motif documentation for details.
#
# Arguments:
# w - The table widget.
# el - The element for the selection operation (typically the
# one under the pointer). Must be in row,col form.
proc ::tk::table::BeginSelect {w el} {
variable Priv
if {[scan $el %d,%d r c] != 2} return
switch [$w cget -selectmode] {
multiple {
if {[$w tag includes title $el]} {
## in the title area
if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {
## We're in a column header
if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {
## We're in the topleft title area
set inc topleft
set el2 end
} else {
set inc [$w index topleft row],$c
set el2 [$w index end row],$c
}
} else {
## We're in a row header
set inc $r,[$w index topleft col]
set el2 $r,[$w index end col]
}
} else {
set inc $el
set el2 $el
}
if {[$w selection includes $inc]} {
$w selection clear $el $el2
} else {
$w selection set $el $el2
}
}
extended {
$w selection clear all
if {[$w tag includes title $el]} {
if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {
## We're in a column header
if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {
## We're in the topleft title area
$w selection set $el end
} else {
$w selection set $el [$w index end row],$c
}
} else {
## We're in a row header
$w selection set $el $r,[$w index end col]
}
} else {
$w selection set $el
}
$w selection anchor $el
set Priv(tablePrev) $el
}
default {
if {![$w tag includes title $el]} {
$w selection clear all
$w selection set $el
set Priv(tablePrev) $el
}
$w selection anchor $el
}
}
}
# ::tk::table::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 table's selection mode.
#
# Arguments:
# w - The table widget.
# el - The element under the pointer (must be in row,col form).
proc ::tk::table::Motion {w el} {
variable Priv
if {![info exists Priv(tablePrev)]} {
set Priv(tablePrev) $el
return
}
if {[string match $Priv(tablePrev) $el]} return
switch [$w cget -selectmode] {
browse {
$w selection clear all
$w selection set $el
set Priv(tablePrev) $el
}
extended {
# avoid tables that have no anchor index yet.
if {[catch {$w index anchor}]} { return }
scan $Priv(tablePrev) %d,%d r c
scan $el %d,%d elr elc
if {[$w tag includes title $el]} {
if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {
## We're in a column header
if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {
## We're in the topleft title area
$w selection clear anchor end
} else {
$w selection clear anchor [$w index end row],$c
}
$w selection set anchor [$w index end row],$elc
} else {
## We're in a row header
$w selection clear anchor $r,[$w index end col]
$w selection set anchor $elr,[$w index end col]
}
} else {
$w selection clear anchor $Priv(tablePrev)
$w selection set anchor $el
}
set Priv(tablePrev) $el
}
}
}
# ::tk::table::BeginExtend --
#
# This procedure is typically invoked on shift-button-1 presses. It
# begins the process of extending a selection in the table. Its
# exact behavior depends on the selection mode currently in effect
# for the table; see the Motif documentation for details.
#
# Arguments:
# w - The table widget.
# el - The element for the selection operation (typically the
# one under the pointer). Must be in numerical form.
proc ::tk::table::BeginExtend {w el} {
# avoid tables that have no anchor index yet.
if {[catch {$w index anchor}]} { return }
if {[string match extended [$w cget -selectmode]] &&
[$w selection includes anchor]} {
::tk::table::Motion $w $el
}
}
# ::tk::table::BeginToggle --
#
# This procedure is typically invoked on control-button-1 presses. It
# begins the process of toggling a selection in the table. Its
# exact behavior depends on the selection mode currently in effect
# for the table; see the Motif documentation for details.
#
# Arguments:
# w - The table widget.
# el - The element for the selection operation (typically the
# one under the pointer). Must be in numerical form.
proc ::tk::table::BeginToggle {w el} {
if {[string match extended [$w cget -selectmode]]} {
variable Priv
set Priv(tablePrev) $el
$w selection anchor $el
if {[$w tag includes title $el]} {
scan $el %d,%d r c
if {$r < [$w cget -titlerows]+[$w cget -roworigin]} {
## We're in a column header
if {$c < [$w cget -titlecols]+[$w cget -colorigin]} {
## We're in the topleft title area
set end end
} else {
set end [$w index end row],$c
}
} else {
## We're in a row header
set end $r,[$w index end col]
}
} else {
## We're in a non-title cell
set end $el
}
if {[$w selection includes $end]} {
$w selection clear $el $end
} else {
$w selection set $el $end
}
}
}
# ::tk::table::AutoScan --
# This procedure is invoked when the mouse leaves an table window
# with button 1 down. It scrolls the window up, down, left, or
# right, depending on where the mouse left the window, and reschedules
# itself as an "after" command so that the window continues to scroll until
# the mouse moves back into the window or the mouse button is released.
#
# Arguments:
# w - The table window.
proc ::tk::table::AutoScan {w} {
if {![winfo exists $w]} return
variable Priv
set x $Priv(x)
set y $Priv(y)
if {$y >= [winfo height $w]} {
$w yview scroll 1 units
} elseif {$y < 0} {
$w yview scroll -1 units
} elseif {$x >= [winfo width $w]} {
$w xview scroll 1 units
} elseif {$x < 0} {
$w xview scroll -1 units
} else {
return
}
::tk::table::Motion $w [$w index @$x,$y]
set Priv(afterId) [after 50 ::tk::table::AutoScan $w]
}
# ::tk::table::MoveCell --
#
# Moves the location cursor (active element) by the specified number
# of cells and changes the selection if we're in browse or extended
# selection mode. If the new cell is "hidden", we skip to the next
# visible cell if possible, otherwise just abort.
#
# Arguments:
# w - The table widget.
# x - +1 to move down one cell, -1 to move up one cell.
# y - +1 to move right one cell, -1 to move left one cell.
proc ::tk::table::MoveCell {w x y} {
if {[catch {$w index active row} r]} return
set c [$w index active col]
set cell [$w index [incr r $x],[incr c $y]]
while {[string compare [set true [$w hidden $cell]] {}]} {
# The cell is in some way hidden
if {[string compare $true [$w index active]]} {
# The span cell wasn't the previous cell, so go to that
set cell $true
break
}
if {$x > 0} {incr r} elseif {$x < 0} {incr r -1}
if {$y > 0} {incr c} elseif {$y < 0} {incr c -1}
if {[string compare $cell [$w index $r,$c]]} {
set cell [$w index $r,$c]
} else {
# We couldn't find a non-hidden cell, just don't move
return
}
}
$w activate $cell
$w see active
switch [$w cget -selectmode] {
browse {
$w selection clear all
$w selection set active
}
extended {
variable Priv
$w selection clear all
$w selection set active
$w selection anchor active
set Priv(tablePrev) [$w index active]
}
}
}
# ::tk::table::ExtendSelect --
#
# Does nothing unless we're in extended selection mode; in this
# case it moves the location cursor (active element) by the specified
# number of cells, and extends the selection to that point.
#
# Arguments:
# w - The table widget.
# x - +1 to move down one cell, -1 to move up one cell.
# y - +1 to move right one cell, -1 to move left one cell.
proc ::tk::table::ExtendSelect {w x y} {
if {[string compare extended [$w cget -selectmode]] ||
[catch {$w index active row} r]} return
set c [$w index active col]
$w activate [incr r $x],[incr c $y]
$w see active
::tk::table::Motion $w [$w index active]
}
# ::tk::table::DataExtend
#
# This procedure is called for key-presses such as Shift-KEndData.
# If the selection mode isnt 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 table widget.
# el - An integer cell number.
proc ::tk::table::DataExtend {w el} {
set mode [$w cget -selectmode]
if {[string match extended $mode]} {
$w activate $el
$w see $el
if {[$w selection includes anchor]} {::tk::table::Motion $w $el}
} elseif {[string match multiple $mode]} {
$w activate $el
$w see $el
}
}
# ::tk::table::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 table widget.
proc ::tk::table::SelectAll {w} {
if {[regexp {^(single|browse)$} [$w cget -selectmode]]} {
$w selection clear all
catch {$w selection set active}
} elseif {[$w cget -selecttitles]} {
$w selection set [$w cget -roworigin],[$w cget -colorigin] end
} else {
$w selection set origin end
}
}
# ::tk::table::ChangeWidth --
#
# Adjust the widget of the specified cell by $a.
#
# Arguments:
# w - The table widget.
# i - cell index
# a - amount to adjust by
proc ::tk::table::ChangeWidth {w i a} {
set tmp [$w index $i col]
if {[set width [$w width $tmp]] >= 0} {
$w width $tmp [incr width $a]
} else {
$w width $tmp [incr width [expr {-$a}]]
}
}
# tk_tableCopy --
#
# This procedure copies the selection from a table widget into the
# clipboard.
#
# Arguments:
# w - Name of a table widget.
proc tk_tableCopy w {
if {[selection own -displayof $w] == "$w"} {
clipboard clear -displayof $w
catch {clipboard append -displayof $w [::tk::table::GetSelection $w]}
}
}
# tk_tableCut --
#
# This procedure copies the selection from a table widget into the
# clipboard, then deletes the selection (if it exists in the given
# widget).
#
# Arguments:
# w - Name of a table widget.
proc tk_tableCut w {
if {[selection own -displayof $w] == "$w"} {
clipboard clear -displayof $w
catch {
clipboard append -displayof $w [::tk::table::GetSelection $w]
$w cursel {}
$w selection clear all
}
}
}
# tk_tablePaste --
#
# This procedure pastes the contents of the clipboard to the specified
# cell (active by default) in a table widget.
#
# Arguments:
# w - Name of a table widget.
# cell - Cell to start pasting in.
#
proc tk_tablePaste {w {cell {}}} {
if {[string compare {} $cell]} {
if {[catch {::tk::table::GetSelection $w} data]} return
} else {
if {[catch {::tk::table::GetSelection $w CLIPBOARD} data]} {
return
}
set cell active
}
tk_tablePasteHandler $w [$w index $cell] $data
if {[$w cget -state] == "normal"} {focus $w}
}
# tk_tablePasteHandler --
#
# This procedure handles how data is pasted into the table widget.
# This handles data in the default table selection form.
#
# NOTE: this allows pasting into all cells except title cells,
# even those with -state disabled
#
# Arguments:
# w - Name of a table widget.
# cell - Cell to start pasting in.
#
proc tk_tablePasteHandler {w cell data} {
#
# Don't allow pasting into the title cells
#
if {[$w tag includes title $cell]} {
return
}
set rows [expr {[$w cget -rows]-[$w cget -roworigin]}]
set cols [expr {[$w cget -cols]-[$w cget -colorigin]}]
set r [$w index $cell row]
set c [$w index $cell col]
set rsep [$w cget -rowseparator]
set csep [$w cget -colseparator]
## Assume separate rows are split by row separator if specified
## If you were to want multi-character row separators, you would need:
# regsub -all $rsep $data <newline> data
# set data [join $data <newline>]
if {[string compare {} $rsep]} { set data [split $data $rsep] }
set row $r
foreach line $data {
if {$row > $rows} break
set col $c
## Assume separate cols are split by col separator if specified
## Unless a -separator was specified
if {[string compare {} $csep]} { set line [split $line $csep] }
## If you were to want multi-character col separators, you would need:
# regsub -all $csep $line <newline> line
# set line [join $line <newline>]
foreach item $line {
if {$col > $cols} break
$w set $row,$col $item
incr col
}
incr row
}
}
# tk::table::Sort --
#
# This procedure handles how data is sorted in the table widget.
# This isn't currently used by tktable, but can be called by the user.
# It's behavior may change in the future.
#
# Arguments:
# w - Name of a table widget.
# start - start cell of rectangle to sort
# end - end cell of rectangle to sort
# col - column within rectangle to sort on
# args - passed to lsort proc (ie: -integer -decreasing)
proc ::tk::table::Sort {w start end col args} {
set start [$w index $start]
set end [$w index $end]
scan $start %d,%d sr sc
scan $end %d,%d er ec
if {($col < $sc) || ($col > $ec)} {
return -code error "$col is not within sort range $sc to $ec"
}
set col [expr {$col - $sc}]
set data {}
for {set i $sr} {$i <= $er} {incr i} {
lappend data [$w get $i,$sc $i,$ec]
}
set i $sr
foreach row [eval [list lsort -index $col] $args [list $data]] {
$w set row $i,$sc $row
incr i
}
}

651
tktable/library/tktable.py Normal file
View File

@@ -0,0 +1,651 @@
# Updated tktable.py wrapper for Python 2.x with Tkinter.
# Improvements over previous version can be seen at:
# https://sf.net/tracker2/?func=detail&aid=2244167&group_id=11464&atid=311464
#
# Copyright (c) 2008, Guilherme Polo
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
"""
This contains a wrapper class for the tktable widget as well a class for using
tcl arrays that are, in some instances, required by tktable.
"""
__author__ = "Guilherme Polo <ggpolo@gmail.com>"
__all__ = ["ArrayVar", "Table"]
import Tkinter
def _setup_master(master):
if master is None:
if Tkinter._support_default_root:
master = Tkinter._default_root or Tkinter.Tk()
else:
raise RuntimeError("No master specified and Tkinter is "
"configured to not support default master")
return master
class ArrayVar(Tkinter.Variable):
def __init__(self, master=None, name=None):
# Tkinter.Variable.__init__ is not called on purpose! I don't wanna
# see an ugly _default value in the pretty array.
self._master = _setup_master(master)
self._tk = self._master.tk
if name:
self._name = name
else:
self._name = 'PY_VAR%s' % id(self)
def get(self, index=None):
if index is None:
res = {}
for key in self.names():
res[key] = self._tk.globalgetvar(str(self), key)
return res
return self._tk.globalgetvar(str(self), str(index))
def names(self):
return self._tk.call('array', 'names', self._name)
def set(self, key, value):
self._tk.globalsetvar(str(self), str(key), value)
class Table(Tkinter.Widget):
"""Create and manipulate tables."""
_switches = ('holddimensions', 'holdselection', 'holdtags', 'holdwindows',
'keeptitles', '-')
_tabsubst_format = ('%c', '%C', '%i', '%r', '%s', '%S', '%W')
_tabsubst_commands = ('browsecommand', 'browsecmd', 'command',
'selectioncommand', 'selcmd',
'validatecommand', 'valcmd')
def __init__(self, master=None, **kw):
master = _setup_master(master)
try:
master.tk.call('package', 'require', 'Tktable')
except Tkinter.TclError:
try:
master.tk.call('load', 'Tktable.dll', 'Tktable')
except Tkinter.TclError:
master.tk.call('load', '', 'Tktable')
Tkinter.Widget.__init__(self, master, 'table', kw)
def _options(self, cnf, kw=None):
if kw:
cnf = Tkinter._cnfmerge((cnf, kw))
else:
cnf = Tkinter._cnfmerge(cnf)
res = ()
for k, v in cnf.iteritems():
if callable(v):
if k in self._tabsubst_commands:
v = "%s %s" % (self._register(v, self._tabsubst),
' '.join(self._tabsubst_format))
else:
v = self._register(v)
res += ('-%s' % k, v)
return res
def _tabsubst(self, *args):
if len(args) != len(self._tabsubst_format):
return args
tk = self.tk
c, C, i, r, s, S, W = args
e = Tkinter.Event()
e.widget = self
e.c = tk.getint(c)
e.i = tk.getint(i)
e.r = tk.getint(r)
e.C = (e.r, e.c)
try:
e.s = tk.getint(s)
except Tkinter.TclError:
e.s = s
try:
e.S = tk.getint(S)
except Tkinter.TclError:
e.S = S
e.W = W
return (e,)
def _handle_switches(self, args):
args = args or ()
return tuple(('-%s' % x) for x in args if x in self._switches)
def activate(self, index):
"""Set the active cell to the one indicated by index."""
self.tk.call(self._w, 'activate', index)
def bbox(self, first, last=None):
"""Return the bounding box for the specified cell (range) as a
4-tuple of x, y, width and height in pixels. It clips the box to
the visible portion, if any, otherwise an empty tuple is returned."""
return self._getints(self.tk.call(self._w, 'bbox', first, last)) or ()
def clear(self, option, first=None, last=None):
"""This is a convenience routine to clear certain state information
managed by the table. first and last represent valid table indices.
If neither are specified, then the command operates on the whole
table."""
self.tk.call(self._w, 'clear', option, first, last)
def clear_cache(self, first=None, last=None):
"""Clear the specified section of the cache, if the table has been
keeping one."""
self.clear('cache', first, last)
def clear_sizes(self, first=None, last=None):
"""Clear the specified row and column areas of specific height/width
dimensions. When just one index is specified, for example 2,0, that
is interpreted as row 2 and column 0."""
self.clear('sizes', first, last)
def clear_tags(self, first=None, last=None):
"""Clear the specified area of tags (all row, column and cell tags)."""
self.clear('tags', first, last)
def clear_all(self, first=None, last=None):
"""Perform all of the above clear functions on the specified area."""
self.clear('all', first, last)
def curselection(self, value=None):
"""With no arguments, it returns the sorted indices of the currently
selected cells. Otherwise it sets all the selected cells to the given
value if there is an associated ArrayVar and the state is not
disabled."""
result = self.tk.call(self._w, 'curselection', value)
if value is None:
return result
def curvalue(self, value=None):
"""If no value is given, the value of the cell being edited (indexed
by active) is returned, else it is set to the given value. """
return self.tk.call(self._w, 'curvalue', value)
def delete_active(self, index1, index2=None):
"""Deletes text from the active cell. If only one index is given,
it deletes the character after that index, otherwise it deletes from
the first index to the second. index can be a number, insert or end."""
self.tk.call(self._w, 'delete', 'active', index1, index2)
def delete_cols(self, index, count=None, switches=None):
args = self._handle_switches(switches) + (index, count)
self.tk.call(self._w, 'delete', 'cols', *args)
def delete_rows(self, index, count=None, switches=None):
args = self._handle_switches(switches) + (index, count)
self.tk.call(self._w, 'delete', 'rows', *args)
def get(self, first, last=None):
"""Returns the value of the cells specified by the table indices
first and (optionally) last."""
return self.tk.call(self._w, 'get', first, last)
def height(self, row=None, **kwargs):
"""If row and kwargs are not given, a list describing all rows for
which a width has been set is returned.
If row is given, the height of that row is returnd.
If kwargs is given, then it sets the key/value pairs, where key is a
row and value represents the height for the row."""
if row is None and not kwargs:
pairs = self.tk.splitlist(self.tk.call(self._w, 'height'))
return dict(pair.split() for pair in pairs)
elif row:
return int(self.tk.call(self._w, 'height', str(row)))
args = Tkinter._flatten(kwargs.items())
self.tk.call(self._w, 'height', *args)
def hidden(self, *args):
"""When called without args, it returns all the hidden cells (those
cells covered by a spanning cell). If one index is specified, it
returns the spanning cell covering that index, if any. If multiple
indices are specified, it returns 1 if all indices are hidden cells,
0 otherwise."""
return self.tk.call(self._w, 'hidden', *args)
def icursor(self, arg=None):
"""If arg is not specified, return the location of the insertion
cursor in the active cell. Otherwise, set the cursor to that point in
the string.
0 is before the first character, you can also use insert or end for
the current insertion point or the end of the text. If there is no
active cell, or the cell or table is disabled, this will return -1."""
return self.tk.call(self._w, 'icursor', arg)
def index(self, index, rc=None):
"""Return the integer cell coordinate that corresponds to index in the
form row, col. If rc is specified, it must be either 'row' or 'col' so
only the row or column index is returned."""
res = self.tk.call(self._w, 'index', index, rc)
if rc is None:
return res
else:
return int(res)
def insert_active(self, index, value):
"""The value is a text string which is inserted at the index postion
of the active cell. The cursor is then positioned after the new text.
index can be a number, insert or end. """
self.tk.call(self._w, 'insert', 'active', index, value)
def insert_cols(self, index, count=None, switches=None):
args = self._handle_switches(switches) + (index, count)
self.tk.call(self._w, 'insert', 'cols', *args)
def insert_rows(self, index, count=None, switches=None):
args = self._handle_switches(switches) + (index, count)
self.tk.call(self._w, 'insert', 'rows', *args)
#def postscript(self, **kwargs):
# """Skip this command if you are under Windows.
#
# Accepted options:
# colormap, colormode, file, channel, first, fontmap, height,
# last, pageanchor, pageheight, pagewidth, pagex, pagey, rotate,
# width, x, y
# """
# args = ()
# for key, val in kwargs.iteritems():
# args += ('-%s' % key, val)
#
# return self.tk.call(self._w, 'postscript', *args)
def reread(self):
"""Rereads the old contents of the cell back into the editing buffer.
Useful for a key binding when <Escape> is pressed to abort the edit
(a default binding)."""
self.tk.call(self._w, 'reread')
def scan_mark(self, x, y):
self.tk.call(self._w, 'scan', 'mark', x, y)
def scan_dragto(self, x, y):
self.tk.call(self._w, 'scan', 'dragto', x, y)
def see(self, index):
self.tk.call(self._w, 'see', index)
def selection_anchor(self, index):
self.tk.call(self._w, 'selection', 'anchor', index)
def selection_clear(self, first, last=None):
self.tk.call(self._w, 'selection', 'clear', first, last)
def selection_includes(self, index):
return self.getboolean(self.tk.call(self._w, 'selection', 'includes',
index))
def selection_set(self, first, last=None):
self.tk.call(self._w, 'selection', 'set', first, last)
def set(self, rc=None, index=None, *args, **kwargs):
"""If rc is specified (either 'row' or 'col') then it is assumes that
args (if given) represents values which will be set into the
subsequent columns (if row is specified) or rows (for col).
If index is not None and args is not given, then it will return the
value(s) for the cell(s) specified.
If kwargs is given, assumes that each key in kwargs is a index in this
table and sets the specified index to the associated value. Table
validation will not be triggered via this method.
Note that the table must have an associated array (defined through the
variable option) in order to this work."""
if not args and index is not None:
if rc:
args = (rc, index)
else:
args = (index, )
return self.tk.call(self._w, 'set', *args)
if rc is None:
args = Tkinter._flatten(kwargs.items())
self.tk.call(self._w, 'set', *args)
else:
self.tk.call(self._w, 'set', rc, index, args)
def spans(self, index=None, **kwargs):
"""Manipulate row/col spans.
When called with no arguments, all known spans are returned as a dict.
When called with only the index, the span for that index only is
returned, if any. Otherwise kwargs is assumed to contain keys/values
pairs used to set spans. A span starts at the row,col defined by a key
and continues for the specified number of rows,cols specified by
its value. A span of 0,0 unsets any span on that cell."""
if kwargs:
args = Tkinter._flatten(kwargs.items())
self.tk.call(self._w, 'spans', *args)
else:
return self.tk.call(self._w, 'spans', index)
def tag_cell(self, tagname, *args):
return self.tk.call(self._w, 'tag', 'cell', tagname, *args)
def tag_cget(self, tagname, option):
return self.tk.call(self._w, 'tag', 'cget', tagname, '-%s' % option)
def tag_col(self, tagname, *args):
return self.tk.call(self._w, 'tag', 'col', tagname, *args)
def tag_configure(self, tagname, option=None, **kwargs):
"""Query or modify options associated with the tag given by tagname.
If no option is specified, a dict describing all of the available
options for tagname is returned. If option is specified, then the
command returns a list describing the one named option. Lastly, if
kwargs is given then it corresponds to option-value pairs that should
be modified."""
if option is None and not kwargs:
split1 = self.tk.splitlist(
self.tk.call(self._w, 'tag', 'configure', tagname))
result = {}
for item in split1:
res = self.tk.splitlist(item)
result[res[0]] = res[1:]
return result
elif option:
return self.tk.call(self._w, 'tag', 'configure', tagname,
'-%s' % option)
else:
args = ()
for key, val in kwargs.iteritems():
args += ('-%s' % key, val)
self.tk.call(self._w, 'tag', 'configure', tagname, *args)
def tag_delete(self, tagname):
self.tk.call(self._w, 'tag', 'delete', tagname)
def tag_exists(self, tagname):
return self.getboolean(self.tk.call(self._w, 'tag', 'exists', tagname))
def tag_includes(self, tagname, index):
return self.getboolean(self.tk.call(self._w, 'tag', 'includes',
tagname, index))
def tag_lower(self, tagname, belowthis=None):
self.tk.call(self._w, 'tag', 'lower', belowthis)
def tag_names(self, pattern=None):
return self.tk.call(self._w, 'tag', 'names', pattern)
def tag_raise(self, tagname, abovethis=None):
self.tk.call(self._w, 'tag', 'raise', tagname, abovethis)
def tag_row(self, tagname, *args):
return self.tk.call(self._w, 'tag', 'row', tagname, *args)
def validate(self, index):
"""Explicitly validates the specified index based on the current
callback set for the validatecommand option. Return 0 or 1 based on
whether the cell was validated."""
return self.tk.call(self._w, 'validate', index)
@property
def version(self):
"""Return tktable's package version."""
return self.tk.call(self._w, 'version')
def width(self, column=None, **kwargs):
"""If column and kwargs are not given, a dict describing all columns
for which a width has been set is returned.
If column is given, the width of that column is returnd.
If kwargs is given, then it sets the key/value pairs, where key is a
column and value represents the width for the column."""
if column is None and not kwargs:
pairs = self.tk.splitlist(self.tk.call(self._w, 'width'))
return dict(pair.split() for pair in pairs)
elif column:
return int(self.tk.call(self._w, 'width', str(column)))
args = Tkinter._flatten(kwargs.items())
self.tk.call(self._w, 'width', *args)
def window_cget(self, index, option):
return self.tk.call(self._w, 'window', 'cget', index, option)
def window_configure(self, index, option=None, **kwargs):
"""Query or modify options associated with the embedded window given
by index. This should also be used to add a new embedded window into
the table.
If no option is specified, a dict describing all of the available
options for index is returned. If option is specified, then the
command returns a list describing the one named option. Lastly, if
kwargs is given then it corresponds to option-value pairs that should
be modified."""
if option is None and not kwargs:
return self.tk.call(self._w, 'window', 'configure', index)
elif option:
return self.tk.call(self._w, 'window', 'configure', index,
'-%s' % option)
else:
args = ()
for key, val in kwargs.iteritems():
args += ('-%s' % key, val)
self.tk.call(self._w, 'window', 'configure', index, *args)
def window_delete(self, *indexes):
self.tk.call(self._w, 'window', 'delete', *indexes)
def window_move(self, index_from, index_to):
self.tk.call(self._w, 'window', 'move', index_from, index_to)
def window_names(self, pattern=None):
return self.tk.call(self._w, 'window', 'names', pattern)
def xview(self, index=None):
"""If index is not given a tuple containing two fractions is returned,
each fraction is between 0 and 1. Together they describe the
horizontal span that is visible in the window.
If index is given the view in the window is adjusted so that the
column given by index is displayed at the left edge of the window."""
res = self.tk.call(self._w, 'xview', index)
if index is None:
return self._getdoubles(res)
def xview_moveto(self, fraction):
"""Adjusts the view in the window so that fraction of the total width
of the table text is off-screen to the left. The fraction parameter
must be a fraction between 0 and 1."""
self.tk.call(self._w, 'xview', 'moveto', fraction)
def xview_scroll(self, number, what):
"""Shift the view in the window left or right according to number and
what. The 'number' parameter must be an integer. The 'what' parameter
must be either units or pages or an abbreviation of one of these.
If 'what' is units, the view adjusts left or right by number cells on
the display; if it is pages then the view adjusts by number screenfuls.
If 'number' is negative then cells farther to the left become visible;
if it is positive then cells farther to the right become visible. """
self.tk.call(self._w, 'xview', 'scroll', number, what)
def yview(self, index=None):
"""If index is not given a tuple containing two fractions is returned,
each fraction is between 0 and 1. The first element gives the position
of the table element at the top of the window, relative to the table
as a whole. The second element gives the position of the table element
just after the last one in the window, relative to the table as a
whole.
If index is given the view in the window is adjusted so that the
row given by index is displayed at the top of the window."""
res = self.tk.call(self._w, 'yview', index)
if index is None:
return self._getdoubles(res)
def yview_moveto(self, fraction):
"""Adjusts the view in the window so that the element given by
fraction appears at the top of the window. The fraction parameter
must be a fraction between 0 and 1."""
self.tk.call(self._w, 'yview', 'moveto', fraction)
def yview_scroll(self, number, what):
"""Adjust the view in the window up or down according to number and
what. The 'number' parameter must be an integer. The 'what' parameter
must be either units or pages or an abbreviation of one of these.
If 'what' is units, the view adjusts up or down by number cells; if it
is pages then the view adjusts by number screenfuls.
If 'number' is negative then earlier elements become visible; if it
is positive then later elements become visible. """
self.tk.call(self._w, 'yview', 'scroll', number, what)
# Sample test taken from tktable cvs, original tktable python wrapper
def sample_test():
from Tkinter import Tk, Label, Button
def test_cmd(event):
if event.i == 0:
return '%i, %i' % (event.r, event.c)
else:
return 'set'
def browsecmd(event):
print "event:", event.__dict__
print "curselection:", test.curselection()
print "active cell index:", test.index('active')
print "active:", test.index('active', 'row')
print "anchor:", test.index('anchor', 'row')
root = Tk()
var = ArrayVar(root)
for y in range(-1, 4):
for x in range(-1, 5):
index = "%i,%i" % (y, x)
var.set(index, index)
label = Label(root, text="Proof-of-existence test for Tktable")
label.pack(side = 'top', fill = 'x')
quit = Button(root, text="QUIT", command=root.destroy)
quit.pack(side = 'bottom', fill = 'x')
test = Table(root,
rows=10,
cols=5,
state='disabled',
width=6,
height=6,
titlerows=1,
titlecols=1,
roworigin=-1,
colorigin=-1,
selectmode='browse',
selecttype='row',
rowstretch='unset',
colstretch='last',
browsecmd=browsecmd,
flashmode='on',
variable=var,
usecommand=0,
command=test_cmd)
test.pack(expand=1, fill='both')
test.tag_configure('sel', background = 'yellow')
test.tag_configure('active', background = 'blue')
test.tag_configure('title', anchor='w', bg='red', relief='sunken')
root.mainloop()
if __name__ == '__main__':
sample_test()

41
tktable/license.txt Normal file
View File

@@ -0,0 +1,41 @@
* COPYRIGHT AND LICENSE TERMS *
(This file blatantly stolen from Tcl/Tk license and adapted - thus assume
it falls under similar license terms).
This software is copyrighted by Jeffrey Hobbs <jeff at hobbs org>. The
following terms apply to all files associated with the software unless
explicitly disclaimed in individual files.
The authors hereby grant permission to use, copy, modify, distribute, and
license this software and its documentation for any purpose, provided that
existing copyright notices are retained in all copies and that this notice
is included verbatim in any distributions. No written agreement, license,
or royalty fee is required for any of the authorized uses.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS
PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO
OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
RESTRICTED RIGHTS: Use, duplication or disclosure by the U.S. government
is subject to the restrictions as set forth in subparagraph (c) (1) (ii)
of the Rights in Technical Data and Computer Software Clause as DFARS
252.227-7013 and FAR 52.227-19.
SPECIAL NOTES:
This software is also falls under the bourbon_ware clause v2:
This software is free, but should you find this software useful in your
daily work and would like to compensate the author, donations in the form
of aged bourbon and scotch are welcome by the author. The user may feel
exempt from this clause if they are below drinking age or think the author
has already partaken of too many drinks.

38
tktable/release.txt Normal file
View File

@@ -0,0 +1,38 @@
WHAT: Tktable v2.10, 2D editable table/matrix widget
WHERE: http://tktable.sourceforge.net/
Tktable binaries are part of ActiveTcl:
http://www.ActiveState.com/Tcl
REQUIREMENTS: Tcl/Tk8.0+, compiling is required
Compiles everywhere Tk does!
UPDATES TO 2.10:
* Code cleanup
* Work around Xft font clipping issues
* Updated build system
See ChangeLog and updated man page for full details
BASIC FEATURES:
* multi-line cells
* support for embedded windows (one per cell)
* variable width columns / height rows (interactively resizable)
* row and column titles
* multiple data sources ((Tcl array || Tcl command) &| internal caching)
* supports standard Tk reliefs, fonts, etc.
* x/y scrollbar support
* 'tag' styles per row, column or cell to change
colors, font, relief, image, etc...
* in-cell editing - returns value back to data source
* support for disabled (read-only) tables or cells (via tags)
* multiple selection modes, with "active" cell
* optional 'flashes' when things update
* cell validation support
* Builds on Windows, Mac and Unix
* Unicode support (8.1+)
Mailing list for Tktable users:
http://lists.sourceforge.net/lists/listinfo/tktable-users
CONTACT: jeff at hobbs.org, Jeff Hobbs

View File

@@ -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

4093
tktable/tclconfig/tcl.m4 Normal file

File diff suppressed because it is too large Load Diff

58
tktable/tests/all.tcl Normal file
View File

@@ -0,0 +1,58 @@
# all.tcl --
#
# This file contains a top-level script to run all of the Tk table
# tests. Execute it by invoking "source all.tcl" when running tktest
# in this directory.
#
# Copyright (c) 1998-2000 Ajuba Solutions
# Copyright (c) 2000-2002 Jeffrey Hobbs
#
# See the file "license.txt" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: all.tcl,v 1.2 2002/06/21 18:16:39 hobbs Exp $
package require tcltest
namespace import -force ::tcltest::*
set ::tcltest::testSingleFile false
set ::tcltest::testsDirectory [file dir [info script]]
# We need to ensure that the testsDirectory is absolute
catch {::tcltest::normalizePath ::tcltest::testsDirectory}
set chan $::tcltest::outputChannel
puts $chan "Tk $tk_patchLevel tests running in interp: [info nameofexecutable]"
puts $chan "Tests running with pwd: [pwd]"
puts $chan "Tests running in working dir: $::tcltest::testsDirectory"
if {[llength $::tcltest::skip] > 0} {
puts $chan "Skipping tests that match: $::tcltest::skip"
}
if {[llength $::tcltest::match] > 0} {
puts $chan "Only running tests that match: $::tcltest::match"
}
if {[llength $::tcltest::skipFiles] > 0} {
puts $chan "Skipping test files that match: $::tcltest::skipFiles"
}
if {[llength $::tcltest::matchFiles] > 0} {
puts $chan "Only sourcing test files that match: $::tcltest::matchFiles"
}
set timeCmd {clock format [clock seconds]}
puts $chan "Tests began at [eval $timeCmd]"
# source each of the specified tests
foreach file [lsort [::tcltest::getMatchingFiles]] {
set tail [file tail $file]
puts $chan $tail
if {[catch {source $file} msg]} {
puts $chan $msg
}
}
# cleanup
puts $chan "\nTests ended at [eval $timeCmd]"
::tcltest::cleanupTests 1
exit

869
tktable/tests/tkTable.test Normal file
View File

@@ -0,0 +1,869 @@
# This file is a Tcl script to test out the "table" command.
# It is organized in the standard fashion for Tcl tests.
#
# Copyright (c) 2000-2001 Jeffrey Hobbs
#
# See the file "license.txt" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: tkTable.test,v 1.14 2008/11/14 23:16:52 hobbs Exp $
# deletes:
# test 2 -5
# test 4 -2
# test 0 -1 (== 0 1)
package require tcltest
namespace import -force ::tcltest::*
set ::VERSION 2.10
package require Tktable $::VERSION
eval destroy [winfo children .]
wm geometry . {}
raise .
set fixed {Courier -12}
proc getsize w {
regexp {(^[^+-]*)} [wm geometry $w] foo x
return $x
}
# Procedure that creates a second table for checking things related
# to partially visible lines.
proc mkPartial {{w .partial}} {
catch {destroy $w}
toplevel $w
wm geometry $w +0+0
table $w.l -width 30 -height 5
pack $w.l -expand 1 -fill both
$w.l insert end one two three four five six seven eight nine ten \
eleven twelve thirteen fourteen fifteen
update
scan [wm geometry $w] "%dx%d" width height
wm geometry $w ${width}x[expr $height-3]
update
}
proc Some args { # do nothing command }
proc Another args { # do nothing command }
# Create entries in the option database to be sure that geometry options
# like border width have predictable values.
option add *Table.borderWidth 1
option add *Table.highlightThickness 2
option add *Table.font {Helvetica -12}
pack [table .t]
update
set i 1
foreach test {
{-anchor n n left {bad anchor position "left": must be n, ne, e, se, s, sw, w, nw, or center}}
{-autoclear yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-background #ff0000 #ff0000 non-existent
{unknown color name "non-existent"}}
{-bd "4 2" "4 2" badValue {bad screen distance "badValue"}}
{-bg #ff0000 #ff0000 non-existent {unknown color name "non-existent"}}
{-bordercursor arrow arrow badValue {bad cursor spec "badValue"}}
{-borderwidth 1 1 badValue {bad screen distance "badValue"}}
{-browsecommand {Some command} {Some command} {} {}}
{-browsecmd {Some command} {Some command} {} {}}
{-cache yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-colorigin 1 1 xyzzy {expected integer but got "xyzzy"}}
{-cols 12 12 xyzzy {expected integer but got "xyzzy"}}
{-colseparator , , {} {}}
{-colstretchmode unset unset bogus {bad option "bogus" must be none, unset, all, last, fill}}
{-coltagcommand {Some command} {Some command} {} {}}
{-colwidth 5 5 xyzzy {expected integer but got "xyzzy"}}
{-command {Some command} {Some command} {} {}}
{-cursor arrow arrow badValue {bad cursor spec "badValue"}}
{-drawmode slow slow badValue {bad option "badValue" must be fast, compatible, slow, single}}
{-ellipsis {...} {...} {} {}}
{-exportselection yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-fg #110022 #110022 bogus {unknown color name "bogus"}}
{-flashmode yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-flashtime 3 3 xyzzy {expected integer but got "xyzzy"}}
{-font {Helvetica 12} {Helvetica 12} {} {font "" doesn't exist}}
{-foreground #110022 #110022 bogus {unknown color name "bogus"}}
{-height 30 30 20p {expected integer but got "20p"}}
{-highlightbackground #112233 #112233 ugly {unknown color name "ugly"}}
{-highlightcolor #123456 #123456 bogus {unknown color name "bogus"}}
{-highlightthickness 6 6 bogus {bad screen distance "bogus"}}
{-highlightthickness -2 0 {} {}}
{-insertbackground #110022 #110022 bogus {unknown color name "bogus"}}
{-insertborderwidth 1.3 1 2.6x {bad screen distance "2.6x"}}
{-insertofftime 100 100 3.2 {expected integer but got "3.2"}}
{-insertontime 100 100 3.2 {expected integer but got "3.2"}}
{-insertwidth 1.3 1 2.6x {bad screen distance "2.6x"}}
{-invertselected yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-ipadx 1.3 1 2.6x {bad screen distance "2.6x"}}
{-ipady 1.3 1 2.6x {bad screen distance "2.6x"}}
{-justify left left wrong {bad justification "wrong": must be left, right, or center}}
{-maxheight 300 300 2.6x {bad screen distance "2.6x"}}
{-maxwidth 300 300 2.6x {bad screen distance "2.6x"}}
{-multiline yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-padx 1.3 1 2.6x {bad screen distance "2.6x"}}
{-pady 1.3 1 2.6x {bad screen distance "2.6x"}}
{-relief groove groove 1.5 {bad relief type "1.5": must be flat, groove, raised, ridge, solid, or sunken}}
{-rowheight -20 -20 xyzzy {expected integer but got "xyzzy"}}
{-roworigin -20 -20 xyzzy {expected integer but got "xyzzy"}}
{-rows 20 20 xyzzy {expected integer but got "xyzzy"}}
{-rowseparator , , {} {}}
{-rowstretchmode unset unset bogus {bad option "bogus" must be none, unset, all, last, fill}}
{-rowtagcommand {Some command} {Some command} {} {}}
{-selcmd {Some command} {Some command} {} {}}
{-selectioncommand {Some command} {Some command} {} {}}
{-selectmode extended extended {} {}}
{-selecttitles yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-selecttype row row bogus {bad option "bogus" must be row, col, both, cell}}
{-sparsearray yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-state disabled disabled foo {bad option "foo" must be normal, disabled}}
{-takefocus "any string" "any string" {} {}}
{-titlecols 4 4 3p {expected integer but got "3p"}}
{-titlerows 4 4 3p {expected integer but got "3p"}}
{-usecommand yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-variable var var {} {}}
{-validate yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-validatecommand {Some command} {Some command} {} {}}
{-vcmd {Some command} {Some command} {} {}}
{-width 45 45 3p {expected integer but got "3p"}}
{-wrap yes 1 xyzzy {expected boolean value but got "xyzzy"}}
{-xscrollcommand {Some command} {Some command} {} {}}
{-yscrollcommand {Another command} {Another command} {} {}}
} {
set name [lindex $test 0]
test table-1.$i "configuration options, $name" {
.t configure $name [lindex $test 1]
list [lindex [.t configure $name] 4] [.t cget $name]
} [list [lindex $test 2] [lindex $test 2]]
incr i
if {[lindex $test 3] != ""} {
test table-1.$i "configuration options, $name" {
list [catch {.t configure $name [lindex $test 3]} msg] $msg
} [list 1 [lindex $test 4]]
}
.t configure $name [lindex [.t configure $name] 3]
incr i
}
foreach test {
{-anchor n n left {bad anchor position "left": must be n, ne, e, se, s, sw, w, nw, or center}}
{-background #ff0000 #ff0000 non-existent
{unknown color name "non-existent"}}
{-bd "4 2" "4 2" badValue {bad screen distance "badValue"}}
{-bg #ff0000 #ff0000 non-existent {unknown color name "non-existent"}}
{-borderwidth 1 1 badValue {bad screen distance "badValue"}}
{-fg #110022 #110022 bogus {unknown color name "bogus"}}
{-font {Helvetica 12} {Helvetica 12} {} {font "" doesn't exist}}
{-foreground #110022 #110022 bogus {unknown color name "bogus"}}
{-image {} {} {} {}}
{-justify left left bogus {bad justification "bogus": must be left, right, or center}}
{-multiline 1 1 xyzzy {expected integer but got "xyzzy"}}
{-relief groove groove 1.5 {bad relief type "1.5": must be flat, groove, raised, ridge, solid, or sunken}}
{-showtext 1 1 xyzzy {expected integer but got "xyzzy"}}
{-state disabled disabled foo {bad option "foo" must be unknown, normal, disabled}}
{-wrap 1 1 xyzzy {expected integer but got "xyzzy"}}
} {
set name [lindex $test 0]
test table-1.$i "tag configuration options, $name" {
.t tag configure title $name [lindex $test 1]
list [lindex [.t tag configure title $name] 4] [.t tag cget title $name]
} [list [lindex $test 2] [lindex $test 2]]
incr i
if {[lindex $test 3] != ""} {
test table-1.$i "tag configuration options, $name" {
list [catch {.t tag configure title $name [lindex $test 3]} msg] $msg
} [list 1 [lindex $test 4]]
}
.t tag configure title $name [lindex [.t tag configure title $name] 3]
incr i
}
test table-2.1 {Tk_TableCmd procedure} {
list [catch {table} msg] $msg
} {1 {wrong # args: should be "table pathName ?options?"}}
test table-2.2 {Tk_TableCmd procedure} {
list [catch {table gorp} msg] $msg
} {1 {bad window path name "gorp"}}
test table-2.3 {Tk_TableCmd procedure} {
catch {destroy .t}
table .t
list [winfo exists .t] [winfo class .t] [info commands .t]
} {1 Table .t}
test table-2.4 {Tk_TableCmd procedure} {
catch {destroy .t}
list [catch {table .t -gorp foo} msg] $msg [winfo exists .t] \
[info commands .t]
} {1 {unknown option "-gorp"} 0 {}}
test table-2.5 {Tk_TableCmd procedure} {
catch {destroy .t}
table .t
} {.t}
option clear
destroy .t
table .t -cache 1
update
update
update
update
update
update
test table-3.1 {TableWidgetCmd procedure} {
list [catch .t msg] $msg
} {1 {wrong # args: should be ".t option ?arg arg ...?"}}
test table-3.2 {TableWidgetCmd procedure, commands} {
list [catch {.t whoknows} msg] $msg
} {1 {bad option "whoknows": must be activate, bbox, border, cget, clear, configure, curselection, curvalue, delete, get, height, hidden, icursor, index, insert, reread, scan, see, selection, set, spans, tag, validate, version, window, width, xview, or yview}}
test table-3.3 {TableWidgetCmd procedure, commands} {
list [catch {.t c} msg] $msg
} {1 {ambiguous option "c": must be activate, bbox, border, cget, clear, configure, curselection, curvalue, delete, get, height, hidden, icursor, index, insert, reread, scan, see, selection, set, spans, tag, validate, version, window, width, xview, or yview}}
test table-4.1 {TableWidgetCmd procedure, "activate" option} {
list [catch {.t activate} msg] $msg
} {1 {wrong # args: should be ".t activate index"}}
test table-4.2 {TableWidgetCmd procedure, "activate" option} {
list [catch {.t activate a b} msg] $msg
} {1 {wrong # args: should be ".t activate index"}}
test table-4.3 {TableWidgetCmd procedure, "activate" option} {
list [catch {.t activate fooey} msg] $msg
} {1 {bad table index "fooey": must be active, anchor, end, origin, topleft, bottomright, @x,y, or <row>,<col>}}
test table-4.4 {TableWidgetCmd procedure, "activate" option} {
.t activate 3,0
.t index active
} 3,0
test table-4.5 {TableWidgetCmd procedure, "activate" option} {
.t activate -1,0
.t index active
} {0,0}
test table-4.6 {TableWidgetCmd procedure, "activate" option} {
.t activate 30,30
.t index active
} {9,9}
test table-4.7 {TableWidgetCmd procedure, "activate" option} {
.t activate origin
.t index active
} {0,0}
test table-4.8 {TableWidgetCmd procedure, "activate" option} {
.t activate end
.t index active
} {9,9}
test table-5.1 {TableWidgetCmd procedure, "bbox" option} {
list [catch {.t bbox} msg] $msg
} {1 {wrong # args: should be ".t bbox first ?last?"}}
test table-5.2 {TableWidgetCmd procedure, "bbox" option} {
list [catch {.t bbox a b c} msg] $msg
} {1 {wrong # args: should be ".t bbox first ?last?"}}
test table-5.3 {TableWidgetCmd procedure, "bbox" option} {
list [catch {.t bbox fooey} msg] $msg
} {1 {bad table index "fooey": must be active, anchor, end, origin, topleft, bottomright, @x,y, or <row>,<col>}}
test table-6.1 {TableWidgetCmd procedure, "cget" option} {
list [catch {.t cget} msg] $msg
} {1 {wrong # args: should be ".t cget option"}}
test table-6.2 {TableWidgetCmd procedure, "cget" option} {
list [catch {.t cget a b} msg] $msg
} {1 {wrong # args: should be ".t cget option"}}
test table-6.3 {TableWidgetCmd procedure, "cget" option} {
list [catch {.t cget -gorp} msg] $msg
} {1 {unknown option "-gorp"}}
test table-6.4 {TableWidgetCmd procedure, "cget" option} {
.t cget -rows
} {10}
test table-7.1 {TableWidgetCmd procedure, "configure" option} {
llength [.t configure]
} {71}
test table-7.2 {TableWidgetCmd procedure, "configure" option} {
list [catch {.t configure -gorp} msg] $msg
} {1 {unknown option "-gorp"}}
test table-7.3 {TableWidgetCmd procedure, "configure" option} {
.t configure -browsecommand
} {-browsecommand browseCommand BrowseCommand {} {}}
test table-7.4 {TableWidgetCmd procedure, "configure" option} {
list [catch {.t configure -gorp is_messy} msg] $msg
} {1 {unknown option "-gorp"}}
test table-7.5 {TableWidgetCmd procedure, "configure" option} {
set oldbd [.t cget -bd]
set oldht [.t cget -highlightthickness]
.t configure -bd 3 -highlightthickness 0
set x "[.t cget -bd] [.t cget -highlightthickness]"
.t configure -bd $oldbd -highlightthickness $oldht
set x
} {3 0}
test table-8.1 {TableWidgetCmd procedure, "curselection" option} {
list [catch {.t curselection a b} msg] $msg
} {1 {wrong # args: should be ".t curselection ?value?"}}
test table-8.2 {TableWidgetCmd procedure, "curselection" option} {
.t selection clear all
.t curselection
} {}
test table-8.2 {TableWidgetCmd procedure, "curselection" option} {
.t selection clear all
.t selection set 1,0 2,2
.t selection set 3,3
.t curselection
} {1,0 1,1 1,2 2,0 2,1 2,2 3,3}
test table-9.1 {TableWidgetCmd procedure, "border" option} {
list [catch {.t border} msg] $msg
} {1 {wrong # args: should be ".t border mark|dragto x y ?row|col?"}}
test table-10.1 {TableWidgetCmd procedure, "clear" option} {
list [catch {.t clear} msg] $msg
} {1 {wrong # args: should be ".t clear option ?first? ?last?"}}
test table-11.1 {TableWidgetCmd procedure, "curvalue" option} {
list [catch {.t curvalue this that} msg] $msg
} {1 {wrong # args: should be ".t curvalue ?<value>?"}}
test table-12.1 {TableWidgetCmd procedure, "delete" option} {
list [catch {.t delete} msg] $msg
} {1 {wrong # args: should be ".t delete option ?switches? arg ?arg?"}}
test table-13.1 {TableWidgetCmd procedure, "get" option} {
list [catch {.t get} msg] $msg
} {1 {wrong # args: should be ".t get first ?last?"}}
test table-14.1 {TableWidgetCmd procedure, "height" option} {
list [catch {.t height a} msg] $msg
} {1 {expected integer but got "a"}}
#test table-15.1 {TableWidgetCmd procedure, "hidden" option} {
# list [catch {.t hidden fooey} msg] $msg
#} {1 {bad table index "fooey": must be active, anchor, end, origin, topleft, bottomright, @x,y, or <row>,<col>}}
destroy .t
table .t
.t configure -cache 1
.t set 1,1 abcde
test table-16.1 {TableWidgetCmd procedure, "icursor" option} {
list [catch {.t icursor a b} msg] $msg
} {1 {wrong # args: should be ".t icursor ?cursorPos?"}}
test table-16.2 {TableWidgetCmd procedure, "icursor" option} {
# no active cell
.t icursor
} -1
.t activate 1,1
test table-16.3 {TableWidgetCmd procedure, "icursor" option} {
# activate sets cursor to end
.t icursor
} 5
test table-16.4 {TableWidgetCmd procedure, "icursor" option} {
# change cursor
.t icursor 2
} 2
test table-16.5 {TableWidgetCmd procedure, "icursor" option} {
# retain changed cursor position
.t icursor
} 2
test table-17.1 {TableWidgetCmd procedure, "index" option} {
list [catch {.t index} msg] $msg
} {1 {wrong # args: should be ".t index <index> ?row|col?"}}
test table-18.1 {TableWidgetCmd procedure, "insert" option} {
list [catch {.t insert} msg] $msg
} {1 {wrong # args: should be ".t insert option ?switches? arg ?arg?"}}
test table-19.1 {TableWidgetCmd procedure, "reread" option} {
list [catch {.t reread foo} msg] $msg
} {1 {wrong # args: should be ".t reread"}}
test table-20.1 {TableWidgetCmd procedure, "scan" option} {
list [catch {.t scan} msg] $msg
} {1 {wrong # args: should be ".t scan mark|dragto x y"}}
test table-21.1 {TableWidgetCmd procedure, "see" option} {
list [catch {.t see} msg] $msg
} {1 {wrong # args: should be ".t see index"}}
test table-22.1 {TableWidgetCmd procedure, "selection" option} {
list [catch {.t selection} msg] $msg
} {1 {wrong # args: should be ".t selection option ?arg arg ...?"}}
test table-23.1 {TableWidgetCmd procedure, "set" option} {
list [catch {.t set} msg] $msg
} {1 {wrong # args: should be ".t set ?row|col? index ?value? ?index value ...?"}}
test table-24.1 {TableWidgetCmd procedure, "spans" option} {
list [catch {.t spans this} msg] $msg
} {1 {bad table index "this": must be active, anchor, end, origin, topleft, bottomright, @x,y, or <row>,<col>}}
test table-25.1 {TableWidgetCmd procedure, "tag" option} {
list [catch {.t tag} msg] $msg
} {1 {wrong # args: should be ".t tag option ?arg arg ...?"}}
test table-25.2.1 {TableWidgetCmd procedure, "tag names" option} {
.t tag names
} {flash active sel title}
test table-25.2.2 {TableWidgetCmd procedure, "tag names" option} {
.t tag names *
} {flash active sel title}
test table-25.2.3 {TableWidgetCmd procedure, "tag names" option} {
.t tag names f*
} {flash}
test table-25.2.4 {TableWidgetCmd procedure, "tag names" option} {
.t tag configure foo
} [expr {
([info tclversion] > 8.3) ?
{{-anchor anchor Anchor center {unknown anchor position}} {-background background Background {} {}} {-bd borderWidth} {-bg background} {-borderwidth borderWidth BorderWidth {} {}} {-ellipsis ellipsis Ellipsis {} {}} {-foreground foreground Foreground {} {}} {-fg foreground} {-font font Font {} {}} {-image image Image {} {}} {-justify justify Justify left {unknown justification style}} {-multiline multiline Multiline -1 -1} {-relief relief Relief flat {}} {-showtext showText ShowText -1 -1} {-state state State unknown unknown} {-wrap wrap Wrap -1 -1}}
:
{{-anchor anchor Anchor center {unknown anchor position}} {-background background Background {} {}} {-bd borderWidth} {-bg background} {-borderwidth borderWidth BorderWidth {} {}} {-ellipsis ellipsis Ellipsis {} {}} {-foreground foreground Foreground {} {}} {-fg foreground} {-font font Font {} {}} {-image image Image {} {}} {-justify justify Justify left {unknown justification style}} {-multiline multiline Multiline -1 -1} {-relief relief Relief flat {unknown relief}} {-showtext showText ShowText -1 -1} {-state state State unknown unknown} {-wrap wrap Wrap -1 -1}}
}]
test table-25.2.5 {TableWidgetCmd procedure, "tag names" option} {
.t tag names
} {flash active sel title foo}
test table-25.2.6 {TableWidgetCmd procedure, "tag names" option} {
.t tag names f*
} {flash foo}
test table-25.2.7 {TableWidgetCmd procedure, "tag names" option} {
.t tag raise foo
.t tag names f*
} {foo flash}
test table-25.2.8 {TableWidgetCmd procedure, "tag names" option} {
.t tag lower foo
.t tag names
} {flash active sel title foo}
test table-25.2.9 {TableWidgetCmd procedure, "tag names" option} {
.t tag raise foo active
.t tag names
} {flash foo active sel title}
test table-25.2.10 {TableWidgetCmd procedure, "tag names" option} {
.t tag raise foo sel
.t tag names
} {flash active foo sel title}
test table-25.2.11 {TableWidgetCmd procedure, "tag names" option} {
.t tag lower foo active
.t tag names
} {flash active foo sel title}
test table-25.2.12 {TableWidgetCmd procedure, "tag names" option} {
.t tag lower foo foo
.t tag names
} {flash active foo sel title}
test table-25.2.13 {TableWidgetCmd procedure, "tag names" option} {
.t tag lower foo sel
.t tag names
} {flash active sel foo title}
test table-25.2.14 {TableWidgetCmd procedure, "tag names" option} {
.t tag lower foo
.t tag names
} {flash active sel title foo}
test table-25.2.15 {TableWidgetCmd procedure, "tag names" option} {
.t tag raise foo foo
.t tag names
} {flash active sel title foo}
test table-25.2.16 {TableWidgetCmd procedure, "tag names" option} {
.t tag raise foo flash
.t tag names
} {foo flash active sel title}
test table-25.2.17 {TableWidgetCmd procedure, "tag names" option} {
.t tag lower foo title
.t tag names
} {flash active sel title foo}
test table-26.1 {TableWidgetCmd procedure, "validate" option} {
list [catch {.t validate} msg] $msg
} {1 {wrong # args: should be ".t validate index"}}
test table-27.1 {TableWidgetCmd procedure, "version" option} {
list [catch {.t version foo} msg] $msg
} {1 {wrong # args: should be ".t version"}}
test table-.1 {TableWidgetCmd procedure, "version" option} {
.t version
} $::VERSION
test table-28.1 {TableWidgetCmd procedure, "window" option} {
list [catch {.t window} msg] $msg
} {1 {wrong # args: should be ".t window option ?arg arg ...?"}}
test table-29.1 {TableWidgetCmd procedure, "width" option} {
list [catch {.t width a} msg] $msg
} {1 {expected integer but got "a"}}
test table-30.1 {Table_EditCmd insert with var trace Bug #487747} {
destroy .t
table .t -cols 7 -rows 0 -variable ::TableData
.t insert rows end 1
.t set row 1,1 {1 2 3 4 5}
.t insert rows -- 0 9000
.t insert rows -- 0 9000
destroy .t
} {}
return
##
## STOP TESTS HERE
##
## The rest of the tests need to be adapted from the listbox tests.
##
test table-3.30 {TableWidgetCmd procedure, "delete" option} {
list [catch {.t delete} msg] $msg
} {1 {wrong # args: should be ".t delete firstIndex ?lastIndex?"}}
test table-3.31 {TableWidgetCmd procedure, "delete" option} {
list [catch {.t delete a b c} msg] $msg
} {1 {wrong # args: should be ".t delete firstIndex ?lastIndex?"}}
test table-3.32 {TableWidgetCmd procedure, "delete" option} {
list [catch {.t delete badIndex} msg] $msg
} {1 {bad table index "badIndex": must be active, anchor, end, @x,y, or a number}}
test table-3.33 {TableWidgetCmd procedure, "delete" option} {
list [catch {.t delete 2 123ab} msg] $msg
} {1 {bad table index "123ab": must be active, anchor, end, @x,y, or a number}}
test table-3.34 {TableWidgetCmd procedure, "delete" option} {
catch {destroy .t2}
table .t2
.t2 insert 0 el0 el1 el2 el3 el4 el5 el6 el7
.t2 delete 3
list [.t2 get 2] [.t2 get 3] [.t2 index end]
} {el2 el4 7}
test table-3.35 {TableWidgetCmd procedure, "delete" option} {
catch {destroy .t2}
table .t2
.t2 insert 0 el0 el1 el2 el3 el4 el5 el6 el7
.t2 delete 2 4
list [.t2 get 1] [.t2 get 2] [.t2 index end]
} {el1 el5 5}
test table-3.42 {TableWidgetCmd procedure, "get" option} {
list [catch {.t get} msg] $msg
} {1 {wrong # args: should be ".t get firstIndex ?lastIndex?"}}
test table-3.43 {TableWidgetCmd procedure, "get" option} {
list [catch {.t get a b c} msg] $msg
} {1 {wrong # args: should be ".t get firstIndex ?lastIndex?"}}
test table-3.44 {TableWidgetCmd procedure, "get" option} {
list [catch {.t get 2.4} msg] $msg
} {1 {bad table index "2.4": must be active, anchor, end, @x,y, or a number}}
test table-3.45 {TableWidgetCmd procedure, "get" option} {
list [catch {.t get end bogus} msg] $msg
} {1 {bad table index "bogus": must be active, anchor, end, @x,y, or a number}}
test table-3.46 {TableWidgetCmd procedure, "get" option} {
catch {destroy .t2}
table .t2
.t2 insert 0 el0 el1 el2 el3 el4 el5 el6 el7
list [.t2 get 0] [.t2 get 3] [.t2 get end]
} {el0 el3 el7}
test table-3.47 {TableWidgetCmd procedure, "get" option} {
catch {destroy .t2}
table .t2
list [.t2 get 0] [.t2 get end]
} {{} {}}
test table-3.57 {TableWidgetCmd procedure, "index" option} {
list [catch {.t index} msg] $msg
} {1 {wrong # args: should be ".t index index"}}
test table-3.58 {TableWidgetCmd procedure, "index" option} {
list [catch {.t index a b} msg] $msg
} {1 {wrong # args: should be ".t index index"}}
test table-3.59 {TableWidgetCmd procedure, "index" option} {
list [catch {.t index @} msg] $msg
} {1 {bad table index "@": must be active, anchor, end, @x,y, or a number}}
test table-3.60 {TableWidgetCmd procedure, "index" option} {
.t index 2
} 2
test table-3.61 {TableWidgetCmd procedure, "index" option} {
.t index -1
} -1
test table-3.62 {TableWidgetCmd procedure, "index" option} {
.t index end
} 18
test table-3.63 {TableWidgetCmd procedure, "index" option} {
.t index 34
} 34
test table-3.64 {TableWidgetCmd procedure, "insert" option} {
list [catch {.t insert} msg] $msg
} {1 {wrong # args: should be ".t insert index ?element element ...?"}}
test table-3.65 {TableWidgetCmd procedure, "insert" option} {
list [catch {.t insert badIndex} msg] $msg
} {1 {bad table index "badIndex": must be active, anchor, end, @x,y, or a number}}
test table-3.66 {TableWidgetCmd procedure, "insert" option} {
catch {destroy .t2}
table .t2
.t2 insert end a b c d e
.t2 insert 3 x y z
.t2 get 0 end
} {a b c x y z d e}
test table-3.67 {TableWidgetCmd procedure, "insert" option} {
catch {destroy .t2}
table .t2
.t2 insert end a b c
.t2 insert -1 x
.t2 get 0 end
} {x a b c}
test table-3.74 {TableWidgetCmd procedure, "scan" option} {
list [catch {.t scan a b} msg] $msg
} {1 {wrong # args: should be ".t scan mark|dragto x y"}}
test table-3.75 {TableWidgetCmd procedure, "scan" option} {
list [catch {.t scan a b c d} msg] $msg
} {1 {wrong # args: should be ".t scan mark|dragto x y"}}
test table-3.76 {TableWidgetCmd procedure, "scan" option} {
list [catch {.t scan foo bogus 2} msg] $msg
} {1 {expected integer but got "bogus"}}
test table-3.77 {TableWidgetCmd procedure, "scan" option} {
list [catch {.t scan foo 2 2.3} msg] $msg
} {1 {expected integer but got "2.3"}}
test table-3.78 {TableWidgetCmd procedure, "scan" option} {fonts} {
catch {destroy .t}
toplevel .t
wm geom .t +0+0
table .t.t -width 10 -height 5
.t.t insert 0 "Short" "Somewhat longer" "Really, quite a whole lot longer than can possibly fit on the screen" "Short" a b c d e f g h i j
pack .t.t
update
.t.t scan mark 100 140
.t.t scan dragto 90 137
update
list [.t.t xview] [.t.t yview]
} {{0.249364 0.427481} {0.0714286 0.428571}}
test table-3.79 {TableWidgetCmd procedure, "scan" option} {
list [catch {.t scan foo 2 4} msg] $msg
} {1 {bad option "foo": must be mark or dragto}}
test table-3.80 {TableWidgetCmd procedure, "see" option} {
list [catch {.t see} msg] $msg
} {1 {wrong # args: should be ".t see index"}}
test table-3.81 {TableWidgetCmd procedure, "see" option} {
list [catch {.t see a b} msg] $msg
} {1 {wrong # args: should be ".t see index"}}
test table-3.82 {TableWidgetCmd procedure, "see" option} {
list [catch {.t see gorp} msg] $msg
} {1 {bad table index "gorp": must be active, anchor, end, @x,y, or a number}}
test table-3.83 {TableWidgetCmd procedure, "see" option} {
.t yview 7
.t see 7
.t index @0,0
} {7}
test table-3.84 {TableWidgetCmd procedure, "see" option} {
.t yview 7
.t see 11
.t index @0,0
} {7}
test table-3.93 {TableWidgetCmd procedure, "selection" option} {
list [catch {.t select a} msg] $msg
} {1 {wrong # args: should be ".t selection option index ?index?"}}
test table-3.94 {TableWidgetCmd procedure, "selection" option} {
list [catch {.t select a b c d} msg] $msg
} {1 {wrong # args: should be ".t selection option index ?index?"}}
test table-3.95 {TableWidgetCmd procedure, "selection" option} {
list [catch {.t selection a bogus} msg] $msg
} {1 {bad table index "bogus": must be active, anchor, end, @x,y, or a number}}
test table-3.96 {TableWidgetCmd procedure, "selection" option} {
list [catch {.t selection a 0 lousy} msg] $msg
} {1 {bad table index "lousy": must be active, anchor, end, @x,y, or a number}}
test table-3.97 {TableWidgetCmd procedure, "selection" option} {
list [catch {.t selection anchor 0 0} msg] $msg
} {1 {wrong # args: should be ".t selection anchor index"}}
test table-3.98 {TableWidgetCmd procedure, "selection" option} {
list [.t selection anchor 5; .t index anchor] \
[.t selection anchor 0; .t index anchor]
} {5 0}
test table-3.99 {TableWidgetCmd procedure, "selection" option} {
.t selection anchor -1
.t index anchor
} {0}
test table-3.100 {TableWidgetCmd procedure, "selection" option} {
.t selection anchor end
.t index anchor
} {17}
test table-3.101 {TableWidgetCmd procedure, "selection" option} {
.t selection anchor 44
.t index anchor
} {17}
test table-3.102 {TableWidgetCmd procedure, "selection" option} {
.t selection clear 0 end
.t selection set 2 8
.t selection clear 3 4
.t curselection
} {2 5 6 7 8}
test table-3.103 {TableWidgetCmd procedure, "selection" option} {
list [catch {.t selection includes 0 0} msg] $msg
} {1 {wrong # args: should be ".t selection includes index"}}
test table-3.104 {TableWidgetCmd procedure, "selection" option} {
.t selection clear 0 end
.t selection set 2 8
.t selection clear 4
list [.t selection includes 3] [.t selection includes 4] \
[.t selection includes 5]
} {1 0 1}
test table-3.105 {TableWidgetCmd procedure, "selection" option} {
.t selection set 0 end
.t selection includes -1
} {0}
test table-3.106 {TableWidgetCmd procedure, "selection" option} {
.t selection clear 0 end
.t selection set end
.t selection includes end
} {1}
test table-3.107 {TableWidgetCmd procedure, "selection" option} {
.t selection set 0 end
.t selection includes 44
} {0}
test table-3.108 {TableWidgetCmd procedure, "selection" option} {
catch {destroy .t2}
table .t2
.t2 selection includes 0
} {0}
test table-3.109 {TableWidgetCmd procedure, "selection" option} {
.t selection clear 0 end
.t selection set 2
.t selection set 5 7
.t curselection
} {2 5 6 7}
test table-3.110 {TableWidgetCmd procedure, "selection" option} {
.t selection set 5 7
.t curselection
} {2 5 6 7}
test table-3.111 {TableWidgetCmd procedure, "selection" option} {
list [catch {.t selection badOption 0 0} msg] $msg
} {1 {bad option "badOption": must be anchor, clear, includes, or set}}
test table-3.114 {TableWidgetCmd procedure, "xview" option} {
catch {destroy .t2}
table .t2
update
.t2 xview
} {0 1}
test table-3.115 {TableWidgetCmd procedure, "xview" option} {
catch {destroy .t}
table .t -width 10 -height 5 -font $fixed
.t insert 0 a b c d e f g h i j k l m n o p q r s t
pack .t
update
.t xview
} {0 1}
catch {destroy .t}
table .t -width 10 -height 5 -font $fixed
.t insert 0 a b c d e f g h i j k l m n o p q r s t
.t insert 1 "0123456789a123456789b123456789c123456789d123456789"
pack .t
update
test table-3.116 {TableWidgetCmd procedure, "xview" option} {fonts} {
.t xview 4
.t xview
} {0.08 0.28}
test table-3.117 {TableWidgetCmd procedure, "xview" option} {
list [catch {.t xview foo} msg] $msg
} {1 {expected integer but got "foo"}}
test table-3.118 {TableWidgetCmd procedure, "xview" option} {
list [catch {.t xview zoom a b} msg] $msg
} {1 {unknown option "zoom": must be moveto or scroll}}
test table-3.119 {TableWidgetCmd procedure, "xview" option} {fonts} {
.t xview 0
.t xview moveto .4
update
.t xview
} {0.4 0.6}
test table-3.120 {TableWidgetCmd procedure, "xview" option} {fonts} {
.t xview 0
.t xview scroll 2 units
update
.t xview
} {0.04 0.24}
test table-3.121 {TableWidgetCmd procedure, "xview" option} {fonts} {
.t xview 30
.t xview scroll -1 pages
update
.t xview
} {0.44 0.64}
test table-3.122 {TableWidgetCmd procedure, "xview" option} {fonts} {
.t configure -width 1
update
.t xview 30
.t xview scroll -4 pages
update
.t xview
} {0.52 0.54}
test table-3.123 {TableWidgetCmd procedure, "yview" option} {
catch {destroy .t}
table .t
pack .t
update
.t yview
} {0 1}
test table-3.124 {TableWidgetCmd procedure, "yview" option} {
catch {destroy .t}
table .t
.t insert 0 el1
pack .t
update
.t yview
} {0 1}
catch {destroy .t}
table .t -width 10 -height 5 -font $fixed
.t insert 0 a b c d e f g h i j k l m n o p q r s t
pack .t
update
test table-3.125 {TableWidgetCmd procedure, "yview" option} {
.t yview 4
update
.t yview
} {0.2 0.45}
test table-3.126 {TableWidgetCmd procedure, "yview" option, partial last line} {
mkPartial
.partial.t yview
} {0 0.266667}
test table-3.127 {TableWidgetCmd procedure, "xview" option} {
list [catch {.t yview foo} msg] $msg
} {1 {bad table index "foo": must be active, anchor, end, @x,y, or a number}}
test table-3.128 {TableWidgetCmd procedure, "xview" option} {
list [catch {.t yview foo a b} msg] $msg
} {1 {unknown option "foo": must be moveto or scroll}}
test table-3.129 {TableWidgetCmd procedure, "xview" option} {
.t yview 0
.t yview moveto .31
.t yview
} {0.3 0.55}
test table-3.130 {TableWidgetCmd procedure, "xview" option} {
.t yview 2
.t yview scroll 2 pages
.t yview
} {0.4 0.65}
test table-3.131 {TableWidgetCmd procedure, "xview" option} {
.t yview 10
.t yview scroll -3 units
.t yview
} {0.35 0.6}
test table-3.132 {TableWidgetCmd procedure, "xview" option} {
.t configure -height 2
update
.t yview 15
.t yview scroll -4 pages
.t yview
} {0.55 0.65}
test table-4.1 {TableGetCellValue, command with large result} {
# test bug 651685
proc getcell {rc i} {
if {$i == 0} {
return [string repeat $rc 200]
}
}
destroy .t
table .t -rows 5 -cols 5 -command {getcell %C %i}
pack .t -fill both -expand 1
update
list
} {}
eval destroy [winfo children .]
option clear
# cleanup
::tcltest::cleanupTests
return

56
tktable/unix/tktable.spec Normal file
View File

@@ -0,0 +1,56 @@
# RPM specfile provided by Jean-Luc Fontaine
# $Id: tktable.spec,v 1.3 2008/11/14 23:16:52 hobbs Exp $
%define version 2.10
%define directory /usr
Summary: table/matrix widget extension to Tcl/Tk.
Name: tktable
Version: %{version}
Release: 1
Copyright: public domain
Group: Development/Languages/Tcl
Source: http://prdownloads.sourceforge.net/tktable/Tktable%{version}.tar.gz
URL: http://tktable.sourceforge.net/
Packager: Jean-Luc Fontaine <jfontain@free.fr>
BuildRequires: XFree86-libs >= 4, XFree86-devel >= 4, tk >= 8.3.1
AutoReqProv: no
Requires: tk >= 8.3.1
Buildroot: /var/tmp/%{name}%{version}
%description
Tktable provides a table/matrix widget for Tk programs. Features:
multi-line cells, embedded windows, variable width columns/height rows
(interactively resizable), scrollbar support, tag styles per row,
column or cell, in-cell editing, works on UNIX, Windows and MacIntosh,
Unicode support with Tk 8.1 and above.
%prep
%setup -q -c
%build
cd Tktable%{version}
./configure --with-tcl=%{directory}/lib --with-tk=%{directory}/lib
make TBL_CFLAGS=-O2
%install
cd Tktable%{version}
DIRECTORY=$RPM_BUILD_ROOT%{directory}/lib/%{name}%{version}
install -d $DIRECTORY
install libTktable%{version}.so $DIRECTORY/
install -m 644 pkgIndex.tcl library/tkTable.tcl library/tktable.py $DIRECTORY
install -d $RPM_BUILD_ROOT%{directory}/man/mann
install -m 644 doc/tkTable.n $RPM_BUILD_ROOT%{directory}/man/mann
install -m 644 ChangeLog README.txt README.blt license.txt ..
install -d ../doc
install -m 644 doc/tkTable.html ../doc
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc ChangeLog README.txt README.blt license.txt doc/tkTable.html
%{directory}/lib/%{name}%{version}
%{directory}/man/mann/tkTable.n.gz

264
tktable/win/makefile.vc Normal file
View File

@@ -0,0 +1,264 @@
# Makefile.vc
#
# This makefile builds Tktable.dll, a table widget as a dynamically
# loadable Tk extension. This makefile is suitable for use with VC++ 5+.
#
# TkTable assumes that Tcl/Tk has already been installed on Windows.
#
# This does not provide support for static builds on Windows
#
# Set this to the appropriate value of /MACHINE: for your platform
# Choices: IX86, IA64
MACHINE = IX86
PROJECT = Tktable
TBL_COMMAND = table
TBL_RUNTIME = tkTable.tcl
# Project directories -- these may need to be customized for your site
#
# ROOT -- location of the source files.
# TMP_DIR -- location for .obj files.
# TOOLS32 -- location of VC++ compiler installation.
# DEST_DIR -- location of Tcl/Tk installation hierarchy
# DEST_DIRU -- same as above with "/" as path separator
#
ROOT = ..
TMP_DIR = .
!if "$(MACHINE)" == "IA64"
# This assumes "-64" suffixes your Win64 build
v3 = 84-64
# IA64 support is based on the standard setup with v2 of the
# Microsoft SDK for XP, RC1
TOOLS32 = C:/Progra~1/Microsoft SDK
CC = "$(TOOLS32)/bin/Win64/cl.exe"
LD = "$(TOOLS32)/bin/Win64/link.exe"
libpath32 = /LIBPATH:"$(TOOLS32)/lib/IA64" \
/LIBPATH:"$(TOOLS32)/lib/Prerelease/IA64"
include32 = -I"$(TOOLS32)/Include/prerelease" \
-I"$(TOOLS32)/Include/Win64/crt" \
-I"$(TOOLS32)/Include/Win64/crt/sys" \
-I"$(TOOLS32)/Include"
!else
# Visual Studio 5 default
#TOOLS32 = C:/Progra~1/devstudio/vc
# Visual Studio 6 default
TOOLS32 = C:/Progra~1/Microsoft Visual Studio/VC98
CC = "$(TOOLS32)/bin/cl.exe"
LD = "$(TOOLS32)/bin/link.exe" -link50compat
libpath32 = /LIBPATH:"$(TOOLS32)/lib"
include32 = -I"$(TOOLS32)/include"
!endif
DEST_DIR = C:\Tcl
DEST_DIRU = C:/Tcl
WIN_DIR = $(ROOT)\win
GENERIC_DIR = $(ROOT)\generic
VPATH = $(GENERIC_DIR):$(WIN_DIR)
#Get version info (this is in Makefile and C format)
!include "$(GENERIC_DIR)\version.h"
# Set your version of Tcl
TCL_VERSION = 8.4
TCL_VER = 84
INST_RUNTIME = $(DEST_DIR)\lib\$(PROJECT)$(VERSION)
INST_RUNTIMEU = $(DEST_DIRU)/lib/$(PROJECT)$(VERSION)
# NO_EMBEDDED_RUNTIME means that the tkTable.tcl file will not be embedded
# into the executable, thus the default tkTable.tcl library file will not
# be available when the library is loaded.
# If this is defined, the tkTable.tcl file must be available in a
# predefined set of directories (see docs).
#TBL_CFLAGS += -DNO_EMBEDDED_RUNTIME
# change the following line to compile with symbols
DEBUG = 0
CP = copy
RM = del
######################################################################
# Project specific targets
######################################################################
TBL_LIB_DIR = $(ROOT)\library
# Assume that WISH is already INSTALLED
TCLSH = $(DEST_DIR)\bin\tclsh$(TCL_VER)
WISH = $(DEST_DIR)\bin\wish$(TCL_VER)
WIN_LIBS = gdi32.lib user32.lib
LIBS = $(DEST_DIR)\lib\tclstub$(TCL_VER).lib \
$(DEST_DIR)\lib\tkstub$(TCL_VER).lib $(WIN_LIBS)
LIBS = C:\build\tcl84-64\tclstub$(TCL_VER).lib \
C:\build\tk84-64\tkstub$(TCL_VER).lib $(WIN_LIBS)
INCLUDES = -I"$(DEST_DIR)\include" -I. $(include32)
DEFINES = -DDLL_BUILD -DBUILD_Tktable $(TBL_CFLAGS) \
-DPACKAGE_VERSION=\"$(VERSION)\" \
-DTBL_COMMAND=\"$(TBL_COMMAND)\" \
-DTBL_RUNTIME="\"$(TBL_RUNTIME)\"" \
-DTBL_RUNTIME_DIR="\"$(INST_RUNTIMEU)\""
## Define this if you want to use STUBS
## This only works for the dynamic library
##
DEFINES = $(DEFINES) -DUSE_TCL_STUBS -DUSE_TK_STUBS
CC_SWITCHES = $(CFLAGS) $(EXTRA_CFLAGS) $(DEFINES) $(INCLUDES)
#---------------------------------------------------------------------
# Compile flags
#---------------------------------------------------------------------
!if !$(DEBUG)
# This cranks the optimization level to maximize speed
cdebug = -O2 -Gs
!else if "$(MACHINE)" == "IA64"
cdebug = -Od -Zi
!else
cdebug = -Z7 -Od -WX
DBGX = d
!endif
# declarations common to all compiler options
cflags = -c -W3 -nologo -Fp$(TMP_DIR)\ -YX -MT$(DBGX)
#---------------------------------------------------------------------
# Link flags
#---------------------------------------------------------------------
!if $(DEBUG)
ldebug = -debug:full -debugtype:cv
!else
ldebug = -release
!endif
# declarations common to all linker options
lflags = -nologo -machine:$(MACHINE) -warn:3 $(libpath32)
# declarations for use on Intel i386, i486, and Pentium systems
!IF "$(MACHINE)" == "IX86"
DLLENTRY = @12
dlllflags = $(lflags) -entry:_DllMainCRTStartup$(DLLENTRY) -dll
!ELSE IF "$(MACHINE)" == "IA64"
dlllflags = $(lflags) -dll
!ELSE
dlllflags = $(lflags) -entry:_DllMainCRTStartup$(DLLENTRY) -dll
!ENDIF
conlflags = $(lflags) -subsystem:console -entry:mainCRTStartup
guilflags = $(lflags) -subsystem:windows -entry:WinMainCRTStartup
#
# Global makefile settings
#
DLLOBJS = $(TMP_DIR)\tkTable.obj \
$(TMP_DIR)\tkTableWin.obj \
$(TMP_DIR)\tkTableTag.obj \
$(TMP_DIR)\tkTableEdit.obj \
$(TMP_DIR)\tkTableCell.obj \
$(TMP_DIR)\tkTableCellSort.obj \
$(TMP_DIR)\tkTableCmds.obj \
$(TMP_DIR)\tkTableUtil.obj
# $(TMP_DIR)\tkTablePs.obj
DLL=$(PROJECT).dll
#
# Targets
#
all: pkgIndex.tcl
test: pkgIndex.tcl
@"$(WISH)" <<
lappend auto_path $(ROOT)
set code [catch {
package require $(PROJECT)
pack [$(TBL_COMMAND) .t]
} msg]
if {$$code != 0} {
tk_messageBox -type ok -message\
"$(PROJECT) failed to load and run: $$msg"
} else {
tk_messageBox -type ok -message\
"everything seems OK for 'package require $(PROJECT)'"
}
exit $$code
<<
pkgIndex.tcl: $(DLL)
"$(TCLSH)" << pkgIndex.tcl
set out [open [lindex $$argv 0] w]
puts $$out {if {[catch {package require Tcl 8.2}]} return}
puts -nonewline $$out {package ifneeded $(PROJECT) $(VERSION) }
puts -nonewline $$out {"package require Tk 8.2; }
puts $$out {[list load [file join $$dir $(DLL)] $(PROJECT)]"}
close $$out
<<
pkgIndex.tcl-NOSTUBS: $(DLL)
"$(TCLSH)" << pkgIndex.tcl
set out [open [lindex $$argv 0] w]
puts $$out {if {[catch {package require Tcl $(TCL_VERSION)}]} return}
puts -nonewline $$out {package ifneeded $(PROJECT) $(VERSION) }
puts -nonewline $$out {"package require Tk $(TCL_VERSION); }
puts $$out {[list load [file join $$dir $(DLL)] $(PROJECT)]"}
close $$out
<<
$(DLL): tkTable.tcl.h $(DLLOBJS)
$(LD) $(linkdebug) $(dlllflags) $(LIBS) \
$(guilibsdll) -out:$@ $(DLLOBJS)
tkTable.tcl.h: $(TBL_LIB_DIR)\tkTable.tcl
"$(TCLSH)" << $(TBL_LIB_DIR)\tkTable.tcl >$(TMP_DIR)\tkTable.tcl.h
set in [open [lindex $$argv 0] r]
while {[gets $$in line] != -1} {
switch -regexp -- $$line "^$$" - {^#} continue
regsub -all {\\} $$line {\\\\} line
regsub -all {"} $$line {\"} line
puts "\"$$line\\n\""
}
<<
# Implicit Targets
{$(WIN_DIR)}.c{$(TMP_DIR)}.obj:
$(CC) $(CC_SWITCHES) $(cdebug) $(cflags) $(cvarsdll) -Fo$(TMP_DIR)\ $<
{$(GENERIC_DIR)}.c{$(TMP_DIR)}.obj:
$(CC) $(CC_SWITCHES) $(cdebug) $(cflags) $(cvarsdll) -Fo$(TMP_DIR)\ $<
install: pkgIndex.tcl $(DLL)
if not exist "$(INST_RUNTIME)\" mkdir "$(INST_RUNTIME)"
copy "$(TBL_LIB_DIR)\tkTable.tcl" "$(INST_RUNTIME)"
copy "$(DLL)" "$(INST_RUNTIME)"
copy pkgIndex.tcl "$(INST_RUNTIME)"
uninstall:
-$(RM) "$(INST_RUNTIME)\tkTable.tcl"
-$(RM) "$(INST_RUNTIME)\$(DLL)"
-$(RM) "$(INST_RUNTIME)\pkgIndex.tcl"
clean:
-$(RM) $(TMP_DIR)\*.obj 2>nul
-$(RM) $(TMP_DIR)\$(DLL) 2>nul
-$(RM) $(TMP_DIR)\$(PROJECT).lib 2>nul
-$(RM) $(TMP_DIR)\$(PROJECT).exp 2>nul
-$(RM) $(TMP_DIR)\pkgIndex.tcl 2>nul
-$(RM) $(TMP_DIR)\tkTable.tcl.h 2>nul